はじめに

ルートモデル結合は、ルーティングを行う際にモデルインスタンスをルートに直接自動的に注入する強力な機能です。適切に使用することでコードを大きく短縮することができます。

対象バージョン Laravel11.x。

ルートモデル結合の使い方

route定義

use App\Http\Controllers\UserController;
use App\Models\User;

Route::get('/users/{user}', [UserController::class, 'show']);

URIにモデル名と一致する変数を入れることで、変数とidが一致するモデルインスタンスを自動的に注入します。上記のUserモデルの場合は{user}とします。

id以外を利用してモデルインスタンスを特定したい場合は{user:slug}とすることでカスタムキーが指定可能。

 

Controller側

use App\Models\User;

public function show(User $user)
{
    return view('user.profile', ['user' => $user]);
}

App\Models\User を指定することで引数にモデルインスタンスを受け取ることができます。

モデルインスタンスが自動的に注入されない場合、404HTTPレスポンスが返されます。これにより、コントローラー内で取得対象のモデルインスタンスが存在しない場合を考慮する必要がなくなります。

また、missing()メソッドを使用することで、モデルインスタンスが存在しない場合の処理を書き換えることも可能。

use App\Http\Controllers\LocationsController;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Redirect;

Route::get('/locations/{location:slug}', [LocationsController::class, 'show'])
    ->name('locations.view')
    ->missing(function (Request $request) {
        return Redirect::route('locations.index');
    });

 

複数のモデルに対してルートモデル結合を使用する場合。

use App\Http\Controllers\BlogController;
use App\Models\User;
use App\Models\Blog;

Route::get('/users/{user}/blog/{blog}', [BlogController::class, 'show']);
use App\Models\User;
use App\Models\Blog;

public function show(User $user, Blog $blog)
{
    return view('user.profile', ['user' => $user, 'blog' => $blog]);
}

 

このとき、2番目のモデルにカスタムキーを指定する、もしくはscopeBindings()メソッドを使用することで、2番目のモデルが1番目のモデルの子であるようにスコープを指定することもできます。

use App\Models\Post;
use App\Models\User;

Route::get('/users/{user}/posts/{post:slug}', function (User $user, Post $post) {
    return $post;
});

Route::get('/users/{user}/posts/{post}', function (User $user, Post $post) {
    return $post;
})->scopeBindings();

 

おわりに

このように、ルートモデル結合を使用することでコードを短縮することができます。

複雑な処理を必要としない場合は非常に強力な機能です。

参考文献

Laravel11.x ルートモデル結合