May 5, 2020 by Glenn

Implicit Route Model Binding

A simple refactor and easy win. Implicit route model binding was introduced way back in 2015 with Laravel 5.2, however all these years later I still find apps out in the wild doing things the hard way. Let's take a look at how route model binding can help you clean things up a bit.

In this example, we'll pretend we have a BlogController with a show method. You would probably have a setup that looks something similar to this:

// routes/web.php
Route::get('/blog/{id}', 'BlogController@show')
// app/Http/Controllers/BlogController
public function show($id)
{
    $blog = Blog::findOrFail($id);

    return view('blog.show', compact('blog'));
}

While this is perfecty fine, the reality is Laravel is already wired out of the box to do some of this work for us. With implicit route model binding we can get rid of that findOrFail and save ourselves a line of code.

First we'll want to update our route definition, changing the route segment name of id to the name of the variable we ultimately want to use in our controller method. In this case, blog seems to be an appropriate name.

// routes/web.php
//Route::get('/blog/{id}', 'BlogController@show')
Route::get('/blog/{blog}', 'BlogController@show')

Next, we'll want to update the method signature of our show method, type-hinting the model we're trying to find, and updating the variable name to one that matches our route segment name.

// app/Http/Controllers/BlogController
//public function show($id)
public function show(Blog $blog)
{
    //$blog = Blog::findOrFail($id);
    //
    return view('blog.show', compact('blog'));
}

And that's it! Using implicit route model binding, Laravel will resolve the correct Blog entry for us. Everything still functions the way it did before; looking for a model id that doesn't exist still throws a 404, etc. It's an easy change and lets you remove some code, which is always a plus.

Customizing the Key Name

Are you looking up your model by a key other than its id? No problem! With the release of Laravel 7.0 it couldn't be more simple. You just need to specify that in the route parameter definition by adding :key to the route segment name.

// routes/web.php
//Route::get('/blog/{id}', 'BlogController@show')
//Route::get('/blog/{blog}', 'BlogController@show')
Route::get('/blog/{blog:slug}', 'BlogController@show')

Now if you're stuck on a version of Laravel prior to 7.0, it's still a relatively simple change. We'll leave our route definition as it was, and instead we'll just add a method to the model that we're wanting to be resolved for us.

// routes/web.php
Route::get('/blog/{blog}', 'BlogController@show')
// app/Blog.php
public function getRouteKeyName()
{
    return 'slug';
}

The getRouteKeyName method should return a string; the name of the key you wish to use for lookups.

Join my mailing list

Subscribe now to stay up to date on whatever cool stuff I'm working on.

View Past Newsletters