В чем преимущества Route Model Binding?
Есть у меня код, в котором вроде бы все понятно.
/**
* Display the specified resource.
*
* @param string $slug
* @return \Illuminate\View\View
*/
public function show(string $slug): \Illuminate\View\View
{
$post = Post::where('slug', $slug)
->where('status', 1) //
->with('reviews')
->firstOrFail();
return view('post.show', compact('post'));
}
Однако, более опытные коллеги, сделали замечание, что лучше бы применить Route Model Binding. Говорят, должна улучшится читаемость да и код будет проще.
Однако, при таком подходе, мне придется:
- В модели указать Sling как ключ для поиска.
- Отдельно подгрузить отношения через load().
- Прописать в модели resolveRouteBinding(), дабы можно было применить where().
Собственно... Кода становится не меньше и теперь он не так очевиден т.к разбросан по файлам, а не прописан в одном месте. Так в чем преимущества Route Model Binding?
Ответы (1 шт):
Идея в том, что конструкцию вида:
Post::where('slug', $slug)
->where('status', 1)
Вы можете использовать в куче контроллеров и методов. Потом добавится еще какой-нибудь параметр и Вам понадобится добавить их во все контроллеры.
Да есть решение через scope
public function scopeActive($builder)
{
$builder->where('status', 1);
}
public function scopeActiveSlug($builder, string $slug)
{
$builder->where('slug', $slug)->active();
}
...
Post::activeSlug($slug);
Но и здесть остаётся дубли Post::activeSlug($slug). Возникает идея, а что если на вход будет приходить сразу нужный пост. Как в случае с инжектированием зависимостей из сервис контейнеров.
В результате можно сделать следующее. В RouteServiceProvider добавить:
public function boot()
{
parent::boot();
Route::bind('postActive', function ($value) {
// scope то же оставляем, так как это хорошая практика. И потом может пригодиться в других местах
return App\Models\Post::activeSlug($value)
->firstOrFail();
});
}
В результате в маршруте будет:
Route::get('posts/{postActive}', [PostController::class, 'show']);
и в контроллере
public function show(Post $post): \Illuminate\View\View
{
$post->load('reviews');
return view('post.show', compact('post'));
}
Мы получаем более читабельный код, и во всех контроллерах ваши where заменятся на входной параметр, удаляя дубли. Далее вы просто одной строкой возвращаете view. В случае каких-либо изменений, вы просто в bind меняете условия и они применятся на все контроллеры где в маршруте используется поиск поста с ключом postActive