diff --git a/CHANGELOG.md b/CHANGELOG.md index 28e9b1f9..b10653c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,12 @@ All notable changes to this project will be documented in this file, in reverse ### Changed -- Nothing. +- [#162](https://github.com/zendframework/zend-diactoros/pull/162) modifies `Serializer\Request` such that it now no longer raises an `UnexpectedValueException` via its `toString()` method + when an unexpected HTTP method is encountered; this can be done safely, as the value can never + be invalid due to other changes in the same patch. + +- [#162](https://github.com/zendframework/zend-diactoros/pull/162) modifies `RequestTrait` such that it now invalidates non-string method arguments to either + the constructor or `withMethod()`, raising an `InvalidArgumentException` for any that do not validate. ### Deprecated diff --git a/src/Request/Serializer.php b/src/Request/Serializer.php index 20148631..edc1e1e6 100644 --- a/src/Request/Serializer.php +++ b/src/Request/Serializer.php @@ -80,9 +80,6 @@ public static function fromStream(StreamInterface $stream) public static function toString(RequestInterface $request) { $httpMethod = $request->getMethod(); - if (empty($httpMethod)) { - throw new UnexpectedValueException('Object can not be serialized because HTTP method is empty'); - } $headers = self::serializeHeaders($request->getHeaders()); $body = (string) $request->getBody(); $format = '%s %s HTTP/%s%s%s'; diff --git a/src/RequestTrait.php b/src/RequestTrait.php index a1bdc3de..0e535dbb 100644 --- a/src/RequestTrait.php +++ b/src/RequestTrait.php @@ -37,7 +37,7 @@ trait RequestTrait /** * @var string */ - private $method = ''; + private $method = 'GET'; /** * The request-target, if it has been provided or calculated. @@ -64,9 +64,10 @@ trait RequestTrait */ private function initialize($uri = null, $method = null, $body = 'php://memory', array $headers = []) { - $this->validateMethod($method); + if ($method !== null) { + $this->setMethod($method); + } - $this->method = $method ?: ''; $this->uri = $this->createUri($uri); $this->stream = $this->getStream($body, 'wb+'); @@ -204,9 +205,8 @@ public function getMethod() */ public function withMethod($method) { - $this->validateMethod($method); $new = clone $this; - $new->method = $method; + $new->setMethod($method); return $new; } @@ -284,21 +284,17 @@ public function withUri(UriInterface $uri, $preserveHost = false) } /** - * Validate the HTTP method + * Set and validate the HTTP method * - * @param null|string $method + * @param string $method * @throws InvalidArgumentException on invalid HTTP method. */ - private function validateMethod($method) + private function setMethod($method) { - if (null === $method) { - return; - } - if (! is_string($method)) { throw new InvalidArgumentException(sprintf( 'Unsupported HTTP method; must be a string, received %s', - (is_object($method) ? get_class($method) : gettype($method)) + is_object($method) ? get_class($method) : gettype($method) )); } @@ -308,6 +304,7 @@ private function validateMethod($method) $method )); } + $this->method = $method; } /** diff --git a/src/ServerRequest.php b/src/ServerRequest.php index bf98cd32..ed85e632 100644 --- a/src/ServerRequest.php +++ b/src/ServerRequest.php @@ -225,42 +225,6 @@ public function withoutAttribute($attribute) return $new; } - /** - * Proxy to receive the request method. - * - * This overrides the parent functionality to ensure the method is never - * empty; if no method is present, it returns 'GET'. - * - * @return string - */ - public function getMethod() - { - if (empty($this->method)) { - return 'GET'; - } - return $this->method; - } - - /** - * Set the request method. - * - * Unlike the regular Request implementation, the server-side - * normalizes the method to uppercase to ensure consistency - * and make checking the method simpler. - * - * This methods returns a new instance. - * - * @param string $method - * @return self - */ - public function withMethod($method) - { - $this->validateMethod($method); - $new = clone $this; - $new->method = $method; - return $new; - } - /** * Recursively validate the structure in an uploaded files array. * diff --git a/test/Request/SerializerTest.php b/test/Request/SerializerTest.php index 0c5ed049..f9ab6cb9 100644 --- a/test/Request/SerializerTest.php +++ b/test/Request/SerializerTest.php @@ -337,14 +337,4 @@ public function testFromStreamStopsReadingAfterScanningHeader() $this->assertInstanceOf(RelativeStream::class, $stream->getBody()); } - - public function testToStringRaisesExceptionOnEmptyMethod() - { - $request = (new Request()) - ->withUri(new Uri('http://example.com/foo/bar?baz=bat')); - - $this->expectException(UnexpectedValueException::class); - - Serializer::toString($request); - } } diff --git a/test/RequestTest.php b/test/RequestTest.php index ded3bc8b..f5c9ae8f 100644 --- a/test/RequestTest.php +++ b/test/RequestTest.php @@ -26,16 +26,33 @@ public function setUp() $this->request = new Request(); } - public function testMethodIsEmptyByDefault() + public function testMethodIsGetByDefault() { - $this->assertSame('', $this->request->getMethod()); + $this->assertSame('GET', $this->request->getMethod()); } public function testMethodMutatorReturnsCloneWithChangedMethod() { - $request = $this->request->withMethod('GET'); + $request = $this->request->withMethod('POST'); $this->assertNotSame($this->request, $request); - $this->assertSame('GET', $request->getMethod()); + $this->assertEquals('POST', $request->getMethod()); + } + + public function invalidMethod() + { + return [ + [null], + [''], + ]; + } + + /** + * @dataProvider invalidMethod + */ + public function testWithInvalidMethod($method) + { + $this->expectException(InvalidArgumentException::class); + $this->request->withMethod($method); } public function testReturnsUnpopulatedUriByDefault()