Laravel’s route model binding is a very powerful feature. It provides a nice and simple way to fetch automatically models from the database based on the credentials that the URI contains. Let’s take a look at how to make it even more flexible by binding contracts instead of implementations.
Binding a Contract to a Model
First of all, let’s take a look, how to bind a contract to a model in the container. This is a very simple process, all we need to do is call the bind() method in our service provider.
use App\Contracts\User as Contract; use App\Models\User; public function register() { $this->app->bind(Contract::class, User::class); }
From this point, when we inject the contract using the container, we’ll receive a model instance. But, it won’t work as we expect. We’ll get a new model, but not the one from the database. So let’s create a custom route model binding for that.
Custom Route Model Binding Using the Contract
So, let’s create an explicit route-model binding in one of our service providers, but instead of resolving a model directly, let’s use the container to get the bound implementation:
use Contracts\User as Contract; use Illuminate\Support\Facades\Route; public function boot() { Route::bind('user', function (string $value, $route) { return $this->app->make(Contracts::class)->resolveRouteBinding( $value, $route->bindingFieldFor('user') ); }); }
So in our routes, we can type-hint our contract and it’ll return with the desired model property:
use Contracts\User as Contract; use Illuminate\Support\Facades\Route; Route::get('users/{user}', function (Contract $user) { return $user; });
Summary
You may ask, why is this even useful? Well, most of the cases this is not the best pattern we can go for, however, sometimes this can provide an extra layer of flexibility.
For example, let’s say you are writing a package that provides a basic CRUD functionality, but you want to give the change to the developers to swap the implementation for the bound model. They can easily override the bound model and return their own.