LaravelControllerCRUDPemula5 mnt baca

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

bash
# Buat controller lengkap dengan 7 method kosong
php artisan make:controller PostController --resource
php
// 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:

MethodURINamaAksi Controller
GET/postsposts.indexindex()
GET/posts/createposts.createcreate()
POST/postsposts.storestore()
GET/posts/{post}posts.showshow()
GET/posts/{post}/editposts.editedit()
PUT/PATCH/posts/{post}posts.updateupdate()
DELETE/posts/{post}posts.destroydestroy()

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):

php
// 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:

php
// 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:

php
// 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.

php
// 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.
php
// 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.

blade
{{-- 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>
blade
{{-- 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?