How To Define Route Model Binding In Laravel With Example

admin_img Posted By Bajarangi soft , Posted On 17-09-2020

When injecting a model ID to a route or controller action, you will often query to retrieve the model that corresponds to that ID. Laravel route model binding provides a convenient way to automatically inject the model instances directly into your routes. For example, instead of injecting a user's ID, you can inject the entire User model instance that matches the given ID.

How To Define Route Model Binding In Laravel With Example

Implicit Binding

Laravel automatically resolves Eloquent models defined in routes or controller actions whose type-hinted variable names match a route segment name.

For example:


Create below route in web.php file

Route::get('api/users/{user_id}', function (App\User $user) {
    return $user->email;// we get user email
});


After creating just pass  url in google chrome (http://localhost/laraveldemoproject/public/api/users/1) you get user email id 

Since the $user variable is type-hinted as the App\User Eloquent model and the variable name matches the {user} URI segment, Laravel will automatically inject the model instance that has an ID matching the corresponding value from the request URI.
If a matching model instance is not found in the database, a 404 HTTP response will automatically be generated.


Customizing The Key

Sometimes you may wish to resolve Eloquent models using a column other than id. To do so, you may specify the column in the route parameter definition:

Create new controller model and migration file using below command in command prompt

php artisan make:controller democontroller -mcr

Now create new route to access data as below

Route::get('api/demos/{demo:id}', function (App\demo $demo) {
    return $demo;
});


Custom Keys & Scoping

Sometimes, when implicitly binding multiple Eloquent models in a single route definition, you may wish to scope the second Eloquent model such that it must be a child of the first Eloquent model.

For example, consider this situation that retrieves a blog demo by id for a specific user:

use App\demo;
use App\User;

Route::get('api/users/{user}/demos/{demo:id}', function (User $user, demo $demo) {
    return $demo;
});


When using a custom keyed implicit binding as a nested route parameter, Laravel will automatically scope the query to retrieve the nested model by its parent using conventions to guess the relationship name on the parent. In this case, it will be assumed that the User model has a relationship named demos(the plural of the route parameter name) which can be used to retrieve the demos model.

Customizing The Default Key Name

If you would like model binding to use a default database column other than id when retrieving a given model class, you may override the getRouteKeyName method on the Eloquent model:
 

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class demo extends Model
{
    protected $fillable = [
        'title', 'description'
    ];

    public function getRouteKeyName()
    {
        return 'title';
    }
}
 

Explicit Binding

Example(1)
Create service provider in provider folder using below commands

php artisan make:provider demoServiceProvider


To register an explicit binding, use the router's model method to specify the class for a given parameter.
You should define your explicit model bindings in the boot method of the RouteServiceProvider class:


Open demoServiceProvider.php and implement below code in that file

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use App\User;

class demoServiceProvider extends ServiceProvider
{
    /**
     * Register services.
     *
     * @return void
     */
    public function register()
    {
        //
    }

    /**
     * Bootstrap services.
     *
     * @return void
     */
    public function boot()
    {
        parent::boot();

        Route::model('user', User::class);
    }
}


Next, define a route that contains a {user} parameter:

Route::get('profile/{user}', function (App\User $user) {
    return $user->name;
});


Pass url in google chrome as below url

http://localhost/laraveldemoproject/public/profile/1


Since we have bound all {user} parameters to the App\User model, a User instance will be injected into the route. So, for example, a request to profile/1 will inject the User instance from the database which has an ID of 1

If a matching model instance is not found in the database, a 404 HTTP response will be automatically generated.


Customizing The Resolution Logic

If you wish to use your own resolution logic, you may use the Route::bind method. The Closure you pass to the bind method will receive the value of the URI segment and should return the instance of the class that should be injected into the route:

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use App\User;

class demoServiceProvider extends ServiceProvider
{
    /**
     * Register services.
     *
     * @return void
     */
    public function register()
    {
        //
    }

    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        parent::boot();

        Route::bind('user', function ($value) {
            return User::where('name', $value)->firstOrFail();
        });
    }
}



Alternatively, you may override the resolveRouteBinding method on your Eloquent model. This method will receive the value of the URI segment and should return the instance of the class that should be injected into the route:
<?php

namespace App;

use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name', 'email', 'password',
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password', 'remember_token',
    ];

    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];

    public function resolveRouteBinding($value, $field = null)
    {
        return $this->where('name', $value)->firstOrFail();
    }
}

Related Post