Konvensi Model: Nama Tabel dan Key
Pahami konvensi penamaan Laravel dan cara meng-override-nya.
Konsep: Convention over Configuration
Framework lama memaksamu menulis konfigurasi untuk segalanya: model Post pakai tabel apa? Primary key-nya kolom apa? Laravel membalik filosofinya: kalau kamu mengikuti konvensi penamaan, tidak perlu konfigurasi sama sekali. Model Post otomatis memakai tabel posts dengan primary key id. Nol baris konfigurasi.
Ini bukan sulap, cuma aturan yang konsisten: model singular PascalCase (UserProfile), tabel plural snake_case (user_profiles), primary key id, dan kolom created_at/updated_at otomatis dikelola.
Contoh 1: Konvensi Bawaan
| Model | Tabel | Primary Key |
|---|---|---|
| Post | posts | id |
| Category | categories | id |
| UserProfile | user_profiles | id |
File: app/Models/Category.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Category extends Model
{
// tidak perlu properti apa pun:
// tabel 'categories', PK 'id', timestamps aktif
}Migration pasangannya mengikuti konvensi yang sama:
File: database/migrations/2026_10_08_140000_create_categories_table.php
return new class extends Migration {
public function up(): void
{
Schema::create('categories', function (Blueprint $table) {
$table->id(); // PK 'id', auto-increment
$table->string('name');
$table->timestamps(); // created_at + updated_at
});
}
// ...
};Selama kamu mengikuti pola ini, Eloquent "tahu" segalanya tanpa diberi tahu.
Contoh 2: Override untuk Tabel Legacy
Kadang kamu mewarisi database lama yang tidak mengikuti konvensi, misal tabel tbl_berita dengan PK id_berita (string, bukan auto-increment) dan tanpa timestamps:
File: app/Models/Berita.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Berita extends Model
{
protected $table = 'tbl_berita'; // tabel tidak mengikuti konvensi
protected $primaryKey = 'id_berita'; // PK bukan 'id'
public $incrementing = false; // PK bukan auto-increment
protected $keyType = 'string'; // PK berupa string
public $timestamps = false; // tanpa created_at/updated_at
}Satu lagi yang wajib di setiap model baru: $fillable, daftar kolom yang boleh diisi massal (detail penuh di modul mass-assignment):
protected $fillable = ['title', 'body', 'published_at'];Tanpa ini, Post::create([...]) melempar MassAssignmentException. Ini fitur keamanan, bukan bug.
Jebakan Umum
1. Override yang tidak lengkap. Menyetel protected $primaryKey = 'id_berita' tapi lupa public $timestamps = false padahal tabel tidak punya created_at. Hasilnya setiap save() error karena kolom tidak ada. Kalau override satu, cek semua asumsi konvensi yang dilanggar tabelmu.
2. $keyType dan $incrementing tidak sinkron. PK string (UUID) tapi $incrementing masih true: Laravel menganggap PK berupa integer auto-increment dan merusak nilai UUID saat insert. Keduanya harus disetel berpasangan.
3. Melawan konvensi tanpa alasan. Membuat tabel data_post untuk model Post "biar keren" hanya menambah satu baris $table yang harus diingat seluruh tim selamanya. Ikuti konvensi kecuali ada alasan nyata (seperti tabel legacy). Setiap override adalah utang pengetahuan.
Catatan teknis: Konvensi juga berlaku untuk foreign key:
user_idmenunjuk ke tabelusers. Method relasi sepertibelongsTomemakai tebakan ini, jadi penamaan kolom yang konsisten membuat relasi Eloquent bekerja tanpa konfigurasi tambahan.
Tantangan
Model Legacy
Misal ada tabel legacy tbl_berita dengan PK id_berita (bukan auto-increment) dan tanpa timestamps. Tulis model Berita yang benar dengan semua override yang diperlukan.
Kuis Bab
Uji pemahamanmu: Bab 4: Migration dan Seeder
Jawab 5 soal berikut, lalu tekan "Periksa Jawaban".
1.Apa fungsi method down() di migration?
2.Perintah untuk membatalkan migration batch terakhir?
3.Kenapa migrate:fresh berbahaya di production?
4.Apa kegunaan Factory dibanding Seeder manual?
5.Model Post secara konvensi memakai tabel apa?