こんな感じでしょうか。
テストしてはいませんが、恐らく動くと思います。
php
1namespace app\mw;
2namespace app\helper;
3
4use Psr\Http\Message\ServerRequestInterface as Request;
5use Psr\Http\Message\ResponseInterface as Response;
6use Slim\Http\Body; // 追加
7
8class HogeMiddleware {
9 // コードの動作とは無関係だが、アクセス修飾子 public を明記
10 // 見間違えなどがあるかもしれないので、どちらかといえば書いたほうが良い
11 // ただし、(publicの場合は)省略しても動作に影響はない
12 public function __invoke(Request $request, Response $response, $next) {
13 if (helper::isCSV($request->getBody()->getContents())) {
14 $csv = helper::toJSON($request->getBody()->getContents());
15
16 /*
17 * リクエストを書き換え
18 *
19 * @see https://github.com/slimphp/Slim/blob/3.x/Slim/Handlers/NotFound.php#L54-L59
20 * @see https://github.com/slimphp/Slim/blob/3.x/Slim/Http/RequestBody.php#L21
21 */
22 $body = new Body(fopen('php://temp', 'w+'));
23 $body->write($csv);
24 $request = $request->withBody($body);
25 }
26
27 $response = $next($request, $response);
28
29 if (helper::isJSON($response->getBody()->getContents())) {
30 $json = helper::toCSV($response->getBody()->getContents());
31
32 /*
33 * レスポンスを書き換え
34 *
35 * @see https://github.com/slimphp/Slim/blob/3.x/Slim/Handlers/NotFound.php#L54-L59
36 * @see https://github.com/slimphp/Slim/blob/3.x/Slim/Http/Response.php#L127
37 */
38 $body = new Body(fopen('php://temp', 'r+'));
39 $body->write($json);
40 $response = $response->withBody($body);
41 }
42
43 return $response;
44 }
45}
リクエストやレスポンスのbodyを取得するためにはgetBody
メソッドを使いますが、書き換える場合はwithBody
メソッドを使います。
このメソッドの引数には、文字列ではなくStreamInterfaceのインスタンスを指定しなくてはなりません。
SlimではこれをSlim\Http\Body
クラスで提供しているため、このクラスを引数に指定すればbodyを書き換えられます。
が、このSlim\Http\Body
クラスも引数に文字列ではなくPHPのストリームを指定し、肝心のbodyはwrite
メソッドで書き込む必要があるため、少々ややこしい事になっています。
SlimのSlim/Handlers/NotFound.phpでは、レスポンスの書き換えをおこなうコードを以下のように実装しています。
変数$output
に、レスポンスのbodyを上書きする文字列が格納されています。
php
1$body = new Body(fopen('php://temp', 'r+'));
2$body->write($output);
3return $response->withStatus(404)
4 ->withHeader('Content-Type', $contentType)
5 ->withBody($body);
このコードを簡単に説明すると、fopen('php://temp', 'r+')
でストリームを生成してSlim\Http\Body
クラスの引数に渡した後、
write
メソッドで変数$output
の内容をbodyとして書き込んでいます。
レスポンスのbodyの書き換えはこれをパクりました。
php
1$body = new Body(fopen('php://temp', 'r+'));
2$body->write($json);
3$response = $response->withBody($body);
リクエストの場合も、withBody
メソッドを利用する点は変わりません。
多分、レスポンスの場合と同じコードで動作するハズです。
…が、この回答では一応のため、Slimがリクエストのbodyを生成している内部処理と同じコードにしました。
レスポンスのコードと異なるのは、fopen関数の第二引数の値です。'r+'
から'w+'
に変更しています。
php
1$body = new Body(fopen('php://temp', 'w+'));
2$body->write($csv);
3$request = $request->withBody($body);
(ストリームとして使うなら、r+
もw+
も変わらないと思いますが、ストリーム関係の動作にはあまり詳しくないので、確証を持って「r+
もw+
も同じだ」と言い切ることが出来ません…)
なお、肝心なことですが、Slimが採用しているPSR-7のServerRequestInterface
やResponseInterface
は不変オブジェクトです。
StreamInterface
(getBody
メソッドで取得できるオブジェクト)を除き、メソッドを実行しただけではオブジェクトそのものの状態(オブジェクトの値)が変化せず、そのメソッドの返り値である「状態が変化したオブジェクト」を利用しなくてはなりません。
このため、withBody
などのメソッドが返す値のオブジェクトを次に渡す必要があります。
このコードでは以下のように変数に再代入して次に渡しています。
誤って再代入を忘れると、bodyが上書きされません。
php
1// 正しい記述
2$response = $response->withBody($body);
3
4// 間違えてこうするとbodyが変わらない
5$response->withBody($body);
詳細は以下をどうぞ。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/06/03 14:02