Laravelを初めて使って、
まず便利だなーと思ったのがRoute::resource()
これを基本使うようにすれば、変なメソッドを生やす意識も減る。
また、既存のControllerに似てるけど
チョット外れたことをしようとした時に、
「いやいや、新しいController切ろう」と気づかせてくれる。
ただ1つメソッドが煩雑化することを気づかせてくれるというのは
すごいな----と思いました
なので今回は感動を与えてくれるRoute::resource()
の中身を追ってみる
何が出来るの
役割はルーティング
リソースに対する様々なアクションを処理する、複数のルートがこの1定義により生成されます。
と本家( https://readouble.com/laravel/5.3/ja/controllers.html#resource-controllers )にあるように
Routeの記述を楽にさせてくれる
どこにあるの
実体を探す
config/app.php
をみると
aliasに記述がされている
'aliases' => [
.....
'Route' => Illuminate\Support\Facades\Route::class,
.....
],
Facadeにaliasが張ってあり
中身を見ると、実体は Illuminate/Routing/Router.php
にあるよーとなってる
https://github.com/laravel/framework/blob/5.3/src/Illuminate/Support/Facades/Route.php
protected static function getFacadeAccessor()
{
return 'router';
}
resource()の中身を見る
ずっとIlluminate/Routing/Router.phpを読んでいくと
resourceの記述を発見
引数は、Resourceを設定する時に与える値の
ルーティングする名前とそれに紐づくコントローラー名
/**
* Route a resource to a controller.
*
* @param string $name
* @param string $controller
* @param array $options
* @return void
*/
public function resource($name, $controller, array $options = [])
{
if ($this->container && $this->container->bound('Illuminate\Routing\ResourceRegistrar')) {
$registrar = $this->container->make('Illuminate\Routing\ResourceRegistrar');
} else {
$registrar = new ResourceRegistrar($this);
}
$registrar->register($name, $controller, $options);
}
中ではIlluminate\Routing\ResourceRegistrar
をnewしている
ResourceRegistrar
読んでみると
Resourceのコアというか、処理自体が分かるのは
このResourceRegistrarぽい
https://github.com/laravel/framework/blob/5.3/src/Illuminate/Routing/ResourceRegistrar.php
まずresource()
で呼ばれたregister()
を見てみる
/**
* Route a resource to a controller.
*
* @param string $name
* @param string $controller
* @param array $options
* @return void
*/
public function register($name, $controller, array $options = [])
{
if (isset($options['parameters']) && ! isset($this->parameters)) {
$this->parameters = $options['parameters'];
}
// If the resource name contains a slash, we will assume the developer wishes to
// register these resource routes with a prefix so we will set that up out of
// the box so they don't have to mess with it. Otherwise, we will continue.
if (Str::contains($name, '/')) {
$this->prefixedResource($name, $controller, $options);
return;
}
// We need to extract the base resource from the resource name. Nested resources
// are supported in the framework, but we need to know what name to use for a
// place-holder on the route parameters, which should be the base resources.
$base = $this->getResourceWildcard(last(explode('.', $name)));
$defaults = $this->resourceDefaults;
foreach ($this->getResourceMethods($defaults, $options) as $m) {
$this->{'addResource'.ucfirst($m)}($name, $base, $controller, $options);
}
}
めっちゃコメント書いてある....
部分的に読み解いていく
ルーティング名に/
が入っていた時の処理
ここの部分
if (Str::contains($name, '/')) {
$this->prefixedResource($name, $controller, $options);
return;
}
同じclass内にあるprefixedResource()
を読んで要約すると
ルーティング名に/
が入っていたら
スラッシュの前の部分をRoute:group()
で定義するよ!
(ルーティングのグループ化: https://readouble.com/laravel/5.3/ja/routing.html#route-groups)
という処理のようだ
groupを設定したあとは、再帰処理する形でまたresource()
引数を渡していく
各リソースをrouteに登録していく
この部分
$base = $this->getResourceWildcard(last(explode('.', $name)));
$defaults = $this->resourceDefaults;
foreach ($this->getResourceMethods($defaults, $options) as $m) {
$this->{'addResource'.ucfirst($m)}($name, $base, $controller, $options);
}
explode('.', $name)
の部分の意味がわからない....
$this->resourceDefaults
には
resourceで登録されるControllerのメソッド集が入ってる(ex:index,show,create...)
そのメソッドごとにrouteの登録処理が行われる
例としてIndexのルートをみてみる
/**
* Add the index method for a resourceful route.
*
* @param string $name
* @param string $base
* @param string $controller
* @param array $options
* @return \Illuminate\Routing\Route
*/
protected function addResourceIndex($name, $base, $controller, $options)
{
$uri = $this->getResourceUri($name);
$action = $this->getResourceAction($name, $controller, 'index', $options);
return $this->router->get($uri, $action);
}
ルーティングしたい名前を定義して
resourceのルールに従った挙動を習得する
routerにURIと挙動を渡したら登録完了!
これを全メソッド分(それぞれで処理が少し異なるが基本一緒)を行い
ルーティングが登録されていく
余談
読んでいる中で見つけたresources()
resourceも配列で渡せば複数resourceが登録できるみたい!
知らなかった!コレは使いたい!
/**
* Register an array of resource controllers.
*
* @param array $resources
* @return void
*/
public function resources(array $resources)
{
foreach ($resources as $name => $controller) {
$this->resource($name, $controller);
}
}