サーバサイドプログラムのリクエスト処理部は、あるURLに対するリクエストを受け取り、リクエストに応じたデータを探して、もしなければ404を返し、と処理を行う必要があります。これを素で書くと例えば次の様になります。
// ルーティングファイル
Route::post('user/{id}', 'UserController@update');
// コントローラファイル
class UserController {
public function update(){
$id = request()->id ?: abort(404);
$user = User::findOrFail($id);
// $userに関連するレコードを更新する処理
return $user;
}
}
Laravelのモデル結合ルートはこの処理を簡略化します。使い方は次の通りの名前と型の指定です。
// ルーティングファイル
Route::post('user/{user}', 'UserController@update');
// コントローラファイル
class UserController {
public function update(User $user){
// $userに関連するレコードを更新する処理
return $user;
}
}
この様にすると、例えばuser/1365とpostを投げた時、User::findOrFail(1365);と同等の動作が実行されupdate関数にはUser::findOrFail(1365);の返り値のUserインスタンスが渡されます。毎度同じ手順で処理を行う必要がなくなり、楽になります。
ルーティング 5.8 Laravel
上記まではモデル結合ルートの基本的な使い方であり、Laravelのデフォルトです。これは主キーで見つけるfindと同等の動作を仕組みを用いていますが、実際には主キーでない何らかのカラムでwhereをかけてモデルを取得したいパターンがあります。そのような時には次の様にモデル内でルートのwhereに使うカラムの名前を指定します。
// vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php
/**
* @inheritDoc
*/
public function getRouteKeyName()
{
return 'モデル結合ルートで使いたいカラム名';
}
このgetRouteKeyName()は次の様にルーティング用のクエリ構築メソッドresolveRouteBindingty中で使われています。このメソッドで返されるModelインスタンスがモデル結合ルートによって渡されるModelのインスタンスになります。
// vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php
/**
* Retrieve the model for a bound value.
*
* @param mixed $value
* @return \Illuminate\Database\Eloquent\Model|null
*/
public function resolveRouteBinding($value)
{
return $this->where($this->getRouteKeyName(), $value)->first();
}
getRouteKeyNameを書き換えることでwhere句の指定するカラム名を書き換えました。もっと深く掘り進めてresolveRouteBindingを書き換えることによって更に大きくモデル結合ルートを改造できます。例えば次です。
public function resolveRouteBinding($value)
{
return $this->where($this->getRouteKeyName(), $value)
->where('status', '<>', config('const.status.freeze'))
->first();
}
凍結状態のレコードが選ばれた時404を返す様にします。ちょっとしたグローバルスコープのパターンです。
65