Laravel as a framework either for building websites or a container to build APIs (lumen) has evolved as a developer’s framework of choice. Laravel comes with a lot of growing features - take for example Laravel’s events. Events in Laravel used to be a simple pub-sub library, but now Laravel events can broadcast all the way to the client and allows us to create real-time apps.
But that’s beside the point, today’s celebrity is Laravel’s route model binding.
Route model binding in Laravel provides a mechanism to inject a model instance into your routes. Still not clear on the meaning, here is an example. Say we want to get a post from the database, we could do something like this:
...
// the route parameter is the id of the post
// for example http://example.com/posts/53
Route::get('posts/{id}', function ($id) {
// we have to find the post using the $id
$post = Post::find($id);
// if there is no post, 404
if (!$post) return abort(404);
// return the view and the post
return view('post.show', compact('post'));
});
...
We could further go on to simplify this method into
...
// the route parameter is the id of the post
// for example http://awesome.dev/posts/53
Route::get('posts/{id}', function ($id) {
// find the post or 404 if not found
$post = Post::findOrFail($id);
// return the view and the post
return view('post.show', compact('post'));
});
...
But route model binding helps us get rid of extra keystrokes by simplifying both instances above into
...
// by using $post, we can inject the Post object
Route::get('posts/{post}', function ($post) {
// we now have access to the $post object! no code necessary
// return the view and the post
return view('post.show', compact('post'));
});
...
This is made possible by telling Laravel to inject a Post
model into any route controller that has a {post}
parameter attached to it.
Laravel currently supports two types of route model bindings. We have:
Note: The example of route model binding listed above is explicit.
While we’ve seen explicit model binding, here’s an example of implicit model binding now:
Route::get('posts/{post}', function (App\Post $post) {
// be awesome. enjoy having the $post object
});
Laravel is smart enough to know that since a Post
model is being injected into the controller closure, it should get the id
parameter from the route and get the details for the user.
Accessing a post will still be done using http://awesome.example.com/posts/24
.
If you would like the implicit model binding to use a database column other than id
when retrieving models, you may override the getRouteKeyName
method on your Eloquent model.
For instance, if we wanted to use the slug
instead of the id
, we could do the following:
class Post extends Model {
public function getRouteKeyName() {
return 'slug';
}
}
Then we could access our route using http://awesome.example.com/posts/my-post-slug
instead of http://awesome.example.com/posts/24
.
Just like the name implies, you have to explicitly tell Laravel you want it to bind a url
parameter to a particular model. There are two ways to do this, we could bind a parameter to a model using the provided Route
facade or carry out this binding in app/Providers/RouteServiceProvider.php
(I prefer this method).
Route
FacadeUsing the Route
facade to bind a parameter to a model, we can do something like this:
Route::bind('post', 'App\Post');
We could also give our binding more meaning, for example, what if we want a post only if is a draft? For that, we could change the second parameter of the Route::bind
to a closure which takes the route parameter as its value.
Route::bind('post', function ($value) {
return App\Post::find($value)->where('status', '=', 'published')->first();
});
RouteServiceProvider
The only difference between using the Route
facade and RouteServiceProvider
class is that - registering your bindings is done in the boot
method of the RouteServiceProvider
class (location is app/Providers
directory) and the bind
method is called on the $router
object injected into the method. Quick example
public function boot(Router $router)
{
parent::boot($router);
$router->bind('post', function ($value) {
return App\Post::find($value)->where('status', '=', 'published')->first();
});
}
I build a lot of APIs, so custom exceptions for route model bindings are actually more useful for people like me. Laravel provides an easy way for us to do this. Still in the boot
method of the RouteServiceProvider
class, call the model
method on the $router
object.
The model
method takes three arguments, the arguments are similar to that of the bind
method, with a new addition the third argument which is a closure that throws the new exception.
$router->model($routeParameter, $modelToBind, function () {
throw new NotFoundHTTPException;
});
You can read more about route model binding in the documentation.
Hopefully this small, but neat feature can save you a few lines of code in your projects and make your controllers that much cleaner.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!
helpful content. thanks