From d09aa074108b6d24433b4d5a86e82b3b869a606e Mon Sep 17 00:00:00 2001 From: shudd3r Date: Wed, 31 Aug 2022 00:41:58 +0200 Subject: [PATCH 1/3] Added default body arg value in Request & Response --- src/Request.php | 20 ++++++++++---------- src/Response.php | 24 ++++++++++++------------ src/ServerRequest.php | 30 +++++++++++++++--------------- src/Stream.php | 4 ++-- tests/RequestTest.php | 5 ++--- tests/ResponseTest.php | 8 ++++---- tests/ServerRequestTest.php | 4 ++-- 7 files changed, 47 insertions(+), 48 deletions(-) diff --git a/src/Request.php b/src/Request.php index 1ecebea..cbcb67a 100644 --- a/src/Request.php +++ b/src/Request.php @@ -21,27 +21,27 @@ class Request implements RequestInterface use RequestMethodsTrait; /** - * @param string $method Normally one of the common methods defined by RFC 7231 section 4.3 - * @param UriInterface $uri - * @param StreamInterface $body - * @param array $headers Associative array of header strings or arrays of header strings - * @param array $params Associative array with following keys and its default values - * when key is not present or its value is null: - * - version - http protocol version (default: '1.1') - * - target - request target (default: resolved from passed $uri param) + * @param string $method Normally one of the common methods defined by RFC 7231 section 4.3 + * @param UriInterface $uri + * @param ?StreamInterface $body + * @param array $headers Associative array of header strings or arrays of header strings + * @param array $params Associative array with following keys and its default values + * when key is not present or its value is null: + * - version - http protocol version (default: '1.1') + * - target - request target (default: resolved from passed $uri param) * * @see https://tools.ietf.org/html/rfc7231#section-4.3 */ public function __construct( string $method, UriInterface $uri, - StreamInterface $body, + ?StreamInterface $body = null, array $headers = [], array $params = [] ) { $this->method = $this->validMethod($method); $this->uri = $uri; - $this->body = $body; + $this->body = $body ?? Stream::fromBodyString(''); $this->version = isset($params['version']) ? $this->validProtocolVersion($params['version']) : '1.1'; $this->target = isset($params['target']) ? $this->validRequestTarget($params['target']) : null; $this->loadHeaders($headers); diff --git a/src/Response.php b/src/Response.php index 03b25ed..a3654f1 100644 --- a/src/Response.php +++ b/src/Response.php @@ -25,26 +25,26 @@ class Response implements ResponseInterface private string $reason; /** - * @param int $statusCode Normally one of the status codes defined by RFC 7231 section 6 - * @param StreamInterface $body - * @param array $headers Associative array of header strings or arrays of header strings - * @param array $params Associative array with following keys and its default values - * when key is not present or its value is null: - * - version - http protocol version (default: '1.1') - * - reason - reason phrase normally associated with $statusCode, so by - * default it will be resolved from it. + * @param int $statusCode Normally one of the status codes defined by RFC 7231 section 6 + * @param ?StreamInterface $body + * @param array $headers Associative array of header strings or arrays of header strings + * @param array $params Associative array with following keys and its default values + * when key is not present or its value is null: + * - version - http protocol version (default: '1.1') + * - reason - reason phrase normally associated with $statusCode, so by + * default it will be resolved from it. * * @see https://tools.ietf.org/html/rfc7231#section-6 * @see StatusCodesTrait */ public function __construct( int $statusCode, - StreamInterface $body, + ?StreamInterface $body = null, array $headers = [], array $params = [] ) { $this->status = $this->validStatusCode($statusCode); - $this->body = $body; + $this->body = $body ?? Stream::fromBodyString(''); $this->reason = $this->validReasonPhrase($params['reason'] ?? ''); $this->version = isset($params['version']) ? $this->validProtocolVersion($params['version']) : '1.1'; $this->loadHeaders($headers); @@ -90,12 +90,12 @@ public static function redirect($uri, int $status = 303): self if ($status < 300 || $status > 399) { throw new InvalidArgumentException('Invalid status code for redirect response'); } - return new self($status, new Stream(fopen('php://temp', 'r')), ['Location' => (string) $uri]); + return new self($status, null, ['Location' => (string) $uri]); } public static function notFound(StreamInterface $body = null): self { - return new self(404, $body ?: Stream::fromResourceUri('php://temp')); + return new self(404, $body); } public function getStatusCode(): int diff --git a/src/ServerRequest.php b/src/ServerRequest.php index 8aa6b80..44a9f5e 100644 --- a/src/ServerRequest.php +++ b/src/ServerRequest.php @@ -28,27 +28,27 @@ class ServerRequest extends Request implements ServerRequestInterface private array $attributes = []; /** - * @param string $method Normally one of the common methods defined by RFC 7231 section 4.3 - * @param UriInterface $uri - * @param StreamInterface $body - * @param array $headers Associative array of header strings or arrays of header strings - * @param array $params Associative array with following keys and its default values - * when key is not present or its value is null: - * - version - http protocol version (default: '1.1') - * - target - request target (default: resolved from passed $uri param) - * - server - $_SERVER superglobal equivalent (default: []) - * - cookie - $_COOKIE superglobal equivalent (default: []) - * - query - $_GET superglobal equivalent (default: []) - * - parsedBody - $_POST superglobal equivalent (default: []) - * - files - associative array (multidimensional) of UploadedFileInterface - * instances (default: []) + * @param string $method Normally one of the common methods defined by RFC 7231 section 4.3 + * @param UriInterface $uri + * @param ?StreamInterface $body + * @param array $headers Associative array of header strings or arrays of header strings + * @param array $params Associative array with following keys and its default values + * when key is not present or its value is null: + * - version - http protocol version (default: '1.1') + * - target - request target (default: resolved from passed $uri param) + * - server - $_SERVER superglobal equivalent (default: []) + * - cookie - $_COOKIE superglobal equivalent (default: []) + * - query - $_GET superglobal equivalent (default: []) + * - parsedBody - $_POST superglobal equivalent (default: []) + * - files - associative array (multidimensional) of UploadedFileInterface + * instances (default: []) * * @see https://tools.ietf.org/html/rfc7231#section-4.3 */ public function __construct( string $method, UriInterface $uri, - StreamInterface $body, + ?StreamInterface $body = null, array $headers = [], array $params = [] ) { diff --git a/src/Stream.php b/src/Stream.php index 4958867..39c98cd 100644 --- a/src/Stream.php +++ b/src/Stream.php @@ -19,7 +19,7 @@ class Stream implements StreamInterface { - protected $resource; + private $resource; private ?array $metaData; private ?bool $readable; @@ -116,7 +116,7 @@ public function tell(): int public function eof(): bool { - return $this->resource ? feof($this->resource) : true; + return !$this->resource || feof($this->resource); } public function isSeekable(): bool diff --git a/tests/RequestTest.php b/tests/RequestTest.php index cddf274..b831836 100644 --- a/tests/RequestTest.php +++ b/tests/RequestTest.php @@ -12,7 +12,6 @@ namespace Polymorphine\Message\Tests; use PHPUnit\Framework\TestCase; -use Polymorphine\Message\Tests\Doubles\FakeStream; use Polymorphine\Message\Request; use Polymorphine\Message\Uri; use Psr\Http\Message\RequestInterface; @@ -142,9 +141,9 @@ private function request($method = 'GET', array $headers = [], $uri = null, $tar $uri = Uri::fromString(); } if (!$target) { - return new Request($method, $uri, new FakeStream(), $headers, []); + return new Request($method, $uri, null, $headers, []); } - return new Request($method, $uri, new FakeStream(), $headers, ['target' => $target]); + return new Request($method, $uri, null, $headers, ['target' => $target]); } } diff --git a/tests/ResponseTest.php b/tests/ResponseTest.php index 34a3c13..5b3835d 100644 --- a/tests/ResponseTest.php +++ b/tests/ResponseTest.php @@ -131,15 +131,15 @@ public function invalidReasonPhrases(): array public function testNamedConstructors() { $this->equivalentConstructs( - new Response(303, new FakeStream(), ['Location' => '/foo/bar/234']), + new Response(303, null, ['Location' => '/foo/bar/234']), Response::redirect(Uri::fromString('/foo/bar/234')) ); $this->equivalentConstructs( - new Response(301, new FakeStream(), ['Location' => '/foo/bar/baz']), + new Response(301, null, ['Location' => '/foo/bar/baz']), Response::redirect('/foo/bar/baz', 301) ); $this->equivalentConstructs( - new Response(404, new FakeStream()), + new Response(404), Response::notFound() ); $this->equivalentConstructs( @@ -184,6 +184,6 @@ private function equivalentConstructs(ResponseInterface $responseA, ResponseInte private function response($status = 200, $reason = null): Response { - return new Response($status, new FakeStream(), [], ['reason' => $reason]); + return new Response($status, null, [], ['reason' => $reason]); } } diff --git a/tests/ServerRequestTest.php b/tests/ServerRequestTest.php index ee23074..71e7674 100644 --- a/tests/ServerRequestTest.php +++ b/tests/ServerRequestTest.php @@ -147,8 +147,8 @@ public function testUploadedFileNestedStructureIsValid() $this->assertSame($files, $request->getUploadedFiles()); } - private function request(array $params = [], $method = 'GET', $headers = []): ServerRequest + private function request(array $params = []): ServerRequest { - return new ServerRequest($method, Uri::fromString(), new Doubles\FakeStream(), $headers, $params); + return new ServerRequest('GET', Uri::fromString(), null, [], $params); } } From 926cd8c839d6331f59141963481dd4ff613165dd Mon Sep 17 00:00:00 2001 From: shudd3r Date: Wed, 31 Aug 2022 18:28:10 +0200 Subject: [PATCH 2/3] Removed force object from default json response --- src/Response.php | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/Response.php b/src/Response.php index a3654f1..45104b5 100644 --- a/src/Response.php +++ b/src/Response.php @@ -66,8 +66,8 @@ public static function xml(string $xml, int $statusCode = 200): self } /** - * There's a XOR operator between $defaultEncode and $encodeOptions, - * which means that if option is set in both provided and default it + * There's a XOR operator between $defaultOptions and $encodeOptions, + * which means that if an option is set in both provided and default it * will be switched off. * * @param array $data @@ -76,11 +76,10 @@ public static function xml(string $xml, int $statusCode = 200): self * * @return self */ - public static function json(array $data, int $statusCode = 200, $encodeOptions = 0): self + public static function json(array $data, int $statusCode = 200, int $encodeOptions = 0): self { - $defaultEncode = JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT | - JSON_UNESCAPED_SLASHES | JSON_FORCE_OBJECT; - $serialized = json_encode($data, $defaultEncode ^ $encodeOptions); + $defaultOptions = JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT | JSON_UNESCAPED_SLASHES; + $serialized = $data ? json_encode($data, $defaultOptions ^ $encodeOptions) : '{}'; return new self($statusCode, Stream::fromBodyString($serialized), ['Content-Type' => 'application/json']); } From 74ea1a970fa43f7f59e182a4e98011e2396a98a9 Mon Sep 17 00:00:00 2001 From: shudd3r Date: Wed, 31 Aug 2022 18:35:11 +0200 Subject: [PATCH 3/3] Added constructors for common Response instances --- src/Response.php | 10 ++++++++++ tests/ResponseTest.php | 7 +++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/Response.php b/src/Response.php index 45104b5..56709f8 100644 --- a/src/Response.php +++ b/src/Response.php @@ -92,6 +92,16 @@ public static function redirect($uri, int $status = 303): self return new self($status, null, ['Location' => (string) $uri]); } + public static function badRequest(StreamInterface $body = null): self + { + return new self(400, $body); + } + + public static function unauthorized(StreamInterface $body = null): self + { + return new self(401, $body); + } + public static function notFound(StreamInterface $body = null): self { return new self(404, $body); diff --git a/tests/ResponseTest.php b/tests/ResponseTest.php index 5b3835d..a6e8419 100644 --- a/tests/ResponseTest.php +++ b/tests/ResponseTest.php @@ -138,10 +138,9 @@ public function testNamedConstructors() new Response(301, null, ['Location' => '/foo/bar/baz']), Response::redirect('/foo/bar/baz', 301) ); - $this->equivalentConstructs( - new Response(404), - Response::notFound() - ); + $this->equivalentConstructs(new Response(400), Response::badRequest()); + $this->equivalentConstructs(new Response(401), Response::unauthorized()); + $this->equivalentConstructs(new Response(404), Response::notFound()); $this->equivalentConstructs( new Response(404, new FakeStream('Not Found. Sorry.')), Response::notFound(new FakeStream('Not Found. Sorry.'))