Laravel · Bab 5
Lab 2: Migrasi & Model Eloquent
Membangun tabel categories, products, dan transactions sebagai kode lewat migrasi, lengkap dengan foreign key, model Eloquent, relasi, dan data awal dari seeder.
Di lab ini kamu menerapkan Database as Code: struktur tiga tabel Smart Retail App (categories, products, transactions) ditulis sebagai file migrasi, lalu setiap tabel dipasangkan dengan Model Eloquent beserta relasinya. Contoh kode di halaman ini memakai studi kasus perpustakaan (authors dan books); terapkan polanya ke tabel Retail Store sesuai desain di Bab 3.
Alur Langkah
- Category — jalankan
php artisan make:modeluntuk model Category beserta migrasinya (-m), isi methodup()migrasi (id,nameunik,descriptionopsional,timestamps), lalu isi Model dengan$fillabledan relasihasManyke Product. - Product — buat model + migrasi Product, isi skema kolom (
category_idsebagai foreign key,product_codeunik,name,price,stockdengan nilai awal 0,timestamps), lalu isi Model dengan$fillable, relasibelongsToke Category, danhasManyke Transaction. - Transaction — buat model + migrasi Transaction, isi skema (
product_idsebagai foreign key,invoice_numberunik,quantity,total_price,transaction_date,timestamps), lalu isi Model dengan$fillabledan relasibelongsToke Product. - Migrasi & seeder — jalankan
php artisan migrate, isidatabase/seeders/DatabaseSeeder.phpdengan tiga kategori awal dan satu akun kasir (password di-hash), lalu jalankanphp artisan db:seed.
Model & Migrasi dengan Artisan
Satu perintah membuat Model sekaligus file migrasinya:
php artisan make:model <NamaModel> -m
Opsi -m meminta Artisan membuat file migrasi database/migrations/xxxx_xx_xx_xxxxxx_create_<nama_tabel>_table.php, sedangkan Model dibuat di app/Models/<NamaModel>.php. Nama tabel diturunkan otomatis dari nama Model sesuai aturan emas di Bab 2 (tunggal → jamak).
Schema Builder
Isi method up() pada file migrasi mendefinisikan kolom tabel. Contoh tabel authors:
public function up(): void
{
Schema::create('authors', function (Blueprint $table) {
$table->id();
$table->string('name')->unique();
$table->string('bio')->nullable();
$table->integer('book_count')->default(0);
$table->date('born_at')->nullable();
$table->timestamps();
});
}
| Pemanggilan | Arti |
|---|---|
$table->id() | Kolom id auto-increment sebagai primary key |
string('kolom') | Teks pendek (VARCHAR) |
integer('kolom') | Bilangan bulat, misalnya harga dan stok |
date('kolom') | Tanggal |
->unique() | Nilai tidak boleh kembar |
->nullable() | Boleh kosong |
->default(0) | Nilai awal bila tidak diisi |
timestamps() | Kolom created_at dan updated_at |
Foreign Key Constraint
Tabel anak menyimpan ID baris tabel induk. Contoh: setiap buku menunjuk satu penulis.
$table->foreignId('author_id')->constrained('authors')->onDelete('cascade');
foreignId('author_id')membuat kolom penampung ID induk.constrained('authors')memasang aturan di level database bahwa nilainya wajib ada di tabelauthors.onDelete('cascade')ikut menghapus baris anak ketika baris induknya dihapus.
Urutan migrasi penting. Migrasi dijalankan berdasarkan timestamp di awal nama file, jadi tabel induk harus dibuat lebih dulu daripada tabel anak. Di Retail Store urutannya categories → products → transactions, sesuai urutan kamu menjalankan make:model.
Model, $fillable & Relasi
Model mewakili satu tabel. Daftarkan kolom yang boleh diisi massal di $fillable, lalu definisikan relasinya sebagai method:
class Author extends Model
{
use HasFactory;
protected $fillable = ['name', 'bio'];
// Satu penulis memiliki BANYAK buku
public function books()
{
return $this->hasMany(Book::class, 'author_id');
}
}
Sisi sebaliknya ada di Model Book:
// Satu buku dimiliki SATU penulis
public function author()
{
return $this->belongsTo(Author::class, 'author_id');
}
Di Retail Store, pola yang sama dipakai dua kali: Category hasMany Product (Product belongsTo Category), dan Product hasMany Transaction (Transaction belongsTo Product). Pastikan semua kolom yang diisi dari form tercantum di $fillable masing-masing Model.
Menjalankan Migrasi & Seeder
Jalankan migrasi untuk membuat semua tabel di database:
php artisan migrate
Jika perlu mengulang dari nol (misalnya setelah memperbaiki urutan migrasi), php artisan migrate:fresh menghapus semua tabel lalu menjalankan ulang seluruh migrasi secara berurutan.
Seeder mengisi data awal secara seragam. Isi method run() di database/seeders/DatabaseSeeder.php:
use App\Models\Author;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
public function run(): void
{
Author::create(['name' => 'Andrea Hirata', 'bio' => 'Penulis Laskar Pelangi']);
User::create([
'name' => 'Petugas Perpustakaan',
'email' => '<email-petugas>',
'password' => Hash::make('<kata-sandi>'),
]);
}
Password wajib di-hash dengan Hash::make, karena proses login di Lab 7 membandingkan hash, bukan teks biasa. Lalu jalankan:
php artisan db:seed
Hasil yang Diharapkan
Di HeidiSQL/phpMyAdmin, database db_retail_store berisi tabel categories, products, dan transactions (plus tabel bawaan Laravel seperti users). Tabel categories sudah berisi tiga kategori, dan tabel users berisi satu akun kasir dengan password yang sudah ter-hash.