Advanced Laravel route parameters casting.

Pavel Buchnev
3 min readApr 22, 2021

Hello, everyone!

Most of the laravel developers have used Explicit Binding at least once. When we speak about explicit model binding we mean convention based model resolution, you can define how route parameters correspond with models.

// RouteServiceProvider.phppublic function boot()
{
Route::model('user', User::class);
// orRoute::bind('user', function ($value) {
return User::where('name', $value)->firstOrFail();
});
// web.phpRoute::get('/users/{user}', function (User $user) {
//
});

99% of the laravel developers use Route Model Binding every day. Implicit Binding is — automatically resolving Eloquent models defined in routes or controller actions whose type-hinted variable names match a route segment name.

// web.phpRoute::get('/users/{user}', function (User $user) {
// ...
});
// orRoute::get('/users/{user}', 'UserController@show');// UserController.phppublic function show(User $user)
{
// ...
}

In case of Explicit Binding everything is clear, because we explicitly bind specific parameter with a model or a closure. But what about Implicit Binding?

Let’s look at this in more detail.

Implicit Binding

The name speaks for itself. A developer simply specifies model type for route parameter or controller action and the router automatically resolves Eloquent models.

How does this happen?

The starting point for this process is middleware — \Illuminate\Routing\Middleware\SubstituteBindings .

It has two purposes:

  1. Custom binding registration throughRoute:bind andRoute::model
  2. Looking for route parameters that implementing \Illuminate\Contracts\Routing\UrlRoutable interface and then resolving these. If you look at the Eloquent class, you’ll see that the class implements the interface.

The main purpose of the middleware is to look for route parameters with the interface and replace them with Eloquent models.

Below you’ll find the vary basic representation of the middleware function

You can find the full code of the middleware here: https://github.com/laravel/framework/blob/8.x/src/Illuminate/Routing/ImplicitRouteBinding.php#L21

Once we understand how it works we can create our own implementation of the route parameters resolving.

Custom solution

Let’s imagine that we use uuidinstead of auto increment ids. The first thing we want to do is to validate a route parameter and cast it to Ramsey\Uuid\UuidInterface.

Here are the route and controller examples

// web.php
Route::get('user/{user}', 'UserController@show')
// UserController.php
public function show(\Ramsey\Uuid\UuidInterface $user)
{
// ...
}

And we want to make a simple request

GET http://site.com/user/123e4567-e89b-12d3-a456-426614174000

and cast the uuid to Ramsey\Uuid\UuidInterface interface, something like this:

// Creates a UUID instance from a string UUID with automatically string validation
$uuid = \Ramsey\Uuid\Uuid::fromString(...);

The simplest way is to use Route:bind function. You can see an example below

But there is a huge disadvantage: what if we don’t want to use uuid or userUuid parameter names? We have to remember all the parameter names and .

We can do the route parameters binding in a better way!

What if we automatically cast all the route parameters, type-hinted with Ramsey\Uuid\UuidInterface to an object that resolves the interface.

Let’s try to do it.

According to implicit binding we explored above, I like the idea doing this using middleware and then use the middleware everywhere we want. (by analogy with \Illuminate\Routing\Middleware\SubstituteBindings middleware)

You can see the full code of the middleware below

And then we register the middleware in App\Http\Kernel.php . Something like this

protected $middlewareGroups = [
'web' => [
...
\App\Interfaces\Http\Middleware\SubstituteUuids::class,
],
'api' => [
...
],
];

And the laravel framework will automatically take care of the route parameters casting.

Thank you!

If you liked this article, let me know here :)

--

--