Eloquent: Model
Memahami ORM Eloquent: konvensi model, mass assignment (#[Fillable]), casting, accessor, dan soft delete.
Eloquent ORM
Eloquent memetakan tabel database ke class PHP (model) dan baris ke objek. Pola ini disebut Active Record: objek model tahu cara menyimpan dirinya sendiri. Kamu bekerja dengan objek, Laravel menulis SQL-nya.
php artisan make:model Produk -mf # model + migration + factory
Konvensi
| Hal | Konvensi | Contoh |
|---|---|---|
| Nama tabel | snake_case jamak dari nama class | Produk → produks, OrderItem → order_items |
| Kunci utama | id | |
| Timestamps | created_at, updated_at diisi otomatis |
Menyimpang dari konvensi: atribut #[Table] (Laravel 13)
use Illuminate\Database\Eloquent\Attributes\Table;
#[Table('produk')] // nama tabel lain
class Produk extends Model {}
#[Table(key: 'kode_produk')] // kunci utama lain
#[Table(timestamps: false)] // tanpa created_at/updated_at
Atribut model Laravel 13 lain: #[Fillable], #[Unguarded], #[WithoutIncrementing], #[WithoutTimestamps], #[DateFormat], #[Connection], #[ScopedBy], #[ObservedBy]. Cara lama dengan properti (protected $table = '...', $fillable) tetap berlaku.
Mass assignment dan #[Fillable]
Produk::create($request->all()) berbahaya: pengguna jahat bisa menyisipkan kolom yang tak kamu duga (mis. is_admin=1). Karena itu Eloquent mewajibkan kamu mendaftarkan kolom yang boleh diisi massal:
use Illuminate\Database\Eloquent\Attributes\Fillable;
#[Fillable(['kategori_id', 'nama', 'slug', 'deskripsi', 'harga', 'stok', 'aktif'])]
class Produk extends Model
{
// cara lama setara: protected $fillable = [...];
}
Kebalikannya $guarded (daftar kolom terlarang). Praktik terbaik: whitelist dengan fillable, dan tetap validasi input.
Casting
protected function casts(): array
{
return [
'harga' => 'integer',
'aktif' => 'boolean',
'atribut' => 'array', // kolom JSON ↔ array PHP
'terbit_pada'=> 'datetime', // ↔ objek Carbon
'password' => 'hashed', // otomatis di-hash saat diisi
];
}
Accessor & mutator
Mengubah nilai saat dibaca/ditulis, memakai Attribute::make:
use Illuminate\Database\Eloquent\Casts\Attribute;
protected function hargaRupiah(): Attribute
{
return Attribute::make(
get: fn () => 'Rp' . number_format($this->harga, 0, ',', '.'),
);
}
protected function nama(): Attribute
{
return Attribute::make(
set: fn (string $nilai) => trim($nilai), // mutator
);
}
// pemakaian: $produk->harga_rupiah (camelCase method → snake_case properti)
Soft delete
use Illuminate\Database\Eloquent\SoftDeletes;
class Produk extends Model
{
use SoftDeletes; // butuh kolom deleted_at ($table->softDeletes())
}
$produk->delete(); // hanya mengisi deleted_at
Produk::withTrashed()->get(); // termasuk yang terhapus
$produk->restore(); // pulihkan
$produk->forceDelete(); // hapus permanen
Atribut tersembunyi
Kolom yang jangan ikut saat model diubah ke array/JSON (mis. password) didaftarkan di protected $hidden = ['password'];.
Strictness (disarankan di development)
Di AppServiceProvider::boot(): Model::shouldBeStrict(! app()->isProduction()); membantu menangkap bug seperti N+1 dan atribut yang tak ada.