https://www.slimframework.com/docs/v3/objects/response.html
ここも結構な大物だろう、と予想。
How to get the Response object
いやまぁHow to言われても「呼ばれる関数(メソッド)の第二引数でゲトれる」くらいだしなぁ。
<?php use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ResponseInterface; $app = new \Slim\App; $app->get('/foo', function (ServerRequestInterface $request, ResponseInterface $response) { // Use the PSR 7 $response object return $response; }); $app->run();
ここは一応突っ込みが無くもなくて。
「文字列をreturnすると、現状の$responseにその文字列をbodyとして書き込むような処理を追記してくれる」んだよね。
http://d.hatena.ne.jp/gallu/20180613/p1
の
} elseif (is_string($newResponse)) { // if route callback returns a string, then append it to the response if ($response->getBody()->isWritable()) { $response->getBody()->write($newResponse); } }
あたりを参照。この辺が「そうそう簡単に変わる」ってのも考えにくいから「文字列returnしたらよしなにしてくれる」は、期待してよい動作、なんじゃないかなぁ? と思ってる。
The PSR 7 response object is injected into your Slim application middleware as the second argument of the middleware callable like this:
<?php use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ResponseInterface; $app = new \Slim\App; $app->add(function (ServerRequestInterface $request, ResponseInterface $response, callable $next) { // Use the PSR 7 $response object return $next($request, $response); }); // Define app routes... $app->run();
middleware周りはまた今度、まとめて徹底的に。なので、今回は一旦、パス。
The Response Status。割と大事ぽ。
$newResponse = $response->withStatus(302);
ここだけ把握しておけばよいんじゃないかなぁ………あぁ、一点気になること。
Response(以外もいくつかそうだけど)は、いわゆる「不変インスタンスである」とされているから、withStatusの実装って
vendor/slim/slim/Slim/Http/Response.php
public function withStatus($code, $reasonPhrase = '') { $code = $this->filterStatus($code); if (!is_string($reasonPhrase) && !method_exists($reasonPhrase, '__toString')) { throw new InvalidArgumentException('ReasonPhrase must be a string'); } $clone = clone $this; $clone->status = $code; if ($reasonPhrase === '' && isset(static::$messages[$code])) { $reasonPhrase = static::$messages[$code]; } if ($reasonPhrase === '') { throw new InvalidArgumentException('ReasonPhrase must be supplied for this code'); } $clone->reasonPhrase = $reasonPhrase; return $clone; }
なんだよね。ポイントは「$clone = clone $this;」して「return $clone;」ってあたり。
なので、この辺でさっきの「文字列をreturn」と組み合わせると、なんか不一致が出そうな気が少しする、ので、気を付けたほうがよいかも。
………うん、returnは「ちゃんとResponseインスタンス返す」ようにしたほうが安全かも。
ちと、確認してみませう。
public/index.php
$app = new \Slim\App; $app->get('/add_header', function(Request $request, Response $response, array $args) { $response = $response->withStatus(304); //return 'test'; return $response->getBody()->write('test'); });
$ telnet localhost 8080
Trying ::1...
telnet: connect to address ::1: Connection refused
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
GET /add_header HTTP/1.1
Host: example.comHTTP/1.1 200 OK
Host: example.com
Date: Mon, 18 Jun 2018 05:07:09 +0000
Connection: close
X-Powered-By: PHP/7.2.6
Content-Type: text/html; charset=UTF-8
Content-Length: 4testConnection closed by foreign host.
………あれ?
…………あ。
vendor/slim/slim/Slim/Http/Stream.php
public function write($string) { if (!$this->isWritable() || ($written = fwrite($this->stream, $string)) === false) { throw new RuntimeException('Could not write to stream'); } // reset size so that it will be recalculated on next call to getSize() $this->size = null; return $written; }
戻り値、stringか。
public/index.php
$app->get('/add_header', function(Request $request, Response $response, array $args) { $response = $response->withStatus(304); $response->getBody()->write('test'); //return 'test'; return $response; });
$ telnet localhost 8080
Trying ::1...
telnet: connect to address ::1: Connection refused
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
GET /add_header HTTP/1.1
Host: example.comHTTP/1.1 304 Not Modified
Host: example.com
Date: Mon, 18 Jun 2018 05:18:11 +0000
Connection: close
X-Powered-By: PHP/7.2.6Connection closed by foreign host.
よし意図通り。
ってことは
$app->get('/add_header', function(Request $request, Response $response, array $args) { $response = $response->withStatus(304); //$response->getBody()->write('test'); return 'test'; });
$ telnet localhost 8080
Trying ::1...
telnet: connect to address ::1: Connection refused
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
GET /add_header HTTP/1.1
Host: example.comHTTP/1.1 200 OK
Host: example.com
Date: Mon, 18 Jun 2018 05:19:06 +0000
Connection: close
X-Powered-By: PHP/7.2.6
Content-Type: text/html; charset=UTF-8
Content-Length: 4testConnection closed by foreign host.
だ〜よ〜ね〜〜。
これ、お作法的に
「最後は return $response; 」っての、徹底したほうが安全かも。ここだけは「Response、不変インスタンスじゃなければよかったのに」とか思う瞬間。まぁ、Slimがそう定義した訳でもない、から、ねぇ。
(実はお便利メソッドがresponseに生えてます。後述するwriteメソッド)。
The Response Headers。
$headers = $response->getHeaders();
とか、むしろ「デバッグの文脈」とか「解析の文脈」とか「テストの文脈」とか、で、便利そうな気がする。
便利ではあると思われるので、ほんのりと記憶しておきませう。
まぁあとは
$headerValueArray = $response->getHeader('Vary'); $headerValueString = $response->getHeaderLine('Vary'); if ($response->hasHeader('Vary')) {
とかあって
$newResponse = $oldResponse->withHeader('Content-type', 'application/json'); $newResponse = $oldResponse->withAddedHeader('Allow', 'PUT');
とかあるので、よき……なんだが、2点。
一つは「戻り値がインスタンスである」って点。「不変インスタンスだったよねぇ」ってのを忘れると色々と切ない気がするので、注意。
もう一つは「withHeaderとwithAddedHeaderの違い」。
どちらも vendor/slim/slim/Slim/Http/Message.php に実装があって、かつ
public function withAddedHeader($name, $value) { $clone = clone $this; $clone->headers->add($name, $value); return $clone; }
とかって実装なので、本当の実装は
vendor/slim/slim/Slim/Http/Headers.php
public function add($key, $value) { $oldValues = $this->get($key, []); $newValues = is_array($value) ? $value : [$value]; $this->set($key, array_merge($oldValues, array_values($newValues))); }
public function set($key, $value) { if (!is_array($value)) { $value = [$value]; } parent::set($this->normalizeKey($key), [ 'value' => $value, 'originalKey' => $key ]); }
この辺。
「複数行」って割と(業務で付与するheader的には)珍しいと思うので、「基本は withHeader() 」って覚えておいて、そんなに問題ないんじゃないかなぁ。
あぁもちろん
Remove Header
$newResponse = $oldResponse->withoutHeader('Allow');
もそろってるので、適宜よしなに。
これも不変インスタンス以下略。
The Response Body については。
$body = $response->getBody();
でとれる……のは、bodyインスタンス。デフォは vendor/slim/slim/Slim/Http/Body.php ここ。
なので
$response->getBody()->write();
この辺が、まぁよく使うところかなぁ、と。
上にも書いたけど「これの戻り値、string」なので、色々と注意、ではある。
Returning JSON。
………あら、ナウい感じ。
vendor/slim/slim/Slim/Http/Response.php
public function withJson($data, $status = null, $encodingOptions = 0) { $response = $this->withBody(new Body(fopen('php://temp', 'r+'))); $response->body->write($json = json_encode($data, $encodingOptions)); // Ensure that the json encoding passed successfully if ($json === false) { throw new \RuntimeException(json_last_error_msg(), json_last_error()); } $responseWithJson = $response->withHeader('Content-Type', 'application/json;charset=utf-8'); if (isset($status)) { return $responseWithJson->withStatus($status); } return $responseWithJson; }
便利〜。
………こっちは「return $response->withJson($data);」ってやってもいいのか………微妙に面倒w
まぁ「withついてるからcloneインスタンスが返ってくる」って覚えてもいいんだけどねぇ。
とはいえいずれにしても、json returnが考慮されているのは、よいこった。
……で、何気なくみていたら
vendor/slim/slim/Slim/Http/Response.php
public function write($data) { $this->getBody()->write($data); return $this; }
やだぁ便利なのあるじゃないですか。
ってことは
return $response->write(HTML文字列);
でいけますなぁ。
こっちこっち。使うの、こっち。
Returning a Redirect。
うん、これも大事。
return $response->withRedirect('/new-url', 301);
シンプル。
………Slimって、ルーティングに「名前付き」ってできたんだっけか?
https://www.slimframework.com/docs/v3/objects/router.html#route-names
に出てくるっぽいので、次回に回そうw
いじょ。
割とシンプルだったなぁ………そういや、Cookie周りのことはなんも書いてないw
まぁ、一通り掘り込んだ上で「なかったら」改めて考察しませう。