リクエスト処理の前後に処理を挿入できるミドルウェア
ミドルウェアは、一言でいうと、リクエスト処理の前後に処理を挿入できる仕組み、となります。そのミドルウェアの概論については、拙記事「Laravelにおけるミドルウェアを理解しよう」で解説を行っています。LaravelでもSlimでも、ミドルウェアの概念は同じなので、一読いただければ幸いです。ここでは、概論よりも、実際のコードを使ってSlimのミドルウェアを体感していただこうと思います。
Slimのミドルウェアは1つのクラス
ミドルウェアは上述のように、リクエスト処理の前後に処理を挿入できる仕組みです。その挿入したい処理を、Slimでは1つのクラスとして記述します。それは、リスト1のようなコードとなります。
<?php namespace CodeZineSlim\FirstSlim\middlewares; use Psr\Http\Server\MiddlewareInterface; use Psr\Http\Server\RequestHandlerInterface; use Psr\Http\Message\ServerRequestInterface as Request; use Psr\Http\Message\ResponseInterface as Response; class BeforeHelloMiddleware implements MiddlewareInterface // (1) { public function process(Request $request, RequestHandlerInterface $handler): Response // (2) { print("BeforeHelloMiddlewareからHello!<br>"); // (3) $response = $handler->handle($request); // (4) return $response; // (5) } }
ミドルウェアの処理を記述したクラス(ミドルウェアクラス)のクラス名、格納先フォルダは特に規定が無いので、自由に決めることができます。とはいえ、ミドルウェアクラスであることがすぐに分かるためにも、リスト1のように、「○○Middleware」といったクラス名にし、/classes/middlewaresフォルダのように1つのフォルダ内にまとめて格納した方が、管理が楽になります。
一方、クラスの作り方には決まりがあります。それは、リスト1の(1)のように、\Psr\Http\Server\MiddlewareInterfaceを実装(implements)する必要があるということです。このインターフェースには、以下の構文のメソッドが1つ定義されています。
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
このprocess()メソッド内にリクエスト処理の前後に挿入したい処理を記述します。リスト1では(2)が該当します。
メソッド内の記述は、リスト1では3行記述されています。(3)は画面に文字列を表示する処理です。(4)はコードの通り、process()メソッドの第2引数であるRequestHandlerInterfaceのメソッドhandle()を実行し、そのhandle()メソッドの戻り値として返ってくるレスポンスオブジェクトを受け取ります。そして、それを(5)でprocess()メソッドの戻り値としてリターンしています。この(4)の処理については、のちに詳しく解説します。
ミドルウェアの登録はルーティング登録に続けてadd()メソッドを記述する
ミドルウェアクラスが作成できたところで、このクラスをリクエスト処理に挿入していきましょう。まず、リクエスト処理の本体となるコントローラクラスとして、リスト2のChap8Controller.phpファイルを作成します。
<?php namespace CodeZineSlim\FirstSlim\controllers; use Psr\Http\Message\ServerRequestInterface as Request; use Psr\Http\Message\ResponseInterface as Response; class Chap8Controller { public function mainRequest(Request $request, Response $response, array $args): Response { print("ここはメインのリクエスト処理<br>"); return $response; } }
ミドルウェアクラスの動きを理解しやすいように、リクエスト処理であるmainRequest()メソッドには、画面に「ここはメインのリクエスト処理」と表示するシンプルな処理しか含まれていません。
次に、このリクエスト処理をルーティング登録します。実は、ミドルウェアを利用する場合、このルーティング登録と同時に登録するようになっています。それはリスト3のコードです。
<?php use CodeZineSlim\FirstSlim\controllers\Chap8Controller; use CodeZineSlim\FirstSlim\middlewares\BeforeHelloMiddleware; $app->any("/no8/withBeforeMiddleware", Chap8Controller::class.":mainRequest")->add(new BeforeHelloMiddleware()); // (1)
リスト3の(1)では、ルーティング登録メソッドany()を使って、ルーティングパターン/no8/withBeforeMiddlewareでリスト2のmainRequest()メソッドを登録しています。その続きとしてadd()メソッドを実行し、引数としてリスト1で用意したミドルウェアクラスをnewして渡しています。これがミドルウェアの登録コードです。ここでは、ルーティング登録メソッドとしてany()を使っていますが、他のルーティング登録メソッドでも同様です。any()を例に構文としてまとめると以下の通りになります。
$app->any(…)->add(new ミドルウェアクラス);
最後に、routes8.phpをindex.phpで読み込むコードを記述し、動作確認を行っておきましょう。リスト4の太字の1行を追記してください。
<?php 〜省略〜 require_once("../routes8.php"); $app->run();
追記が終了したら、以下のURLにアクセスしてください。
- http://localhost/firstslim/src/public/no8/withBeforeMiddleware
図1の画面が表示されます。
図1を見ると、2行目に表示された内容は、リクエスト処理であるmainRequest()メソッドの実行結果です。一方、1行目はmainRequest()メソッドには含まれておらず、これこそがまさにミドルウェアクラスであるリスト1の(3)の処理であり、リクエスト処理の前に処理が挿入されたことが理解できます。
このように、各リクエスト処理の前後に定型処理を挿入したい時、その処理をミドルウェアクラスとして作成すると、ルーティング登録時に登録するだけで済みます。全てのコントローラクラスメソッド内に定型処理を記述する必要が無くなります。