【Laravel】モデル結合ルートを使ってコントローラの記述を簡略化

著者:杉浦

【Laravel】モデル結合ルートを使ってコントローラの記述を簡略化

 サーバサイドプログラムのリクエスト処理部は、ある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

  • この記事いいね! (1)

著者について

杉浦 administrator