LoginSignup
15
10

More than 5 years have passed since last update.

【Laravel】Route Model Binding のカスタムロジックをクラスに切り出す

Last updated at Posted at 2018-08-30

前提

Laravel ではルーティングパラメータから Model を bind させることができる。

RouteServiceProvider
public function boot()
{
    parent::boot();

    // ルーティングで {user} を指定すると下記コールバックの $userName に渡され
    // その戻り値を Controller の引数に渡すことができる
    Route::bind('user', function ($userName) {
        return resolve(MyApp\Domain\Repositories\UserRepository::class)->findByName($userName) ?? abort(404);
    });
}

詳しくは 公式ドキュメント(Routing # Explicit Binding) の "Customizing The Resolution Logic" を参照。

しかし、 bind のためのロジックは ServiceProvier の関心事ではなく、そのコードがここに出てくるのはあまりよろしくない。

Route::bind() の中身を見てみると

実は Route::bind() の第2引数には callback だけでなく文字列を渡すことができる。

過程は省略するがRoute::bind()の第2引数に文字列を渡した場合、以下のメソッドの引数 $binding となる。

Illuminate\Routing\RouteBinding
    protected static function createClassBinding($container, $binding)
    {
        return function ($value, $route) use ($container, $binding) {
            // If the binding has an @ sign, we will assume it's being used to delimit
            // the class name from the bind method name. This allows for bindings
            // to run multiple bind methods in a single class for convenience.
            list($class, $method) = Str::parseCallback($binding, 'bind');

            $callable = [$container->make($class), $method];

            return call_user_func($callable, $value, $route);
        };
    }

bind() というメソッドを持ったクラス名、あるいはソース中のコメントにある通りクラス名@メソッド名を指定すれば、bind のためのロジックを指定することができる。

bind のためのロジックを別のクラスに切り出す

上記より、次のようなクラスを作成すれば、

MyApp\Application\Routing\Binders\User
namespace MyApp\Application\Routing\Binders;

use MyApp\Domain\Repositories\UserRepository;

class User
{
    protected $repository;

    public function __construct(UserRepository $repository)
    {
        $this->repository = $repository;
    }

    public function bind($userName)
    {
        return $this->repository->findByName($userName) ?? abort(404);
    }
}

RouteServiceProvider 側では次のようにして使うことができる。

RouteServiceProvider
public function boot()
{
    parent::boot();

    Route::bind('user', MyApp\Application\Routing\Binders\User::class);
}

これで、ServiceProvider の関心事の外である「bind のためのロジック」をカプセル化することができる。

15
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
10