В Laravel есть удобный механизм, который позволяет автоматически подставлять модели в маршруты и контроллеры — Route Model Binding. Благодаря ему можно избежать лишнего кода для поиска модели в базе и сразу работать с готовым экземпляром.
Зачем нужен Route Model Binding?
Обычно, если мы хотим получить запись из базы по id, приходится писать что-то вроде:
Route::get('/users/{id}', function ($id) {
$user = User::findOrFail($id);
return $user;
});
С Route Model Binding это сокращается до:
Route::get('/users/{user}', function (User $user) {
return $user;
});
Laravel автоматически поймёт, что {user} в маршруте нужно заменить на модель User, и выполнит запрос в БД.
Виды Route Model Binding
1. Неявное (Implicit Binding)
Route::get('/posts/{post}', function (Post $post) {
return $post;
});
Поиск происходит по id (или по ключу из getRouteKeyName). Если модель не найдена — вернётся 404.
2. Явное (Explicit Binding)
Route::bind('post', function ($value) {
return Post::where('slug', $value)->firstOrFail();
});
Route::get('/posts/{post}', function (Post $post) {
return $post;
});
Здесь мы сами определяем, как именно искать модель.
3. Кастомизация ключа поиска (getRouteKeyName)
class Post extends Model
{
public function getRouteKeyName()
{
return 'slug';
}
}
Теперь {post} будет искаться по slug, а не по id.
Scoped Route Model Binding (scopeBindings)
Иногда нужно подгружать вложенные ресурсы, и тогда простого биндинга недостаточно. Например, у пользователя (User) есть посты (Post), и важно, чтобы загруженный post действительно принадлежал указанному user.
Без scopeBindings
Route::get('/users/{user}/posts/{post}', function (User $user, Post $post) {
return $post;
});
/users/1/posts/10 сработает даже если пост id=10 не принадлежит пользователю id=1.
С включением scopeBindings
Route::get('/users/{user}/posts/{post}', function (User $user, Post $post) {
return $post;
})->scopeBindings();
Теперь /users/1/posts/10 вернёт 404, если пост не принадлежит пользователю.
Route Model Binding в контроллерах
Route::get('/posts/{post}', [PostController::class, 'show']);
class PostController extends Controller
{
public function show(Post $post)
{
return view('posts.show', compact('post'));
}
}
Laravel автоматически загрузит модель и передаст её в метод контроллера.
Дополнительные возможности
🔹 Optional Binding
Route::get('/posts/{post?}', function (?Post $post) {
return $post ?? 'Нет поста';
});
Сравнительная таблица способов Route Model Binding
| Способ | Где применяется | Как работает | Пример |
|---|---|---|---|
| Implicit (неявный) | Везде (по умолчанию) | Поиск по id или getRouteKeyName() |
Route::get('/posts/{post}', fn(Post $post) => $post); |
| Explicit (явный) | RouteServiceProvider / Route::bind | Полный контроль над логикой поиска | Route::bind('post', fn($v) => Post::where('slug', $v)->firstOrFail()); |
| getRouteKeyName | В модели | Позволяет указать поле для поиска (например, slug) |
В модели: public function getRouteKeyName() { return 'slug'; } |
| scopeBindings | Вложенные маршруты | Проверяет, принадлежит ли дочерняя модель родителю | Route::get('/users/{user}/posts/{post}')->scopeBindings(); |
| Optional Binding | В маршрутах | Параметр может быть пустым (null) |
Route::get('/posts/{post?}', fn(?Post $post) => $post ?? 'Нет поста'); |
Преимущества Route Model Binding
- Меньше кода — не нужно вручную писать
findOrFail(). - Единообразие — маршруты становятся чище и понятнее.
- Гибкость — легко переопределить ключ поиска или добавить кастомную логику.
- Безопасность — при отсутствии модели возвращается 404.
- scopeBindings — защищает вложенные маршруты от доступа к чужим данным.
Итог
Route Model Binding — это мощный инструмент Laravel, который позволяет работать с моделями напрямую в маршрутах и контроллерах.
- Если нужен поиск по
id— используем неявный биндинг. - Если по другому ключу —
getRouteKeyNameили явный биндинг. - Для вложенных ресурсов — scopeBindings().
- Для опциональных параметров — Optional Binding.