ルートモデル結合とはなんぞ
今回フォーカスを当てるのは「ルートモデル結合」
これがとても便利で
ルートモデル結合をしたルーティングの場合、
パラメータに対象のモデルIDを渡すだけで紐づくモデルインスタンスをルートに自動注入してくれる
実際書いてみるとこんな感じ
- routes/web.php
use App\Models\User;
Route::get('/users/{user}', function (User $user) {
return $user->email;
});
上記ルーティングを設定の上、例えば /users/10
にアクセスした場合、
usersテーブルにID=10のレコードがあればそれを関数の引数に渡してくれて、
なければ404 Not Foundのエラーを吐いてくれる
パラメータで渡されたid
を使用して対象のレコードを取得&存在チェックを行う従来の処理と比べるとかなりシンプルになる
- web/routes.php
use App\Models\User;
// 従来の処理の場合
Route::get('/users/{id}', function (int $id) {
$user = User::find($id);
if (!$user) {
abort(404);
}
return $user->email;
});
// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
// ルートモデル結合を活用した場合
Route::get('/users/{user}', function (User $user) {
return $user->email;
});
/users/{user}
の{user}
の部分を対象のモデル名の小文字にしてあげればOK
これだけでルーティング側がタイプヒントしてくれて、関数の中ではパラメータIDに対応する値と一致するIDを持つモデルインスタンスを自動的に挿入される
例えばUserモデルじゃなくてPostモデルを対象にしたい場合はこんな感じ/posts/{post}
Controllerで使用する場合も同様
これまでの例ではroutes/web.php
内で完結させてるけど
Controllerで使用する場合でも同じ
- routes/web.php
use App\Http\Controllers\UserController;
Route::get('/user/{user}', [UserController::class, 'show']);
- UserController
<?php
namespace App\Http\Controllers;
use App\Models\User;
class UserController extends Controller
{
public function show(User $user)
{
return $user->email;
}
}
従来のルーティングと同様にURLを生成すればOK
// urlを使用する場合
<a href="{{ url('/users/10')}}>リンク</a>
// routeを使用する場合
<a href="{{ route('users.show', ['user' => 10]) }}>リンク</a>
// モデル変数がある場合はそれをそのまま渡すでOK
<a href="{{ route('users.show', $user) }}>リンク</a>
IDのカラム以外でルートモデル結合するようにカスタマイズする
例えばポータルサイトのユーザープロフィール画面などで、
IDではなくユーザー名をパラメータにしたい場合
- routes/web.php
use App\Http\Controllers\UserController;
Route::get('/user/{name}', [UserController::class, 'show']);
前述と同様、ルートモデル結合をしない場合はController内でいちいち取得しないといけない
- UserController
<?php
namespace App\Http\Controllers;
use App\Models\User;
class UserController extends Controller
{
public function show(string $name)
{
$user = User::where('name', $name)->first();
if (!$user) {
abort(404);
}
return $user->email;
}
}
これをカスタマイズしてあげる
ルートパラメータ定義でカラムを指定
対象のルーティングだけで使用したいだけの場合はルート上で設定すればOK
- routes/web.php
use App\Http\Controllers\UserController;
// パラメータに{モデル名:カラム名} で指定する
Route::get('/user/{user:name}', [UserController::class, 'show']);
- UserController
<?php
namespace App\Http\Controllers;
use App\Models\User;
class UserController extends Controller
{
public function show(User $user)
{
return $user->email;
}
}
従来通り自動注入してくれる
そのモデルでは永続的にID以外のカラムをキーにしたい場合
対象のモデルに紐づくルーティングは全てカラムをID以外に変更したい場合、
EloquentのgetRouteKeyName
をオーバーライドする
- app/Models/User.php
// ⭐️ 下記関数を追記
/**
* モデルのルートキーの取得
*
* @return string
*/
public function getRouteKeyName()
{
return 'name';
}
LaravelのルーティングにはパラメータにIDを渡すとそれに紐づくモデルを自動で取得して渡してくれる便利機能がある
今回はそれのカスタマイズのメモ