Laravel Route Model binding using Multiple keys
Laravel tutorial on how to retrieve a model instance using its id or slug, leveraging Laravel route model binding
Laravel ships with route model binding, the abilty to pass data through the get request, Laravel out of the box, captures the value, and find the matched model instance.
Lets assume we have the famous task list app, where we can see task on the index page of our website but we can visit each task by its Id.
We setup Laravel
Installation of Laravel
Laravel new Tasklist
We have to create a database, and change credentials to connect to the database through our .env file.
I use sqlite database. so I run the command:
touch database/database.sqlite
Then we specify the driver on our .env file:
DB_CONNECTION=sqlite
Our project world
We create a model Task, with migration, factory, seeder and resourceful controller.
php artisan make:model Task -a
Model created successfully.
Factory created successfully.
Created Migration: 2021_09_09_084744_create_tasks_table
Seeder created successfully.
Controller created successfully.
Lets first create some tasks to work with:
Given a task has only a title, in our tasks migration file, we add the title to our table, it ca
Schema::create('tasks', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->string('slug')->unique();
$table->timestamps();
});
We run the command to migrate our databse.
php artisan migrate
// tables migrated successfully
In our TaskFactory, we give it what it should return as a dummy data. we create a fake sentence,
return [
'title' => $title = $this->faker->sentence(),
'slug' => \Illuminate\Support\Str::slug($title),
];
Lets give our seeder the number (10) of factories we want to create
public function run()
{
\App\Models\Task::factory(10)->create();
}
In our DatabaseSeeder.php we have to call the TaskSeeder Class
public function run()
{
$this->call([
TaskSeeder::class,
]);
// we can directly add our task seeder here \App\Models\Task::factory(10)->create();
}
Lets seed our data.
php artisan db:seed
We check through the browser
To see all our tasks in our routes file we
use App\Http\Controllers\TaskController;
Route::get('/', [TaskController::class, 'index']);
In our TaskController
public function index()
{
return \App\Models\Task::all();
}
now we visit the index of our website
tasklist.test
This will print out all our tasks, we can see the slug and Id, of course.
Route Model binding
Now in our routes folder, web.php file we get the tasks using route model binding defaults, which is the ID.
Route::get('/{task}', [TaskController::class, 'show']);
In our controller show method, we return the task, Laravel will automatically give as the task instance using the ID, from the URI given.
public function show(Task $task)
{
return $task;
}
Route Model binding using multiple keys
Lets assume for whatever reason, we want the tasks either using the ID, or a slug as well,
We go to our AppServiceProvider.php in our Providers folder.
\Route::bind('task', function ($value){
return \App\Models\Task::where('slug', $value)->orWhere( function ($query) use ($value){
if (is_numeric($value)){
$query->where('id', $value);
}
})->firstOrFail();
});
Now whenever we visit tasks through id tasklist.test/1
or we visit by slug tasklist.test/facere-provident-corrupti-quibusdam-magnam
we get the same result.
id: "1"
title: "Facere provident corrupti quibusdam magnam."
slug: "facere-provident-corrupti-quibusdam-magnam"