https://www.slimframework.com/docs/v3/concepts/middleware.html
ネタ的には「最重要クラス」に重要なネタなので、腰を据えて。
とりあえず、こちらの画像が一番わかりやすいんだろうなぁ、って思う。
https://www.slimframework.com/docs/v3/images/middleware.png
今まで書いてきたのはapp、つまりは「一番真ん中」で。
その外側に「Middleware 1」をラッピングして、さらにその外側に「Middleware 2」をラッピングして……的に、玉ねぎのような状態にする感じ。
なので、実行順番としては
・Middleware 2の入り口
・Middleware 1の入り口
・app(本体)
・Middleware 1の出口
・Middleware 2の出口
って感じで動く。エンジニアなら理解しやすい入れ子構造なんじゃないかなぁ?
個人的には(=MagicWeaponでは)、この辺を「クラスの継承」関係で書いてたんだけど。
いや「クラスの継承で書けばいいじゃん」って思わなくもないんだけど(問題なく書けてたし)、ただまぁ「後で付け足す」って感じで考えると、このMiddlewareって考え方は「面白いなぁ」って思うざますの。
なんて感じで「大まかに概念を把握した」ところで、さっそく、実装方法。
基本的には
・Middleware本体のクラスの記述
・Middlewareを「適用させる」ための、routerへの登録
の2種類の手順が必要ぽ。
Middlewareはどうも実際には「クラスでも関数でもOK」ぽいんだけど、まぁとりあえずクラス。
その場合「実装は__invoke()に書いてね」って感じらしい。
これ、多分「Middlewareを入れる場所を用意する」&「その辺をauto_loaderで読み込めるようにする」的なことが必要なんだろうなぁ。
ただその辺の考察は厳密には「今回の考察の範疇外」なので、今回は「index.phpにべた書き」とかいう、乱雑な方法を使いますw
class ExampleMiddleware { public function __invoke($request, $response, $next) { $response->write('BEFORE:'); $response = $next($request, $response); $response->write(':AFTER'); return $response; } } $app = new \Slim\App; $app->add(new ExampleMiddleware() ); $app->get('/', function(Request $request, Response $response, array $args) { echo "hoge test\n"; }); $app->get('/aaa', function(Request $request, Response $response, array $args) { echo "hoge aaa\n"; });
BEFORE::AFTERhoge test
あら。………あぁそうか「echoで取ってきてる」から、最後に足されちゃうのか。
ちょいと書き換え。
class ExampleMiddleware { public function __invoke($request, $response, $next) { $response->write('BEFORE:'); $response = $next($request, $response); $response->write(':AFTER'); return $response; } } $app = new \Slim\App; $app->add(new ExampleMiddleware() ); $app->get('/', function(Request $request, Response $response, array $args) { return $response->write("hoge test\n"); }); $app->get('/aaa', function(Request $request, Response $response, array $args) { return $response->write("hoge aaaa\n"); });
BEFORE:hoge test
:AFTER
はい予想どおり。
軽く、入れ子も確認。
class ExampleMiddleware { public function __invoke($request, $response, $next) { $response->write('BEFORE:'); $response = $next($request, $response); $response->write(':AFTER'); return $response; } } class ExampleMiddleware2 { public function __invoke($request, $response, $next) { $response->write('BEFORE 2:'); $response = $next($request, $response); $response->write(':AFTER 2'); return $response; } } $app = new \Slim\App; $app->add(new ExampleMiddleware() ); $app->add(new ExampleMiddleware2() ); $app->get('/', function(Request $request, Response $response, array $args) { return $response->write("hoge test\n"); }); $app->get('/aaa', function(Request $request, Response $response, array $args) { return $response->write("hoge aaaa\n"); });
今度は/aaaにアクセス。
BEFORE 2:BEFORE:hoge aaaa
- AFTER
- AFTER 2
はい、きれいに入れ子。
ふと疑問。「一部広域」「一部局所」だとどうなるんだろ?
多分「広域が一番外側」だと思われるんだけど。
class ExampleMiddleware { public function __invoke($request, $response, $next) { $response->write('BEFORE:'); $response = $next($request, $response); $response->write(':AFTER'); return $response; } } class ExampleMiddleware2 { public function __invoke($request, $response, $next) { $response->write('BEFORE 2:'); $response = $next($request, $response); $response->write(':AFTER 2'); return $response; } } $app = new \Slim\App; $app->add(new ExampleMiddleware() ); $app->get('/', function(Request $request, Response $response, array $args) { return $response->write("hoge test\n"); })->add(new ExampleMiddleware2() ); $app->get('/aaa', function(Request $request, Response $response, array $args) { return $response->write("hoge aaaa\n"); });
まず/aaaは
BEFORE:hoge aaaa
:AFTER
なのでOK。
次、/にアクセス。
BEFORE:BEFORE 2:hoge test
- AFTER 2
- AFTER
うん予想通り。「全体→局所」で動くねぇ。
Group Middleware
あたりまでは大体
・想像できる動き
・「(無名含む)関数」は基本書くつもりなし
なので、放置。
Passing variables from middleware
「ミドルウェアから属性を渡す最も簡単な方法は、要求の属性を使用することです。(機械翻訳)」。
$request = $request->withAttribute('foo', 'bar');
で値を設定して
$foo = $request->getAttribute('foo');
で使う、と。
ふむぅ……MagicWeaponのbagとか、突っ込んどこうかしらん?
とりあえず、ほんのり記憶はしておきませう。
Finding available middleware
むぅ。色々あるのかまぁそうか。
https://github.com/oscarotero/psr7-middlewares
https://github.com/slimphp/Slim/wiki/Middleware-for-Slim-Framework-v3.x
https://github.com/lalop/awesome-psr7
さて。
ちょりと気になったのが
・middlewareの中でcontainer使える?
・「Middlewareの途中でエラー」の出し方
の2つ。
「middlewareの中でcontainer使える?」
は、ググってみたら「コンストラクタで渡したら?」ってな記述があった。
うんまぁAppに相当する本体も「コンストラクタ渡し」なので、それでよいかなぁ。よし解決w
疑問の本命「エラー」。
予想してみたコード。
class ExampleMiddleware { public function __invoke($request, $response, $next) { $response->write('Middleware Error!!'); /* $response->write('BEFORE:'); $response = $next($request, $response); $response->write(':AFTER'); */ return $response; } } class ExampleMiddleware2 { public function __invoke($request, $response, $next) { $response->write('BEFORE 2:'); $response = $next($request, $response); $response->write(':AFTER 2'); return $response; } } $app = new \Slim\App; $app->add(new ExampleMiddleware() ); $app->get('/', function(Request $request, Response $response, array $args) { return $response->write("hoge test\n"); })->add(new ExampleMiddleware2() ); $app->get('/aaa', function(Request $request, Response $response, array $args) { return $response->write("hoge aaaa\n"); });
Middleware Error!!
よし1mmの狂いもなく予想的中w
比較的あっさりと終わったな。
さすがはSlim、全体的に思想がシンプルだ。素晴らしい。