Dulunya, mungkin ini sangat repot, kita harus definisikan key apa yang ingin kita jadikan wildcardnya seperti berikut.
Route model binding dalam Laravel adalah fitur yang memudahkan Anda dalam mengambil record database berdasarkan parameter yang ada di URL. Laravel akan secara otomatis mencocokkan parameter URL dengan instance model yang sesuai.
Sebelum adanya model binding, Anda mungkin akan menuliskan kode seperti ini:
Route::get('users/{id}', function ($id) {
return User::findOrFail($id);
});
Atau mungkin jika dengan field lainnya:
Route::get('users/{username}', function ($username) {
return User::where('username', $username)->firstOrFail();
});
Ketika kita menggunakan route model binding ini, kita tidak perlu lagi membuat semacam query di dalam controller nya. Yang perlu kita lakukan adalah menuliskan versi singular dari model yang ingin kita gunakan di dalam route. Contohnya seperti ini:
Route::get('users/{user}', function (App\Models\User $user) {
return $user->email;
});
By default jika kita tidak memberikan key pada wildcard, maka Laravel akan mencocokkan dengan primary key dari model yang kita gunakan. Jadi dalam case ini Laravel akan mencocokkan dengan field id
dari model User
.
Namun, jika kita ingin mencocokkan dengan field lainnya, kita bisa menambahkan key pada wildcard nya. Contohnya seperti ini:
Route::get('users/{user:username}', function (App\Models\User $user) {
return $user->email;
});
Dengan begitu, kita akan mengunjugi URL seperti ini:
http://localhost:8000/users/john
Pastinya kita akan mendapatkan email dari user dengan username john
.
Terkadang ada kalanya kita ingin menampilkan object bukan hanya dari 1 key, bisa jadi 2 bahkan 3. Misal, di dalam model User
kita memiliki field username
dan id
. Kita ingin mencocokkan kedua field tersebut. Caranya adalah dengan menambahkan key nya seperti ini:
Route::get('users/{user:id,username}', function (App\Models\User $user) {
return $user->email;
});
Itu harapannya ya guys. Tapi sebenarnya itu belum bisa hahaha. Yang bisa kita lakukan saat ini adalah seperti:
Route::get('users/{identifier}', function ($identifier) {
return User::where('username', $identifier)->orWhere('id', $identifier)->firstOrFail();
});
Namun jika seperti itu, kita akan di tuntut untuk menuliskan query nya di dalam controller. Jadi, bagaimana cara kita untuk mencocokkan 2 identifier tersebut? Kita bisa menggunakan Route::bind
pada RouteServiceProvider
seperti ini:
use App\Models\User;
Route::bind('user', function ($value) {
return User::where('username', $value)->orWhere('id', $value)->firstOrFail();
});
Dengan begitu, kita bisa menggunakan simpel route seperti ini:
Route::get('users/{user}', function (App\Models\User $user) {
return $user->email;
});
Ketika Anda sudah paham tentang route model binding, Anda mungkin akan bertanya-tanya, bagaimana jika kita ingin menggunakan 2 model dalam 1 route? Misal kita ingin menampilkan artikel dari kategori tertentu. Kita bisa menggunakan route model binding seperti ini:
Route::get('articles/{category:slug}/{article:slug}', [ArticleController::class, 'show']);
Dalam case ini kita akan menggunakan controller. Jika kita membuat wildcard nya 2, pastinya di dalam method nya akan menerima 2 model.
use App\Models\Article;
use App\Models\Category;
public function show(Category $category, Article $article)
{
return $article;
}
Dan ini akan otomatis Not found (404) jika memang kategori yang diberikan tidak seusai dengan yang berelasi dengan artikel.
Namun, jika kita coba untuk tidak menggunakan explicit binding, maka Not found tidak akan terjadi. Contoh nya seperti ini:
Route::get('articles/{category}/{article}', [ArticleController::class, 'show']);
Jika kita coba untuk mengunjungi URL seperti ini:
http://routing.test/articles/2/1
Yang saat ini, pada tabel artikel tidak memiliki relasi ke kategori dengan id 2. Namun, kita tidak akan mendapatkan Not found. Karena Laravel akan mencoba untuk mencocokkan dengan primary key dari model yang kita gunakan. Jadi, jika kita ingin menggunakan implicit binding, kita harus menambahkan key nya seperti contoh pada explicit binding.
Pertanyaan nya adalah, bagaimana jika kita tidak ingin menggunakan key nya? Karena memang kita ingin dari keduanya di identifikasi dari id nya. Kita bisa menggunakan scoped binding seperti ini:
Route::get('articles/{category}/{article}', [ArticleController::class, 'show'])->scopeBindings();
Maka dengan begitu, ketika kita mengunjungi url yang sama seperti di atas, kita akan mendapatkan Not found.
Ketika kita bekerja dengan route resource. Dalam case ini, kita akan beranggapan bahwa ada table playlist dan juga episode. Yang mana 2 tabel tersebut akan benar-benar berhubungan dalam case apapun.
Maka route yang kita lakukan adalah seperti:
Route::resource('{playlist}/{episode}', EpisodeController::class);
Dalam case ini, kita benar-benar ingin bahwa yang ada di url adalah model yang berelasi. Dengan resource
kita tidak bisa menggunakan yang namanya scopeBindings()
, maka kita bisa menggunakan ->shallow()()
seperti ini:
Route::resource('{playlist}/{episode}', EpisodeController::class)->shallow();
Dengan begitu, jika playlist atau episode tidak berelasi satu sama lain, maka kita akan mendapatkan Not found.
Ketika Anda menggunakan fitur soft deletes di laravel, semua route yang telah dihapus akan otomatis mendapatkan Not found. Namun, jika Anda ingin menampilkan route yang telah dihapus, Anda bisa menggunakan withTrashed()
seperti ini:
Route::get('articles/{article}', [ArticleController::class, 'restore'])->withTrashed();
Ketika Anda menggunakan route caching, maka semua route yang Anda buat akan di cache. Sehingga, ketika Anda membuat route baru, maka route tersebut tidak akan terbaca. Untuk mengatasi hal tersebut, Anda bisa menggunakan php artisan route:clear
untuk menghapus cache route Anda.
Semoga artikel ini bermanfaat untuk Anda. Jika ada pertanyaan, silahkan bertanya di discord atau langsung dm saya di twitter. Terima kasih.
Let's start living like no one can help us in any event, so that when we are helped in certain times, it becomes a plus in itself.