はじめに
この記事について
Laravel Advent Calendar 2017 6日目の記事です。
5日目は4日目に引き続き @mpyw さんの記事で、リレーションを含んだルールを持つアクセスポリシーとResourcefulルーティングを組み合わせたときのURLパターンの考察と実装例でした。最終的なPolicyクラスのサンプルコードは何が書いてあるかひと目でわかるようになっていますね!
@mpyw さんは直接の面識はないのですが、いつも読みやすい記事を投稿してくださっていて、最近ですと↓の記事に助けられました。(PHPではありませんが)
たぶんこれが一番分かりやすいと思います React + Redux のフロー図解
また、この記事は @ytake さんの ytake/lumen-adr-example のコードを読んでADRパターンの勉強をしていたところ出てきた疑問から生まれました。
環境
- PHP 7.1.8
- Laravel 5.5.14
Controllerクラスは必須ではない
コントローラのドキュメント にこのようなTipsがあります。
Tip!! コントローラはベースクラスの拡張を要求してはいません。しかし、middleware、validate、dispatchのような便利な機能へアクセスできなくなります。
初学者は読み飛ばしてしまうでしょうし、このTipsは5.3のドキュメントから追加されたみたいですので、5.2以前から始めた方は見たことがないかもしれません。
これは何を意味しているのでしょうか?
試してみる
簡単なControllerを作ってみましょう。(プロジェクト初期化直後を想定)
<?php
namespace App\Http\Controllers;
class WelcomeController extends Controller
{
public function index()
{
return view('welcome');
}
}
<?php
Route::get('/', 'WelcomeController@index');
いつものWelcome画面が出てきますね!
次にControllerクラスの継承をやめてみましょう。
<?php
namespace App\Http\Controllers;
class WelcomeController
{
public function index()
{
return view('welcome');
}
}
...これも問題なくWelcome画面が出ます!
ソースを読んでみる
Illuminate\Routing\Controller (as BaseController)
フレームワーク内にあるコントローラの基底クラスです。全て見てもそんなに長くないので見ていきましょう。1
<?php
namespace Illuminate\Routing;
use BadMethodCallException;
abstract class Controller
{
/**
* コントローラに登録されたミドルウェア
*/
protected $middleware = [];
/**
* コントローラにミドルウェアを登録
*/
public function middleware($middleware, array $options = [])
{
foreach ((array) $middleware as $m) {
$this->middleware[] = [
'middleware' => $m,
'options' => &$options,
];
}
return new ControllerMiddlewareOptions($options);
}
/**
* コントローラにされたミドルウェアを取得
*/
public function getMiddleware()
{
return $this->middleware;
}
/**
* コントローラのアクションを実行(渡された関数名の動的コール)
*/
public function callAction($method, $parameters)
{
return call_user_func_array([$this, $method], $parameters);
}
/**
* 未定義の関数が呼ばれたときのマジックメソッド
*/
public function __call($method, $parameters)
{
throw new BadMethodCallException("Method [{$method}] does not exist on [".get_class($this).'].');
}
}
前半は $middleware
配列への登録と取得です。ここで指すミドルウェアはコントローラに紐づくもので、これが無くてもグローバルミドルウェアやルート定義時のミドルウェアは適用可能です。
callAction
はルート定義で 'Controller@action'
の形の文字列で渡されるアクションの呼び出しで使われますが、先ほどの実験でみたようにように無くても動きます。2
__call
はエラー文言を整形しているだけです。
App\Http\Controllers\Controller
プロジェクト初期化時にControllersディレクトリに作成されるクラスです。
<?php
namespace App\Http\Controllers;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
class Controller extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
}
Tipsにあるvalidateとdispatchはここで使われているtraitを指しているようですね。
長くなるので割愛しますが、3つのtraitのうち AuthorizeRequests
の authorizeResource
メソッドのみ $this->middleware
を呼び出しているので、BaseController
を継承せずにこの機能を使うとエラーになります。
他の2つのtraitは BaseController
に依存しておらず、それぞれ独立して使用できます。
まとめと考察
Tipsにある middleware、validate、dispatchのような便利な機能
とは、Controllerクラスに実装されたものとtraitとして実装されたものをひとまとめに指しているということがわかりました。
特に、 middleware
と authorizeResource
のメソッドを使わない場合はプレーンなクラスとしてコントローラを定義可能です。
これは、特定のフレームワークへの依存を嫌うようなプロジェクトにおいてはメリットになります。
そうでなくてLaravelが大好きという人も、詳しい実装を知ることでウェブ職人3に一歩近づくでしょう。
さいごに
小さな疑問でもフレームワークのソースを追ってみることで、そのフレームワークの仕様はもちろん、言語そのものに対する理解が深まると思います。
そのためにも、 PhpStorm などのリッチなIDEを使うことを強くおすすめします。
ソースが読みやすいというのも、Laravelのいいところの一つだと思っています。4
7日目は @yoshikyoto さんのLaravel触ってみた系の記事の予定です。よろしくお願いします!