Laravel SubstituteBindingsミドルウェアについて調べてみた。
SubstituteBindingsミドルウェアは、Kernel.phpでwebとapiグループのミドルウェアとして指定されている。
Substitute = 代替(代わりに使う)。Binding = 紐づける
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
// \Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
];
SubstituteBindingsは
ルートモデルバインディング用の機能。
https://laravel.com/docs/6.x/routing#route-model-binding
routeにfunctionを入れてモデルを引数にすると、pathの値を元に自動でfindOrFailして引数として渡してくれる。
{user} pathでUserが取得できない場合は404エラーが返される。
Route::get('/user/{user}', function (\App\Models\User $user) {
return $user;
});
curl http://127.0.0.1:8000/api/user/1
{"id":1,"name":"aaa","email":"hoge@co.jp","email_verified_at":null,"api_token":"WzLJB6Djg7HS9vDp8Ss8RqcIKYPYvs2pJBUl8CYMwsnVCHXK3FeIEdLBFq8Q","created_at":"2020-12-04T14:46:11.000000Z","updated_at":"2020-12-04T14:46:11.000000Z"}%
SubstituteBindingsをミドルウェアから外した状態で再度アクセスするとLaravelコンテナによってUserモデルがインスタンス化された状態で引数に追加される。($userはnullではないが$user->idとかはnullになる)
SubstituteBindings読む
SubstituteBindingsのコンストラクタでRegisterを引数でもらっている。
public function __construct(Registrar $router)
{
$this->router = $router;
}
handle関数では、bindingを行っている。
binding処理はコンストラクタで受け取ったRegisterクラスで行っている。
public function handle($request, Closure $next)
{
$this->router->substituteBindings($route = $request->route());
$this->router->substituteImplicitBindings($route);
return $next($request);
}
Register
Illuminate\Foundation\Application.phpのregisterCoreContainerAliases関数でRegisterのaliasが設定されている。
Registerクラスは\Illuminate\Routing\Router::classの型を使ってDIされる。
'router' => [\Illuminate\Routing\Router::class, \Illuminate\Contracts\Routing\Registrar::class, \Illuminate\Contracts\Routing\BindingRegistrar::class],
substituteBindings
substituteBindingsは明示的なpathとModelの結合の処理に使用される。
substituteBindingsの関数を見ると、routeのparameterを元にパラメータを設定している。
Routerにはpath名と型を紐づけるbinderを管理するbidnersプロパティがあり、そこに該当するbinderが設定されているとperformBinding関数を使ってパラメータを取得し、setParameterでセットしている。
binderはbind関数で追加されるが、これはmodel関数で使用されている。
model関数は Route::model('user', \App\Models\User::class);
のように使われる。
public function substituteBindings($route)
{
foreach ($route->parameters() as $key => $value) {
if (isset($this->binders[$key])) {
$route->setParameter($key, $this->performBinding($key, $value, $route));
}
}
return $route;
}
↓routeのパラメータはpathを分解した時のpath名をkeyに値をvalueにした配列になっている。
Route::get('hoge/{hogeId}', [\App\Http\Controllers\HogeController::class, 'hoge']);
↓route->parameters()の値
{"hogeId":"11"}
substituteImplicitBindings
substituteImplicitBindingsは暗黙的なpathとモデルの結合に使用される。
Implicit = 暗黙的