前後の区別とhandle()メソッドの働き
前節で紹介したサンプルでは、リクエスト処理の前に処理が挿入されました。ここまで再三述べているように、ミドルウェアはリクエスト処理の「前後」に処理が挿入できます。「後」の場合について見ていきましょう。
前後の区別はhandle()メソッドの記述位置で決まる
リクエスト処理の後に処理を挿入したい場合のミドルウェアクラスのコードは、リスト5の通りになります。
<?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 AfterHelloMiddleware implements MiddlewareInterface { public function process(Request $request, RequestHandlerInterface $handler): Response { $response = $handler->handle($request); // (1) print("AfterHelloMiddlewareからHello!<br>"); // (2) return $response; } }
リスト1との違いは、クラス名と(1)と(2)のコードだけです。その(1)と(2)も表示文字列は少し違っているぐらいで、大きな違いはその順序です。リスト1のBeforeHelloMiddlewareでは、handle()の前にprint()を実行しています。一方、リスト5では、handle()の後にprint()を実行しています。
実は、このhandle()メソッドとはリクエスト処理本体を指し、リスト1のように、handle()の前に挿入したい処理を記述することで、リクエスト処理の前に処理が挿入され、同様に、リスト5のように、handle()の後に記述することで、リクエスト処理の後に処理が挿入される仕組みとなっているのです。
では、このミドルウェアを利用するルーティング登録を行い、動作確認を行っておきましょう。リクエスト処理としては、リスト2のmainRequest()を再利用します。routes8.phpにリスト6の太字の行を追記してください。
〜省略〜 use CodeZineSlim\FirstSlim\middlewares\AfterHelloMiddleware; $app->any("/no8/withBeforeMiddleware", Chap8Controller::class.":mainRequest")->add(new BeforeHelloMiddleware()); $app->any("/no8/withAfterMiddleware", Chap8Controller::class.":mainRequest")->add(new AfterHelloMiddleware());
追記ができたら動作確認を行っておきましょう。以下のURLにアクセスしてください。
- http://localhost/firstslim/src/public/no8/withAfterMiddleware
図2の画面が表示されます。
![図2:リクエスト処理の後に処理が挿入された実行画面](http://cz-cdn.shoeisha.jp/static/images/article/12263/12263_002.png)
図2から分かるように、リクエスト処理の後にミドルウェアの処理が無事、挿入されています。
handle()の記述位置で自由に決められる挿入位置
前項では、handle()メソッドと挿入する処理の位置関係で、リクエスト処理の前後どちらに挿入するかが決まることが分かりました。勘のいい人はすでに気づいているかもしれませんが、実はSlimのミドルウェアは、handle()の記述位置でリクエスト処理の位置を決められるため、リクエスト処理の前後どちらかではなく、そのどちらにも自由に挿入できるようになっています。
例えば、リスト7のようなコードです。
<?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 InnerMiddleware implements MiddlewareInterface { public function process(Request $request, RequestHandlerInterface $handler): Response { print("InnerMiddlewareのhandle()の前の処理<br>"); // (1) $response = $handler->handle($request); // (2) print("InnerMiddlewareのhandle()の後の処理<br>"); // (3) return $response; } }
リスト7では、(2)のhandle()メソッドの呼び出しの前に(1)の文字列表示、後に(3)の文字列表示と、リクエスト処理の前後両方に処理を記述しています。実際に、リクエスト処理の前後に処理が挿入されるか動作確認をしておきましょう。routes8.phpにリスト8の太字の行を追記してください。
〜省略〜 use CodeZineSlim\FirstSlim\middlewares\InnerMiddleware; 〜省略〜 $app->any("/no8/withBeforeMiddleware", Chap8Controller::class.":mainRequest")->add(new AfterHelloMiddleware()); $app->any("/no8/withInnerMiddleware", Chap8Controller::class.":mainRequest")->add(new InnerMiddleware());
追記ができたら動作確認を行っておきましょう。以下のURLにアクセスしてください。
- http://localhost/firstslim/src/public/no8/withInnerMiddleware
図3の画面が表示されます。
![図3:リクエスト処理の前後両方に処理が挿入された実行画面](http://cz-cdn.shoeisha.jp/static/images/article/12263/12263_003.png)
このように、Slimのミドルウェアは、リクエスト処理の前後両方に処理を挿入できる仕組みとなっているので、イメージ的には図4の通り、リクエスト処理を中心にした同心円のような仕組みとなっています。
![図4:Slimのミドルウェアは同心円のイメージ](http://cz-cdn.shoeisha.jp/static/images/article/12263/12263_004.png)
複数重ねられるミドルウェア
さらに、このミドルウェアは複数重ねることができます。例えば、リスト9のようなミドルウェアを考えます。なお、リスト9の内容は、リスト7のInnerMiddleware.phpとほぼ同じです。違いは、太字の部分だけです。
<?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 OuterMiddleware implements MiddlewareInterface { public function process(Request $request, RequestHandlerInterface $handler): Response { print("OuterMiddlewareのhandle()の前の処理<br>"); $response = $handler->handle($request); print("OuterMiddlewareのhandle()の後の処理<br>"); return $response; } }
このOuterMiddlewareとリスト7のInnerMiddlewareの両方をリクエスト処理に付与してみましょう。ルーティング登録コードは次の通りになります。routes8.phpにリスト10の太字の行を追記してください。
〜省略〜 use CodeZineSlim\FirstSlim\middlewares\OuterMiddleware; 〜省略〜 $app->any("/no8/withInnerMiddleware", Chap8Controller::class.":mainRequest")->add(new InnerMiddleware()); $app->any("/no8/withDoubleMiddleware", Chap8Controller::class.":mainRequest")->add(new InnerMiddleware())->add(new OuterMiddleware()); // (1)
追記ができたら動作確認を行っておきましょう。以下のURLにアクセスしてください。
- http://localhost/firstslim/src/public/no8/withDoubleMiddleware
図5の画面が表示されます。
![図5:ミドルウェアを2個付与した実行画面](http://cz-cdn.shoeisha.jp/static/images/article/12263/12263_005.png)
ミドルウェアを複数付与するには、リスト10の(1)のように、add()メソッドを続けて複数実行するだけです。その際、注意しておく必要があるのは、その追加の順番です。ここでの処理の流れを図にすると、図6の通りになります。
![図6:複数ミドルウェアも同心円が重なるイメージ](http://cz-cdn.shoeisha.jp/static/images/article/12263/12263_006.png)
図6でSlimのミドルウェアは同心円のイメージであると伝えましたが、複数ミドルウェアを付与した場合も同心円が重なるイメージを持ってください。その際、リクエスト処理を中心に、add()した順番で円が重なります。そのため、以下の順番で処理が行われます。
最後にadd()したOuterのhandle()より前の処理
最後にadd()したOuterのhandle()より後の処理
↓
最初にadd()したInnerのhandle()より前の処理
↓
リクエスト処理
↓
最初にadd()したInnerのhandle()より後の処理
↓
図6の実行結果もそのことを物語っています。