BAB 22: Seeding dan Factory
Mengisi database dengan data awal menggunakan seeder dan factory di Laravel.
Saat membangun aplikasi, kamu perlu data untuk diuji. Membuat data manual lewat form setiap kali menjalankan migrate:fresh adalah pemborosan waktu yang nyata. Ada cara yang jauh lebih baik: seeder dan factory.
Seeder adalah class PHP yang bertugas mengisi database dengan data awal. Factory adalah blueprint untuk membuat instance model dengan data yang di-generate otomatis — termasuk data palsu yang realistis seperti nama, email, dan paragraf teks menggunakan library Faker. Kombinasi keduanya memungkinkan kamu mengisi database dengan puluhan atau ratusan record yang masuk akal hanya dalam satu perintah.
Membuat Seeder
Buat seeder menggunakan Artisan:
php artisan make:seeder CatatanSeeder
File baru muncul di database/seeders/CatatanSeeder.php:
// database/seeders/CatatanSeeder.php
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
class CatatanSeeder extends Seeder
{
public function run(): void
{
// logika pengisian data di sini
}
}
Method run() adalah satu-satunya tempat kamu menulis logika seeder. Di dalamnya bisa menggunakan Query Builder, Eloquent, atau factory.
Untuk sementara, isi dengan data statis menggunakan Eloquent:
// database/seeders/CatatanSeeder.php
use App\Models\Catatan;
use App\Models\User;
public function run(): void
{
$user = User::first();
Catatan::create([
'user_id' => $user->id,
'judul' => 'Persiapan sprint minggu ini',
'isi' => 'Review backlog, estimasi story points, dan assign task ke tim.',
'prioritas' => 'tinggi',
'selesai' => false,
]);
Catatan::create([
'user_id' => $user->id,
'judul' => 'Baca dokumentasi Eloquent',
'isi' => 'Fokus pada bagian relationships dan eager loading.',
'prioritas' => 'normal',
'selesai' => true,
]);
}
DatabaseSeeder sebagai Orkestrator
File database/seeders/DatabaseSeeder.php adalah seeder induk yang Laravel jalankan secara default. Daftarkan seeder lain di sini menggunakan $this->call():
// database/seeders/DatabaseSeeder.php
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
public function run(): void
{
$this->call([
CatatanSeeder::class,
]);
}
}
Urutan dalam array call() penting — seeder yang bergantung pada data dari seeder lain harus diletakkan setelahnya.
Menjalankan Seeder
Beberapa perintah yang perlu diketahui:
# Jalankan DatabaseSeeder (default)
php artisan db:seed
# Jalankan seeder tertentu saja
php artisan db:seed --class=CatatanSeeder
# Reset database, jalankan semua migrasi, lalu seed
php artisan migrate:fresh --seed
Perintah migrate:fresh --seed adalah yang paling sering dipakai selama pengembangan — ia menghapus semua tabel, membuat ulang dari awal, lalu mengisi data. Sangat berguna setelah mengubah struktur migrasi.
migrate:fresh menghapus semua tabel dan data yang ada. Jangan jalankan di database production. Gunakan --force hanya jika benar-benar diperlukan di environment non-development.
Model Factory
Seeder dengan data statis seperti contoh di atas cukup untuk beberapa record, tapi tidak praktis ketika kamu butuh 50 atau 100 record dengan variasi data yang realistis. Di sinilah factory berperan.
Buat factory untuk model Catatan:
php artisan make:factory CatatanFactory --model=Catatan
File baru muncul di database/factories/CatatanFactory.php. Isi method definition() dengan blueprint atribut menggunakan helper fake():
// database/factories/CatatanFactory.php
<?php
namespace Database\Factories;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
class CatatanFactory extends Factory
{
public function definition(): array
{
return [
'user_id' => User::factory(),
'judul' => fake()->sentence(nb: 5, variableNbWords: true),
'isi' => fake()->paragraphs(nb: 2, asText: true),
'prioritas' => fake()->randomElement(['rendah', 'normal', 'tinggi']),
'selesai' => fake()->boolean(chanceOfGettingTrue: 30),
];
}
}
Beberapa hal yang perlu diperhatikan di sini:
User::factory()sebagai nilaiuser_idartinya setiap kali factoryCatatandigunakan, ia akan otomatis membuatUserbaru jika tidak ada yang di-supply. Ini memudahkan pembuatan data yang berelasi.fake()->sentence()menghasilkan kalimat acak sebagai judul.fake()->boolean(30)menghasilkantrue30% dari waktu — sehingga mayoritas catatan berstatus belum selesai, yang lebih realistis.
Tambahkan trait HasFactory ke model Catatan agar factory bisa digunakan:
// app/Models/Catatan.php
use Illuminate\Database\Eloquent\Factories\HasFactory;
class Catatan extends Model
{
use HasFactory;
use SoftDeletes;
// ...
}
Membuat Record dengan Factory
// Buat 1 record, simpan ke database
$catatan = Catatan::factory()->create();
// Buat 10 record sekaligus
$catatans = Catatan::factory()->count(10)->create();
// Override atribut tertentu
$catatan = Catatan::factory()->create([
'prioritas' => 'mendesak',
'selesai' => false,
]);
// Buat instance tanpa menyimpan ke database (untuk unit test)
$catatan = Catatan::factory()->make();
Factory States
Untuk variasi yang sering dipakai, definisikan state di factory:
// database/factories/CatatanFactory.php
public function mendesak(): static
{
return $this->state(fn (array $attributes) => [
'prioritas' => 'mendesak',
'selesai' => false,
]);
}
public function sudahSelesai(): static
{
return $this->state(fn (array $attributes) => [
'selesai' => true,
]);
}
Gunakan state saat membuat data:
// 5 catatan mendesak
Catatan::factory()->count(5)->mendesak()->create();
// 3 catatan yang sudah selesai
Catatan::factory()->count(3)->sudahSelesai()->create();
// Bisa di-chain
Catatan::factory()->sudahSelesai()->create(['prioritas' => 'rendah']);
Factory dengan Sequence
Untuk membuat data dengan pola berulang, gunakan sequence():
// Buat 6 catatan dengan prioritas bergantian
Catatan::factory()
->count(6)
->sequence(
['prioritas' => 'rendah'],
['prioritas' => 'normal'],
['prioritas' => 'tinggi'],
)
->create();
Hasilnya: 2 catatan rendah, 2 normal, 2 tinggi — sequence otomatis berulang.
Menggunakan Factory di Seeder
Perbarui CatatanSeeder untuk menggunakan factory alih-alih data statis:
// database/seeders/CatatanSeeder.php
use App\Models\Catatan;
use App\Models\User;
public function run(): void
{
// Pastikan ada minimal 1 user
$users = User::factory()->count(3)->create();
// Buat 20 catatan yang tersebar ke 3 user
$users->each(function (User $user) {
Catatan::factory()
->count(fake()->numberBetween(3, 8))
->for($user)
->create();
});
// Tambahkan beberapa catatan mendesak
Catatan::factory()
->count(5)
->mendesak()
->for($users->first())
->create();
}
Method for() digunakan untuk mengikat catatan ke user tertentu, menggantikan user_id yang ada di factory. Hasilnya: setiap user punya 3–8 catatan biasa ditambah 5 catatan mendesak untuk user pertama.
Jalankan:
php artisan migrate:fresh --seed
Database langsung terisi dengan data yang bervariasi dan realistis.
Tambahkan fake()->locale('id_ID') di config/app.php dengan key faker_locale untuk mendapatkan nama dan alamat Indonesia dari Faker, bukan nama barat. Ini membuat data seed terasa lebih relevan saat diperagakan ke klien lokal.
Latihan
Coba kerjakan latihan berikut:
-
Factory label — Buat factory untuk model
Labelyang kita buat di BAB 20. Gunakanfake()->colorName()untuk nama label danfake()->hexColor()untuk warna. BuatLabelSeederyang menghasilkan 10 label, lalu daftarkan diDatabaseSeeder. -
Relasi many-to-many di seeder — Di
CatatanSeeder, setelah membuat catatan, gunakansync()untuk melampirkan 1–3 label acak ke setiap catatan. Hint:Label::inRandomOrder()->limit(rand(1, 3))->pluck('id'). -
State kustom — Tambahkan state
terlambat()keCatatanFactoryyang mengisi kolomtenggatdengan tanggal di masa lalu danselesaibernilai false. Gunakan state ini untuk membuat 5 catatan terlambat di seeder.
Penutup Bab
Seeder dan factory menyelesaikan persiapan layer database kita. Model sudah punya relasi, atribut sudah punya transformasi yang tepat, dan sekarang database sudah bisa diisi dengan data yang realistis kapan saja dibutuhkan.
Bagian berikutnya membawa semua fondasi yang sudah dibangun ke dalam konteks nyata: membangun aplikasi CRUD lengkap dari awal. Kita akan mulai dari menginstal proyek Laravel baru, menghubungkannya ke database, lalu membangun fitur satu per satu sampai aplikasi benar-benar bisa digunakan.