Mass Assignment: $fillable dan $guarded
Pahami proteksi mass assignment dan cara pakainya dengan benar.
Cerita Seramnya Dulu
Tahun 2012, GitHub pernah kebobolan lewat celah ini: seseorang menambahkan parameter is_admin pada form dan langsung menjadi admin. Sejak itu framework modern mewajibkan proteksi mass assignment, dan Laravel menyalakannya secara default. Kamu harus paham cara kerjanya supaya tidak malah melawannya dengan $guarded = [].
Masalahnya: Input User Mengisi Kolom Apa Pun
Mass assignment artinya mengisi banyak atribut model sekaligus dari sebuah array, biasanya langsung dari input user:
// app/Http/Controllers/UserController.php
// JANGAN LAKUKAN INI:
User::create($request->all());Kalau request berisi is_admin=1 (sangat gampang ditambahkan lewat devtools browser), kolom itu ikut tersimpan dan user biasa naik pangkat jadi admin. Validasi tidak otomatis menolong: field is_admin bisa saja lolos validasi atau tidak divalidasi sama sekali.
Solusi: $fillable (Whitelist)
// app/Models/User.php
class User extends Model
{
protected $fillable = ['name', 'email', 'password'];
}Hanya kolom yang terdaftar yang boleh diisi secara massal. is_admin tidak ada di daftar, jadi diam-diam diabaikan saat create() atau update([...]). Diam-diam artinya tidak error, hanya tidak tersimpan. Itu disengaja: form boleh mengirim field ekstra tanpa membuat aplikasi meledak.
Alternatif: $guarded (Blacklist)
// app/Models/User.php
protected $guarded = ['id', 'is_admin'];Kebalikannya: semua kolom boleh diisi kecuali yang disebut. Terlihat praktis saat tabel punya banyak kolom aman, tapi berisiko: kolom sensitif yang ditambahkan belakangan (misalnya is_verified) otomatis terbuka sampai kamu ingat menambahkannya ke $guarded. Karena itu $fillable (whitelist) lebih aman secara default: yang baru otomatis tertutup.
Jebakan paling fatal: protected $guarded = []; artinya tidak ada yang dijaga, semua kolom terbuka untuk mass assignment. Ini mematikan proteksi sepenuhnya. Banyak tutorial lama menyarankan ini "agar gampang", jangan ikuti di project nyata.
Catatan teknis: Proteksi ini HANYA berlaku untuk mass assignment: create(), update([...]), dan fill(). Assignment langsung tetap bisa karena itu keputusan eksplisit programmer di dalam kode, bukan dari input user: $user->is_admin = true; $user->save(); Cara aman menaikkan seseorang jadi admin adalah lewat kode eksplisit seperti itu, atau lewat form khusus admin yang terpisah. Pola terbaik menggabungkan dua lapis pertahanan: $fillable di model plus Form Request validation, lalu User::create($request->validated()); validated() hanya mengembalikan field yang lolos aturan validasi.
fill() untuk Update Bertahap
create() bukan satu-satunya bentuk mass assignment. fill() mengisi atribut tanpa menyimpan, berguna saat kamu perlu memeriksa sesuatu dulu sebelum save:
// app/Http/Controllers/PostController.php
$post = new Post();
$post->fill($request->validated());
if ($post->isDirty('title')) {
$post->slug = Str::slug($post->title);
}
$post->save();isDirty() mengecek apakah sebuah atribut berubah sejak model di-load atau dibuat. Pola fill lalu save memberi fleksibilitas new + save() dengan keringkasan mass assignment, dan tetap dilindungi $fillable.
Satu pengecualian yang sadar: di seeder kamu mengontrol penuh datanya sehingga mass assignment aman-aman saja, tapi $fillable tetap berlaku. Kalau seeder perlu mengisi kolom di luar $fillable, isi lewat assignment langsung ($model->kolom = x) alih-alih mematikan proteksi.
Tantangan
Uji Proteksi
Buat model dengan $fillable TANPA kolom role. Via tinker, coba Model::create([...,'role'=>'admin']). Apa yang terjadi dengan kolom role? Buktikan dengan mengecek datanya.