Resource Controller: 7 Aksi CRUD Sekaligus
Generate 7 route CRUD standar dengan satu baris Route::resource.
Analogi: Paket "Hajatan Lengkap" di Katering
Katering punya paket "hajatan lengkap": tenda, kursi, prasmanan, pelayan, sound system, satu harga. Kamu tidak memesan satu per satu. Hampir semua aplikasi CRUD butuh paket yang sama: tampilkan daftar, tampilkan form tambah, simpan, tampilkan satu, tampilkan form edit, update, hapus.
Resource controller adalah paket hajatan itu: satu perintah Artisan membuat controller dengan 7 method standar, satu baris Route::resource mendaftarkan 7 route standar. Kamu tinggal mengisi tiap method.
Kenapa Resource Ada? Masalah Apa yang Diselesaikan?
Tanpa resource, setiap CRUD ditulis manual: 7 route + 7 method per entitas. Punya 10 entitas (post, user, produk, kategori...)? Itu 70 route dan 70 method yang polanya identik. Selain melelahkan, setiap programmer menamai route seenaknya: tampilkan_post, postLihat, lihatPost, kacau.
Resource menyelesaikan dua hal: kecepatan (scaffolding 7 aksi sekaligus) dan standarisasi nama (semua orang memakai posts.index, posts.store, dst). Developer yang pindah project langsung paham tanpa membaca dokumentasi.
Contoh 1: Satu Baris, Tujuh Route
# Buat controller lengkap dengan 7 method kosong
php artisan make:controller PostController --resource// routes/web.php
use App\Http\Controllers\PostController;
Route::resource('posts', PostController::class);Satu baris itu mendaftarkan 7 route. Cek dengan php artisan route:list:
| Method | URI | Nama | Aksi Controller |
|---|---|---|---|
| GET | /posts | posts.index | index() |
| GET | /posts/create | posts.create | create() |
| POST | /posts | posts.store | store() |
| GET | /posts/{post} | posts.show | show() |
| GET | /posts/{post}/edit | posts.edit | edit() |
| PUT/PATCH | /posts/{post} | posts.update | update() |
| DELETE | /posts/{post} | posts.destroy | destroy() |
Perhatikan polanya: create/edit menampilkan FORM (GET), store/update/destroy memproses DATA. Route model binding otomatis aktif di {post}.
Contoh 2: Membatasi dan Versi API
Jarang semua 7 aksi dibutuhkan. Blog publik misalnya tidak butuh form create/edit di web (itu urusan admin):
// routes/web.php: hanya yang dibutuhkan
Route::resource('posts', PostController::class)->only(['index', 'show']);
// atau: semua kecuali destroy (hapus hanya via admin khusus)
Route::resource('posts', PostController::class)->except(['destroy']);Untuk API (tanpa form HTML, hanya JSON), pakai apiResource:
// routes/api.php: otomatis tanpa create & edit (tidak ada form di API)
Route::apiResource('posts', PostController::class);
// menghasilkan: index, store, show, update, destroy (5 route)Dan isi method-nya mengikuti pola standar yang sama di semua project:
// app/Http/Controllers/PostController.php
public function create()
{
return view('posts.create'); // tampilkan form kosong
}
public function store(Request $request)
{
$data = $request->validate(['title' => 'required|max:255', 'body' => 'required']);
$post = Post::create($data);
return redirect()->route('posts.show', $post);
}
public function edit(Post $post)
{
return view('posts.edit', compact('post')); // tampilkan form terisi data
}
public function update(Request $request, Post $post)
{
$post->update($request->validate(['title' => 'required|max:255', 'body' => 'required']));
return redirect()->route('posts.show', $post);
}
public function destroy(Post $post)
{
$post->delete();
return redirect()->route('posts.index');
}Catatan teknis: Form HTML hanya mendukung GET dan POST. Untuk PUT/PATCH/DELETE, Blade menyediakan
@method('PUT')yang menyisipkan hidden input_method. Trik ini disebut method spoofing, dan Laravel membacanya otomatis:blade<form method="POST" action="{{ route('posts.update', $post) }}"> @csrf @method('PUT') <!-- input form --> </form>
Kesalahan Umum Pemula
Salah: memakai Route::resource lalu menimpa salah satu route-nya secara manual hingga bentrok.
// SALAH: route kustom menimpa route resource tanpa sadar
Route::resource('posts', PostController::class);
Route::get('/posts/populer', [PostController::class, 'populer']);
// /posts/populer DITANGKAP oleh route show ({post} = "populer") karena
// didefinisikan SETELAH resource! Ingat: route dicocokkan dari atas ke bawah.// BENAR: route kustom yang spesifik ditulis SEBELUM resource
Route::get('/posts/populer', [PostController::class, 'populer']);
Route::resource('posts', PostController::class);Salah: lupa @method('PUT')/@method('DELETE') di form edit/hapus.
{{-- SALAH: form edit tanpa method spoofing → dikirim sebagai POST biasa --}}
<form method="POST" action="{{ route('posts.update', $post) }}">
@csrf
{{-- hasilnya: 405 Method Not Allowed, karena route update butuh PUT --}}
</form>{{-- BENAR --}}
<form method="POST" action="{{ route('posts.update', $post) }}">
@csrf
@method('PUT')
</form>Error 405 (Method Not Allowed) pada form edit/hapus hampir selalu berarti @method ketinggalan.
Rangkuman
Resource controller adalah paket CRUD lengkap: make:controller --resource + Route::resource menghasilkan 7 aksi standar dengan nama yang konsisten. Batasi dengan only/except, pakai apiResource untuk API, dan ingat method spoofing untuk form PUT/DELETE. Modul Pemula selesai di sini, selamat! Berikutnya kamu siap masuk ke Blade templating di level Menengah.
Tantangan
Resource Produk
Buat ProductController --resource dan daftarkan Route::resource('products', ...)->except(['destroy']). Jalankan route:list: berapa route terdaftar? Sebutkan nama-namanya.
Kuis Bab
Uji pemahamanmu: Bab 2: Routing
Jawab 5 soal berikut, lalu tekan "Periksa Jawaban".
1.Route dicocokkan dengan urutan seperti apa?
2.Apa syarat implicit route model binding bekerja?
3.Berapa route yang dibuat Route::resource('posts', ...)?
4.Kenapa route:cache gagal jika ada route closure?
5.Bagaimana cara kirim PUT dari form HTML?