LaravelRoutingEloquentPemula4 mnt baca

Route Model Binding: Otomatis Ambil Data

Biarkan Laravel mengubah {post} menjadi model Post otomatis, termasuk 404-nya.

Analogi: Pelayan yang Sudah Tahu Pesananmu

Bayangkan kamu pelanggan tetap di warteg. Kamu baru duduk, pelayan langsung menghidangkan "nasi setengah, ayam goreng, es teh manis" tanpa kamu memesan. Ia mengenali kamu dan tahu persis maumu.

Route model binding seperti pelayan itu. Kamu menulis {post} di route dan type-hint Post $post di method, Laravel langsung mengambilkan data post dari database. Tidak perlu menulis Post::find($id) manual, tidak perlu cek 404 manual. Datang, duduk, hidangan tersaji.

Kenapa Fitur Ini Ada? Masalah Apa yang Diselesaikan?

Pola paling berulang di aplikasi web adalah: terima ID dari URL, cari di database, kalau tidak ketemu tampilkan 404. Di PHP murni dan Laravel awal, pola ini ditulis manual berkali-kali:

php
// Cara manual yang melelahkan (dan rawan lupa cek null):
public function show(string $id)
{
    $post = Post::find($id);
    if (!$post) abort(404);
    return view('posts.show', compact('post'));
}

Tiga baris boilerplate di setiap method, dan kalau lupa cek null, aplikasi error 500 dengan pesan membingungkan alih-alih 404 yang rapi. Route model binding menghapus boilerplate itu: satu type-hint menggantikan tiga baris, dan 404 ditangani otomatis dengan benar.

Contoh 1: Implicit Binding, Sihir Dasarnya

php
// routes/web.php
use App\Models\Post;
use Illuminate\Support\Facades\Route;

// Nama parameter {post} SAMA dengan nama variabel Post $post
Route::get('/post/{post}', function (Post $post) {
    return $post->title; // $post sudah berupa MODEL, bukan string id!
});
php
// app/Http/Controllers/PostController.php: versi controller, lebih rapi
public function show(Post $post)
{
    return view('posts.show', compact('post'));
}

Yang terjadi di balik layar: Laravel melihat type-hint Post, mengambil nilai {post} dari URL (misal 42), menjalankan Post::where('id', 42)->firstOrFail(). Kalau tidak ketemu, otomatis 404. Kamu tidak menulis satu baris pun query.

Contoh 2: Binding Pakai Slug (URL Cantik)

ID angka itu jelek untuk URL publik: /post/42 tidak memberi tahu apa-apa. Slug lebih ramah: /post/cara-menanam-cabai. Caranya, beri tahu model kolom mana yang dipakai untuk binding:

php
// app/Models/Post.php
class Post extends Model
{
    // Default binding pakai kolom 'id', override ke 'slug':
    public function getRouteKeyName(): string
    {
        return 'slug';
    }
}
php
// routes/web.php: route-nya TIDAK berubah sama sekali!
Route::get('/post/{post}', function (Post $post) {
    return view('posts.show', compact('post'));
});
// /post/cara-menanam-cabai → Laravel mencari WHERE slug = 'cara-menanam-cabai'

Route tetap {post}, tapi Laravel sekarang mencari berdasarkan kolom slug. Satu method kecil di model mengubah perilaku seluruh aplikasi. Itulah kekuatan konvensi.

Catatan teknis: Implicit binding punya dua syarat keras yang tidak bisa ditawar: (1) type-hint-nya harus Eloquent model, dan (2) nama variabel harus SAMA PERSIS dengan nama parameter route. {post} cocok dengan Post $post, tapi {post} dengan Post $artikel GAGAL diam-diam (variabelnya jadi null/error). Ini sumber bug paling licin untuk pemula.

Kesalahan Umum Pemula

Salah: nama variabel tidak sama dengan nama parameter route.

php
// SALAH: {post} vs $artikel: binding gagal diam-diam
Route::get('/post/{post}', function (Post $artikel) {
    // $artikel tidak terisi model! Laravel tidak tahu {post} = $artikel
});
php
// BENAR: nama harus sama persis
Route::get('/post/{post}', function (Post $post) {
    return $post->title; // aman, sudah berupa model
});

Salah: mencampur binding dengan query manual yang redundan.

php
// SALAH: sudah dapat model dari binding, masih query lagi
public function show(Post $post)
{
    $post = Post::findOrFail($post->id); // mubazir: query dua kali!
    return view('posts.show', compact('post'));
}
php
// BENAR: percaya pada binding, langsung pakai
public function show(Post $post)
{
    return view('posts.show', compact('post'));
}

Kalau $post sudah berupa model hasil binding, jangan query ulang. Query ganda seperti ini tidak merusak, tapi memperlambat dan menunjukkan kamu belum paham apa yang diberikan framework.

Rangkuman

Route model binding mengubah {post} menjadi objek Post otomatis: type-hint model + nama variabel yang sama persis, dan 404 gratis. Butuh URL cantik? Override getRouteKeyName() ke 'slug'. Berikutnya: merapikan puluhan route sekaligus dengan route group.

Tantangan

Binding Slug

Tambahkan kolom slug (string, unique) ke tabel posts via migration. Override getRouteKeyName() di model Post. Buat route /post/{post} dan buktikan /post/slug-artikelmu menampilkan judul artikel.