From 7f0b8886eb32c45c38d095301d7d73431b240a1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B8=D1=85=D0=B0=D0=B8=D0=BB=20=D0=9A=D1=80=D0=B0?= =?UTF-8?q?=D1=81=D0=B8=D0=BB=D1=8C=D0=BD=D0=B8=D0=BA=D0=BE=D0=B2?= Date: Fri, 29 Jan 2016 12:32:12 +0300 Subject: [PATCH 1/2] ResponseBuilder class. --- spec/Builder/ResponseBuilderSpec.php | 35 ++++++++ src/Builder/ResponseBuilder.php | 115 +++++++++++++++++++++++++++ 2 files changed, 150 insertions(+) create mode 100644 spec/Builder/ResponseBuilderSpec.php create mode 100644 src/Builder/ResponseBuilder.php diff --git a/spec/Builder/ResponseBuilderSpec.php b/spec/Builder/ResponseBuilderSpec.php new file mode 100644 index 0000000..606884a --- /dev/null +++ b/spec/Builder/ResponseBuilderSpec.php @@ -0,0 +1,35 @@ +beConstructedWith($response); + $this->shouldHaveType('Http\Message\Builder\ResponseBuilder'); + } + + function it_reads_headers_from_array(ResponseInterface $response) + { + $response->withStatus(200, 'OK')->willReturn($response); + $response->withProtocolVersion('1.1')->willReturn($response); + $response->hasHeader('Content-type')->willReturn(false); + $response->withHeader('Content-type', 'text/html')->willReturn($response); + $this->beConstructedWith($response); + $this->setHeadersFromArray(['HTTP/1.1 200 OK', 'Content-type: text/html']); + } + + function it_reads_headers_from_string(ResponseInterface $response) + { + $response->withStatus(200, 'OK')->willReturn($response); + $response->withProtocolVersion('1.1')->willReturn($response); + $response->hasHeader('Content-type')->willReturn(false); + $response->withHeader('Content-type', 'text/html')->willReturn($response); + $this->beConstructedWith($response); + $this->setHeadersFromString("HTTP/1.1 200 OK\r\nContent-type: text/html\r\n"); + } +} diff --git a/src/Builder/ResponseBuilder.php b/src/Builder/ResponseBuilder.php new file mode 100644 index 0000000..7616849 --- /dev/null +++ b/src/Builder/ResponseBuilder.php @@ -0,0 +1,115 @@ +response = $response; + } + + /** + * Return response. + * + * @return ResponseInterface + */ + public function getResponse() + { + return $this->response; + } + + /** + * Add headers represented by an array of header lines. + * + * @param string[] $headers Response headers as array of header lines. + * + * @return $this + * + * @throws \UnexpectedValueException For invalid header values. + * @throws \InvalidArgumentException For invalid status code arguments. + */ + public function setHeadersFromArray(array $headers) + { + $statusLine = trim(array_shift($headers)); + $parts = explode(' ', $statusLine, 3); + if (count($parts) < 2 || substr(strtolower($parts[0]), 0, 5) !== 'http/') { + throw new \UnexpectedValueException( + sprintf('"%s" is not a valid HTTP status line', $statusLine) + ); + } + + $reasonPhrase = count($parts) > 2 ? $parts[2] : ''; + $this->response = $this->response + ->withStatus((int) $parts[1], $reasonPhrase) + ->withProtocolVersion(substr($parts[0], 5)); + + foreach ($headers as $headerLine) { + $headerLine = trim($headerLine); + if ('' === $headerLine) { + continue; + } + + $parts = explode(':', $headerLine, 2); + if (count($parts) !== 2) { + throw new \UnexpectedValueException( + sprintf('"%s" is not a valid HTTP header line', $headerLine) + ); + } + $name = trim(urldecode($parts[0])); + $value = trim(urldecode($parts[1])); + if ($this->response->hasHeader($name)) { + $this->response = $this->response->withAddedHeader($name, $value); + } else { + $this->response = $this->response->withHeader($name, $value); + } + } + + return $this; + } + + /** + * Add headers represented by a single string. + * + * @param string $headers Response headers as single string. + * + * @return $this + * + * @throws \InvalidArgumentException if $headers is not a string on object with __toString() + * @throws \UnexpectedValueException For invalid header values. + */ + public function setHeadersFromString($headers) + { + if (!(is_string($headers) + || (is_object($headers) && method_exists($headers, '__toString'))) + ) { + throw new \InvalidArgumentException( + sprintf( + '%s expects parameter 1 to be a string, %s given', + __METHOD__, + is_object($headers) ? get_class($headers) : gettype($headers) + ) + ); + } + + $this->setHeadersFromArray(explode("\r\n", $headers)); + return $this; + } +} From cb742fd413c12c17647c8be83b33a3847b066a68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B8=D1=85=D0=B0=D0=B8=D0=BB=20=D0=9A=D1=80=D0=B0?= =?UTF-8?q?=D1=81=D0=B8=D0=BB=D1=8C=D0=BD=D0=B8=D0=BA=D0=BE=D0=B2?= Date: Fri, 29 Jan 2016 16:13:22 +0300 Subject: [PATCH 2/2] Fix code style. --- src/Builder/ResponseBuilder.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Builder/ResponseBuilder.php b/src/Builder/ResponseBuilder.php index 7616849..b841c03 100644 --- a/src/Builder/ResponseBuilder.php +++ b/src/Builder/ResponseBuilder.php @@ -110,6 +110,7 @@ public function setHeadersFromString($headers) } $this->setHeadersFromArray(explode("\r\n", $headers)); + return $this; } }