DEV Community

yone3
yone3

Posted on

Simplify Your Laravel Code with Route Model Binding!

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]);
  }
}
Enter fullscreen mode Exit fullscreen mode

And in the FormRequest:

class PostEditRequest extends FormRequest
{
  public function rules()
  {
    return [
      'post_id' => 'required|exists:posts,id'
    ];
  }
}
Enter fullscreen mode Exit fullscreen mode

Alternatively, you might set up routing like this:

Route::get('/post/{id}', [PostController::class, 'edit']);
Enter fullscreen mode Exit fullscreen mode

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]);
  }
}
Enter fullscreen mode Exit fullscreen mode

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']);
Enter fullscreen mode Exit fullscreen mode

And in your controller:

class PostController extends Controller
{
  public function edit(Post $post)
  {
    return view('post', ['data' => $post]);
  }
}
Enter fullscreen mode Exit fullscreen mode

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']);
Enter fullscreen mode Exit fullscreen mode

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();
Enter fullscreen mode Exit fullscreen mode

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
  }
}
Enter fullscreen mode Exit fullscreen mode

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);
  }
}
Enter fullscreen mode Exit fullscreen mode

(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)