В чем преимущества 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. Говорят, должна улучшится читаемость да и код будет проще.

Однако, при таком подходе, мне придется:

  1. В модели указать Sling как ключ для поиска.
  2. Отдельно подгрузить отношения через load().
  3. Прописать в модели resolveRouteBinding(), дабы можно было применить where().

Собственно... Кода становится не меньше и теперь он не так очевиден т.к разбросан по файлам, а не прописан в одном месте. Так в чем преимущества Route Model Binding?


Ответы (1 шт):

Автор решения: Dmitrii Sedov

Идея в том, что конструкцию вида:

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

→ Ссылка