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、全体的に思想がシンプルだ。素晴らしい。