Hey everyone! Are you using Laravel?
I'm currently working mainly with TypeScript, but I also touch Laravel from time to time.
Checking if data exists after receiving a request is a pretty common scenario. I recently discovered something new (to me at least!), so I wanted to share it with you all.
Traditional Implementation Patterns
Let's say you have a feature that retrieves post information using a post_id
and displays the details on the screen.
class PostController extends Controller
{
public function edit(PostEditRequest $request)
{
$detail = Post::where('id', $request->post_id)->first();
return view('post', ['data' => $detail]);
}
}
And in the FormRequest:
class PostEditRequest extends FormRequest
{
public function rules()
{
return [
'post_id' => 'required|exists:posts,id'
];
}
}
Alternatively, you might set up routing like this:
Route::get('/post/{id}', [PostController::class, 'edit']);
And handle it in the controller:
class PostController extends Controller
{
public function edit(int $id)
{
$detail = Post::where('id', $id)->first();
if (is_null($detail)) {
// Handle error
}
return view('post', ['data' => $detail]);
}
}
These are pretty standard patterns, right?
What is Route Model Binding?
What I recently learned about is "Route Model Binding" - apparently it's been around for quite a while. (Please don't judge me for not knowing about it! 😅)
With Route Model Binding, you can do this:
Route::get('/post/{post}', [PostController::class, 'edit']);
And in your controller:
class PostController extends Controller
{
public function edit(Post $post)
{
return view('post', ['data' => $post]);
}
}
By the time your code reaches the controller, you already have an Eloquent Model instance!
Plus, if the ID doesn't exist, Laravel automatically returns a 404 error. How convenient!
Searching by Non-Primary Key Columns
You can also do this:
Route::get('/post/{post:post_uuid}', [PostController::class, 'edit']);
This searches by a different column. If found, the controller processes it; if not, you get a 404.
If you need ID validation but implementing a FormRequest feels like overkill, this approach might be perfect for your use case.
Binding Related Models
Here's a bonus: you can also use Route Model Binding with related data.
For example, let's say you want to retrieve Employee data that belongs to a specific Company:
Route::get('/company/{company}/employee/{employee}', [EmployeeController::class, 'detail'])->scopeBindings();
This ensures you have the employee model that's associated with the company when the controller processes the request.
In your controller:
class EmployeeController extends Controller
{
public function detail(Company $company, Employee $employee)
{
// Do something
}
}
For this to work, Laravel's Eloquent ORM needs to understand the parent-child relationship. You'll need to define the relationship in your Company model:
class Company extends Model
{
public function employees(): HasMany
{
return $this->hasMany(Employee::class);
}
}
(There are other ways to establish these relationships, but I'll skip those for now.)
Summary
- Route Model Binding gives you a Model instance by the time you reach the controller
- Great for simple implementations where you don't need complex validation
- Automatically returns a 404 error for non-existent data
- You can search by columns other than the primary key
- Parent-child relationships can be bound using
scopeBindings()
- This automatically verifies that the specified employee actually belongs to that company
When to Use What
- Use FormRequest when: You have complex validation rules or need custom error messages
- Use Route Model Binding when: Simple existence checks are sufficient and you want cleaner code
Wrapping Up
Route Model Binding is simple and incredibly convenient! Laravel still has so many features I haven't discovered yet. I'll share more as I find them!
Top comments (0)