Skip to content

Commit

Permalink
Merge pull request #15 from sunrise-php/release/v1.3.0
Browse files Browse the repository at this point in the history
v1.3.0
  • Loading branch information
fenric committed Apr 13, 2020
2 parents fd098f2 + 8ffa127 commit 37a4dfe
Show file tree
Hide file tree
Showing 5 changed files with 149 additions and 45 deletions.
51 changes: 51 additions & 0 deletions src/Exception/JsonException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php declare(strict_types=1);

/**
* It's free open-source software released under the MIT License.
*
* @author Anatoly Fenric <[email protected]>
* @copyright Copyright (c) 2018, Anatoly Fenric
* @license https://github.com/sunrise-php/http-message/blob/master/LICENSE
* @link https://github.com/sunrise-php/http-message
*/

namespace Sunrise\Http\Message\Exception;

/**
* Import classes
*/
use RuntimeException;

/**
* Import functions
*/
use function json_last_error;
use function json_last_error_msg;

/**
* Import constants
*/
use const JSON_ERROR_NONE;

/**
* JsonException
*/
class JsonException extends RuntimeException
{

/**
* @return void
*
* @throws self
*/
public static function assert() : void
{
$code = json_last_error();

if (JSON_ERROR_NONE === $code) {
return;
}

throw new self(json_last_error_msg(), $code);
}
}
85 changes: 46 additions & 39 deletions src/Message.php
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,7 @@ public function getHeader($name) : array
{
$name = $this->normalizeHeaderName($name);

if (empty($this->headers[$name]))
{
if (empty($this->headers[$name])) {
return [];
}

Expand All @@ -110,8 +109,7 @@ public function getHeaderLine($name) : string
{
$name = $this->normalizeHeaderName($name);

if (empty($this->headers[$name]))
{
if (empty($this->headers[$name])) {
return '';
}

Expand All @@ -121,14 +119,18 @@ public function getHeaderLine($name) : string
/**
* {@inheritDoc}
*/
public function withHeader($name, $value) : MessageInterface
public function withHeader($name, $value, bool $append = false) : MessageInterface
{
$this->validateHeaderName($name);
$this->validateHeaderValue($value);

$name = $this->normalizeHeaderName($name);
$value = $this->normalizeHeaderValue($value);

if (isset($this->headers[$name]) && $append) {
$value = \array_merge($this->headers[$name], $value);
}

$clone = clone $this;

$clone->headers[$name] = $value;
Expand All @@ -141,22 +143,28 @@ public function withHeader($name, $value) : MessageInterface
*/
public function withAddedHeader($name, $value) : MessageInterface
{
$this->validateHeaderName($name);
$this->validateHeaderValue($value);
return $this->withHeader($name, $value, true);
}

$name = $this->normalizeHeaderName($name);
$value = $this->normalizeHeaderValue($value);
/**
* Returns a new instance with the given headers
*
* @param iterable $headers
* @param bool $append
*
* @return MessageInterface
*
* @since 1.3.0
*/
public function withMultipleHeaders(iterable $headers, bool $append = false) : MessageInterface
{
$result = clone $this;

if (! empty($this->headers[$name]))
{
$value = \array_merge($this->headers[$name], $value);
foreach ($headers as $name => $value) {
$result = $result->withHeader($name, $value, $append);
}

$clone = clone $this;

$clone->headers[$name] = $value;

return $clone;
return $result;
}

/**
Expand Down Expand Up @@ -207,13 +215,14 @@ public function withBody(StreamInterface $body) : MessageInterface
*/
protected function validateProtocolVersion($protocolVersion) : void
{
if (! \is_string($protocolVersion))
{
if (! \is_string($protocolVersion)) {
throw new \InvalidArgumentException('HTTP protocol version must be a string');
}
else if (! \preg_match('/^\d(?:\.\d)?$/', $protocolVersion))
{
throw new \InvalidArgumentException(\sprintf('The given protocol version "%s" is not valid', $protocolVersion));

if (! \preg_match('/^\d(?:\.\d)?$/', $protocolVersion)) {
throw new \InvalidArgumentException(
\sprintf('The given protocol version "%s" is not valid', $protocolVersion)
);
}
}

Expand All @@ -230,13 +239,14 @@ protected function validateProtocolVersion($protocolVersion) : void
*/
protected function validateHeaderName($headerName) : void
{
if (! \is_string($headerName))
{
if (! \is_string($headerName)) {
throw new \InvalidArgumentException('Header name must be a string');
}
else if (! \preg_match(HeaderInterface::RFC7230_TOKEN, $headerName))
{
throw new \InvalidArgumentException(\sprintf('The given header name "%s" is not valid', $headerName));

if (! \preg_match(HeaderInterface::RFC7230_TOKEN, $headerName)) {
throw new \InvalidArgumentException(
\sprintf('The given header name "%s" is not valid', $headerName)
);
}
}

Expand All @@ -253,25 +263,23 @@ protected function validateHeaderName($headerName) : void
*/
protected function validateHeaderValue($headerValue) : void
{
if (\is_string($headerValue))
{
if (\is_string($headerValue)) {
$headerValue = [$headerValue];
}

if (! \is_array($headerValue) || [] === $headerValue)
{
if (! \is_array($headerValue) || [] === $headerValue) {
throw new \InvalidArgumentException('Header value must be a string or not an empty array');
}

foreach ($headerValue as $oneOf)
{
if (! \is_string($oneOf))
{
foreach ($headerValue as $oneOf) {
if (! \is_string($oneOf)) {
throw new \InvalidArgumentException('Header value must be a string or an array containing only strings');
}
else if (! \preg_match(HeaderInterface::RFC7230_FIELD_VALUE, $oneOf))
{
throw new \InvalidArgumentException(\sprintf('The given header value "%s" is not valid', $oneOf));

if (! \preg_match(HeaderInterface::RFC7230_FIELD_VALUE, $oneOf)) {
throw new \InvalidArgumentException(
\sprintf('The given header value "%s" is not valid', $oneOf)
);
}
}
}
Expand Down Expand Up @@ -303,7 +311,6 @@ protected function normalizeHeaderName($headerName) : string
protected function normalizeHeaderValue($headerValue) : array
{
$headerValue = (array) $headerValue;

$headerValue = \array_values($headerValue);

return $headerValue;
Expand Down
22 changes: 17 additions & 5 deletions src/ResponseFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,10 @@ public function createResponse(int $code = 200, string $reasonPhrase = '') : Res
*/
public function createHtmlResponse(int $status, $content) : ResponseInterface
{
$content = (string) $content;

$body = (new StreamFactory)->createStream();
$body->write((string) $content);
$body->write($content);

return (new Response)
->withStatus($status)
Expand All @@ -63,22 +65,32 @@ public function createHtmlResponse(int $status, $content) : ResponseInterface
}

/**
* Creates a JSON response object
* Creates a JSON response instance
*
* @param int $status
* @param mixed $payload
* @param int $options
* @param int $depth
*
* @return ResponseInterface
*
* @throws Exception\JsonException
*/
public function createJsonResponse(int $status, $payload, int $options = 0) : ResponseInterface
public function createJsonResponse(int $status, $payload, int $options = 0, int $depth = 512) : ResponseInterface
{
// clears a previous error...
json_encode(null);

$content = json_encode($payload, $options, $depth);

Exception\JsonException::assert();

$body = (new StreamFactory)->createStream();
$body->write(json_encode($payload, $options));
$body->write($content);

return (new Response)
->withStatus($status)
->withHeader('Content-Type', 'application/json')
->withHeader('Content-Type', 'application/json; charset=utf-8')
->withBody($body);
}
}
21 changes: 21 additions & 0 deletions tests/MessageTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,27 @@ public function testAddInvalidHeaderValueInArray($headerValue)
(new Message)->withAddedHeader('x-foo', ['bar', $headerValue, 'baz']);
}

public function testWithMultipleHeaders() : void
{
$message = new Message();

$subject = $message
->withMultipleHeaders(['x-foo' => 'bar'])
->withMultipleHeaders(['x-foo' => 'baz']);

$this->assertNotSame($subject, $message);
$this->assertCount(0, $message->getHeaders());
$this->assertSame(['x-foo' => ['baz']], $subject->getHeaders());

$subject = $message
->withMultipleHeaders(['x-foo' => 'bar'], true)
->withMultipleHeaders(['x-foo' => 'baz'], true);

$this->assertNotSame($subject, $message);
$this->assertCount(0, $message->getHeaders());
$this->assertSame(['x-foo' => ['bar', 'baz']], $subject->getHeaders());
}

public function testDeleteHeader()
{
$mess = (new Message)->withHeader('x-foo', 'bar');
Expand Down
15 changes: 14 additions & 1 deletion tests/ResponseFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamInterface;
use Sunrise\Http\Message\Exception\JsonException;
use Sunrise\Http\Message\ResponseFactory;

/**
Expand Down Expand Up @@ -89,7 +90,19 @@ public function testCreateJsonResponse() : void

$this->assertInstanceOf(ResponseInterface::class, $response);
$this->assertSame(400, $response->getStatusCode());
$this->assertSame('application/json', $response->getHeaderLine('Content-Type'));
$this->assertSame('application/json; charset=utf-8', $response->getHeaderLine('Content-Type'));
$this->assertSame(json_encode($payload, $options), (string) $response->getBody());
}

/**
* @return void
*/
public function testCreateResponseWithInvalidJson() : void
{
$this->expectException(JsonException::class);
$this->expectExceptionMessage('Maximum stack depth exceeded');

$response = (new ResponseFactory)
->createJsonResponse(200, [[]], 0, 1);
}
}

0 comments on commit 37a4dfe

Please sign in to comment.