Eloquent Create: Menyimpan Data Baru
Tiga cara menyimpan data: save, create, dan firstOrCreate.
Kenapa Ada Banyak Cara Menyimpan?
Menyimpan data baru adalah operasi paling sering di aplikasi CRUD. Laravel menyediakan tiga pola utama karena kebutuhannya berbeda: kadang kamu perlu mengolah data dulu sebelum disimpan, kadang cukup satu baris langsung jadi, kadang kamu harus memastikan tidak ada duplikat. Memilih pola yang tepat membuat kode lebih pendek dan maksudnya jelas terbaca oleh programmer lain.
Cara 1: new + save()
Pola paling eksplisit. Kamu membuat instance model kosong, mengisi atribut satu per satu, lalu memanggil save().
// app/Http/Controllers/PostController.php
$post = new Post();
$post->title = $request->title;
$post->slug = Str::slug($request->title);
$post->published_at = $request->publish_now ? now() : null;
$post->save(); // INSERT INTO posts ...Pola ini cocok saat atribut butuh diolah dulu: membuat slug, hash password, atau set nilai default bersyarat. Langkah-langkahnya terlihat jelas berurutan, gampang di-debug.
Jebakan umum: lupa memanggil save(). Model yang baru di-instansiasi belum punya id dan belum ada di database sampai save() dipanggil. Kalau kamu me-return $post tanpa save, datanya diam-diam tidak tersimpan dan tidak ada error sama sekali. Silent bug yang bikin bingung setengah jam.
Cara 2: create() Massal
Satu baris, langsung INSERT, dan mengembalikan model yang sudah tersimpan (id-nya sudah terisi).
// app/Http/Controllers/PostController.php
$post = Post::create([
'title' => $request->title,
'body' => $request->body,
'category_id' => $request->category_id,
]);Syaratnya: kolom-kolom itu harus didaftarkan di $fillable pada model, kalau tidak Laravel melempar MassAssignmentException. Itu fitur keamanan, bukan bug (dibahas tuntas di modul mass-assignment). Pola ini paling enak dipasangkan dengan Form Request validation:
// app/Http/Controllers/PostController.php
public function store(StorePostRequest $request)
{
$post = Post::create($request->validated());
return redirect()->route('posts.show', $post);
}$request->validated() hanya berisi field yang lolos validasi, jadi create() menerima data yang sudah bersih.
Jebakan umum: memanggil create($request->all()) tanpa validasi dan tanpa $fillable yang benar. Itu jalan pintas menuju celah keamanan karena user bisa mengirim field apa pun lewat request.
Cara 3: firstOrCreate()
Pola "cari dulu, buat kalau belum ada". Berguna untuk data referensi seperti kategori atau tag yang tidak boleh duplikat.
// database/seeders/CategorySeeder.php
$category = Category::firstOrCreate(
['slug' => 'teknologi'], // kunci pencarian
['name' => 'Teknologi'], // dipakai hanya saat membuat baru
);Argumen pertama dipakai untuk mencari. Kalau ketemu, model itu dikembalikan tanpa diubah. Kalau tidak ketemu, argumen pertama digabung dengan argumen kedua lalu di-insert.
Jebakan umum: menaruh semua atribut di argumen pertama. Kalau 'name' ikut jadi kunci pencarian, perubahan kecil pada nama akan membuat baris baru padahal slug-nya sama. Kunci pencarian harus kolom yang benar-benar unik dan stabil, seperti slug atau kode.
Catatan teknis: firstOrCreate() menjalankan SELECT lalu INSERT sebagai dua query terpisah, jadi di traffic tinggi masih ada celah race condition (dua request membuat baris kembar nyaris bersamaan). Untuk jaminan mutlak, pasang unique constraint di database pada kolom kunci (misalnya slug) dan tangani exception-nya. firstOrCreate mencegah duplikat di level aplikasi, unique constraint mencegahnya di level database. Ada juga updateOrCreate() yang mirip, bedanya ia meng-update baris yang ketemu dengan nilai argumen kedua.
Memilih Pola yang Tepat
| Situasi | Pola yang dipakai |
|---|---|
| Atribut butuh diolah dulu (slug, hash, default bersyarat) | new + save() |
| Data sudah bersih dari validasi | create() |
| Data referensi yang tidak boleh duplikat | firstOrCreate() |
Satu lagi yang sering dipakai untuk sinkronisasi data: updateOrCreate(). Mirip firstOrCreate, bedanya kalau baris ketemu ia langsung di-update dengan nilai argumen kedua:
// app/Console/Commands/SinkronKategori.php
Category::updateOrCreate(
['slug' => 'teknologi'],
['name' => 'Teknologi & Gadget'], // di-update kalau slug sudah ada
);Cocok untuk import CSV atau sinkronisasi API eksternal yang dijalankan berulang: dijalankan sepuluh kali pun hasilnya tetap konsisten.
Tantangan
Seed Manual
Via tinker, buat 3 kategori dengan firstOrCreate (berdasarkan slug). Jalankan 2 kali dan buktikan tidak ada duplikat (count tetap 3).