Laravel Route bindings
Laravel allows you to explicitely and implicitely bind parameters in the route to models in your controller methods. This includes all kinds of scoping and configuration, but this only works if your route can determine the base model of the route parameter.
There are basically two ways of configuring this base model. The first one is an explicit route binding, where you indicate the slug and explicitly bind that slug to a specific model:
https://laravel.com/docs/10.x/routing#customizing-the-resolution-logic
use App\Models\User;
use Illuminate\Support\Facades\Route;
/**
use App\Models\User;
use Illuminate\Support\Facades\Route;
/**
* Define your route model bindings, pattern filters, etc.
*/
public function boot(): void
{
// default binding version that searches a model by id
Route::model('user', User::class);
// bind a parameter and return any kind of model
Route::bind('username', function (string $parameter) {
return User::where('name', $parameter)->firstOrFail();
});
}
If you use explicit binding, you need to indicate the search field for the binding in the name of the explicitely bound parameter. In the above example, the {username} parameter indicates searching a user bound by name.
If you want to use implicit binding, the framework will look at the parameters of the controller method to invoke for the route. In this case it is mandatory that the name of the parameter in that method matches the route parameter name exactly. The model associated with that specific parameter is than instantiated, implicitely, searching by id on default, but you can indicate a different column to search for in the route parameter.
Route::get('/{project:slug}', function(Project $project) {
...
});
Note that in this case the route parameter name matches the method parameter name. The route parameter is extended by a column name to search for (and of course, this column should be a unique value). And the method parameter is type hinted, allowing Laravel to instantiate the correct model and then perform a resolveRouteBinding call on that model.
If you do not have a single column with a unique value to search for, but can create a concatenated fieldname in the url (e.g.: date plus title), you can override the models resolveRouteBinding to extract the data yourself:
class Blog extends Model
{
...
public function resolveRouteBinding($value, $field = null)
{
if ($field == 'dateandname') {
list($date, $name) = explode('-', $dateandname);
return $this->where('date', $date)->where('name', $name)->firstOrFail();
}
return $this->where('id', $value)->firstOrFail();
}
}
..
Route::get('/{blog:dateandname}', function(Blog $blog) {
...
});
However, note that this again only works if the base model is type hinted in the invoked methods.