Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

andyg1's avatar

Route Model Binding - optional RouteKeyName

On my front-end I am using the slug field to access the objects e.g.

site.dev/slug-of-title/

and have set it using the getRouteKeyName() method.

On my admin side of the site, I am building the CRUD pages for all these things. I wanted my URLs to be the simple ones e.g.

site.dev/admin/object/1
site.dev/admin/object/3/edit

etc

But the system is still expecting to access the resource from the slug, not the id.

Is it possible to optionally override this so I don't have the slug-ified URLs for my admin section?

(I should state that I am using resource controllers...) Thanks

0 likes
12 replies
guc43's avatar

I think (not testet) you can use the explicit binding in your RouteServiceProvider. Check the documentation here: https://laravel.com/docs/5.6/routing#route-model-binding

and try this in your RouteServiceProvider

Route::bind('uid', function ($value) {
        return App\User::where('id', $value)->first() ?? abort(404);
    });
Route::bind('uslug', function ($value) {
        return App\User::where('slug', $value)->first() ?? abort(404);
    });

and in your Routes

// frontend
Route::get('profile/{uslug}', function (App\User $user) {
    //
});
//backend
Route::get('admin/{uid}', function (App\User $user) {
    //
});

as i said, i didn't test it and can't test it right now :(

rumm.an's avatar

Assuming that your admin side is on site.com/admin. This could be a work around, Im not sure.

function getRouteKeyName()
{
    return Request::segment(1) === 'admin' ? 'id' : 'slug';
}

If Request::segment() doesnt work you can use your own logic to check if you are on admin side. Hope it helps! ;)

martinbean's avatar

@andyg1 Unfortunately not. You’ll need to define a second parameter name and use explicit route–model binding to resolve it, i.e.

// Use default key name for admin routes
Route::get('admin/articles/{article}/edit', 'Admin\ArticleController@edit');

// Use a different slug-based parameter for front-end routes
Route::get('articles/{articleSlug}', 'ArticleController@show');

// Create the binding for slug parameters
Route::bind('articleSlug', function ($slug) {
    return Article::whereSlug($slug)->firstOrFail();
});
martinbean's avatar

@rin4ik Feel free to use @rumm.an’s solution. I prefer to route requests based on parameters, and not “magic” happening in my models.

2 likes
andyg1's avatar

Agreed @martinbean - their way introduces a dependency (the URL prefix) into the model. I'd rather keep responsibilities separate and have route logic where it belongs. Your suggestion is cleaner. Thanks

1 like
rumm.an's avatar

@martinbean that way $articleSlug will be resolved into a model instance but now the variable name suggests it is slug but it is a model instance. Not the end of world, but I like readability. Anyways, didn't knew about Route::bind. It is a good use case. Liked it!

Cronix's avatar

Why not just use the slug everywhere? Does it matter if it's a slug or ID for the admin urls?

marcosdipaolo's avatar

@Cronix it's what i thought in the beginning, since i needed slugs in my products urls and not ids, but when the time comes where you have to build an e-commerce cart where you'll charge money to people's credit cards, isn't an incremental id less error prone and secure?. I've actually coded some logic to make slugs unique on product's create and update, but still i was unsecure to use slugs for the critical stuff.

Snapey's avatar

@marcosdipaolo

isn't an incremental id less error prone and secure?

less error prone AND less secure

Better to use a hashid or uuid.

How about a separate model for admin use which has a different routeKeyName?

kurucu's avatar

What is the Laravel 10 way of doing this? I've tried {article:slug} for my web routes, and {article:id} for my api routes, and they are both using the id (so I get a 404 on the front end). If I set getRouteKeyName to return 'slug' then I get a 404 on the front end - any ideas?

Please or to participate in this conversation.