From 292e213c0a9b87fa9d2a06d0d7b94ba94c3233b3 Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Sun, 22 Mar 2015 18:02:36 -0400 Subject: [PATCH] Add Message\Request --- src/Message/Request.php | 220 +++++++++++++++++++++ test/tests/unit/Message/RequestTest.php | 250 ++++++++++++++++++++++++ 2 files changed, 470 insertions(+) create mode 100644 src/Message/Request.php create mode 100644 test/tests/unit/Message/RequestTest.php diff --git a/src/Message/Request.php b/src/Message/Request.php new file mode 100644 index 0000000..cbe5f1b --- /dev/null +++ b/src/Message/Request.php @@ -0,0 +1,220 @@ +hasHeader("host")) { + $headers["Host"] = [$this->uri->getHost()]; + } + return $headers; + } + + /** + * Extends MessageInterface::getHeader() to provide request-specific + * behavior. + * + * This method acts exactly like MessageInterface::getHeader(), with + * one behavioral change: if the Host header is requested, but has + * not been previously set, the method MUST attempt to pull the host + * segment of the composed URI, if present. + * + * @see MessageInterface::getHeader() + * @see UriInterface::getHost() + * @param string $name Case-insensitive header field name. + * @return string + */ + public function getHeader($name) + { + $header = parent::getHeader($name); + if ($header === null && (strtolower($name) === "host") && isset($this->uri)) { + $header = $this->uri->getHost(); + } + return $header; + } + + /** + * Extends MessageInterface::getHeaderLines() to provide request-specific + * behavior. + * + * Retrieves a header by the given case-insensitive name as an array of strings. + * + * This method acts exactly like MessageInterface::getHeaderLines(), with + * one behavioral change: if the Host header is requested, but has + * not been previously set, the method MUST attempt to pull the host + * segment of the composed URI, if present. + * + * @see MessageInterface::getHeaderLines() + * @see UriInterface::getHost() + * @param string $name Case-insensitive header field name. + * @return string[] + */ + public function getHeaderLines($name) + { + $headerLines = parent::getHeaderLines($name); + if (!$headerLines && (strtolower($name) === "host") && isset($this->uri)) { + $headerLines = [$this->uri->getHost()]; + } + return $headerLines; + } + + /** + * Retrieves the message's request target. + * + * Retrieves the message's request-target either as it will appear (for + * clients), as it appeared at request (for servers), or as it was + * specified for the instance (see withRequestTarget()). + * + * In most cases, this will be the origin-form of the composed URI, + * unless a value was provided to the concrete implementation (see + * withRequestTarget() below). + * + * If no URI is available, and no request-target has been specifically + * provided, this method MUST return the string "/". + * + * @return string + */ + public function getRequestTarget() + { + if (isset($this->requestTarget)) { + $target = $this->requestTarget; + } elseif (isset($this->uri)) { + $target = $this->uri->getPath(); + $query = $this->uri->getQuery(); + if ($query) { + $target .= "?" . $query; + } + } else { + $target = "/"; + } + return $target; + } + + /** + * Create a new instance with a specific request-target. + * + * If the request needs a non-origin-form request-target — e.g., for + * specifying an absolute-form, authority-form, or asterisk-form — + * this method may be used to create an instance with the specified + * request-target, verbatim. + * + * This method MUST be implemented in such a way as to retain the + * immutability of the message, and MUST return a new instance that has the + * changed request target. + * + * @link http://tools.ietf.org/html/rfc7230#section-2.7 (for the various + * request-target forms allowed in request messages) + * @param mixed $requestTarget + * @return self + */ + public function withRequestTarget($requestTarget) + { + $request = clone $this; + $request->requestTarget = $requestTarget; + return $request; + } + + /** + * Retrieves the HTTP method of the request. + * + * @return string Returns the request method. + */ + public function getMethod() + { + return $this->method; + } + + /** + * Create a new instance with the provided HTTP method. + * + * While HTTP method names are typically all uppercase characters, HTTP + * method names are case-sensitive and thus implementations SHOULD NOT + * modify the given string. + * + * This method MUST be implemented in such a way as to retain the + * immutability of the message, and MUST return a new instance that has the + * changed request method. + * + * @param string $method Case-insensitive method. + * @return self + * @throws \InvalidArgumentException for invalid HTTP methods. + */ + public function withMethod($method) + { + $request = clone $this; + $request->method = $method; + return $request; + } + + /** + * Retrieves the URI instance. + * + * This method MUST return a UriInterface instance. + * + * @link http://tools.ietf.org/html/rfc3986#section-4.3 + * @return UriInterface Returns a UriInterface instance + * representing the URI of the request, if any. + */ + public function getUri() + { + return $this->uri; + } + + /** + * Create a new instance with the provided URI. + * + * This method MUST be implemented in such a way as to retain the + * immutability of the message, and MUST return a new instance that has the + * new UriInterface instance. + * + * @link http://tools.ietf.org/html/rfc3986#section-4.3 + * @param UriInterface $uri New request URI to use. + * @return self + */ + public function withUri(UriInterface $uri) + { + $request = clone $this; + $request->uri = $uri; + return $request; + } + + public function __clone() + { + if (isset($this->uri)) { + $this->uri = clone $this->uri; + } + parent::__clone(); + } +} diff --git a/test/tests/unit/Message/RequestTest.php b/test/tests/unit/Message/RequestTest.php new file mode 100644 index 0000000..5cabea1 --- /dev/null +++ b/test/tests/unit/Message/RequestTest.php @@ -0,0 +1,250 @@ +prophesize("\\Psr\\Http\\Message\\UriInterface"); + $uri->getHost()->willReturn("localhost"); + + $request = new Request(); + $request = $request->withUri($uri->reveal()); + + $headers = $request->getHeaders(); + $this->assertEquals(["localhost"], $headers["Host"]); + } + + /** + * @covers WellRESTed\Message\Request::getHeaders + * @uses WellRESTed\Message\Request::withUri + * @uses WellRESTed\Message\Request::__clone + * @uses WellRESTed\Message\Message + * @uses WellRESTed\Message\HeaderCollection + */ + public function testGetHeadersPrefersExplicitHostHeader() + { + $uri = $this->prophesize("\\Psr\\Http\\Message\\UriInterface"); + $uri->getHost()->willReturn("localhot"); + + $request = new Request(); + $request = $request->withUri($uri->reveal()); + $request = $request->withHeader("Host", "www.mysite.com"); + + $headers = $request->getHeaders(); + $this->assertEquals(["www.mysite.com"], $headers["Host"]); + } + + /** + * @covers WellRESTed\Message\Request::getHeader + * @uses WellRESTed\Message\Request::getRequestTarget + * @uses WellRESTed\Message\Request::withUri + * @uses WellRESTed\Message\Request::__clone + * @uses WellRESTed\Message\Message + * @uses WellRESTed\Message\HeaderCollection + */ + public function testGetHeaderReturnsHostFromUri() + { + $uri = $this->prophesize("\\Psr\\Http\\Message\\UriInterface"); + $uri->getHost()->willReturn("localhost"); + + $request = new Request(); + $request = $request->withUri($uri->reveal()); + $this->assertEquals("localhost", $request->getHeader("host")); + } + + /** + * @covers WellRESTed\Message\Request::getHeader + * @uses WellRESTed\Message\Request::getRequestTarget + * @uses WellRESTed\Message\Request::withUri + * @uses WellRESTed\Message\Request::__clone + * @uses WellRESTed\Message\Message + * @uses WellRESTed\Message\HeaderCollection + */ + public function testGetHeaderPrefersExplicitHostHeader() + { + $uri = $this->prophesize("\\Psr\\Http\\Message\\UriInterface"); + $uri->getHost()->willReturn("localhot"); + + $request = new Request(); + $request = $request->withUri($uri->reveal()); + $request = $request->withHeader("Host", "www.mysite.com"); + $this->assertEquals("www.mysite.com", $request->getHeader("host")); + } + + /** + * @covers WellRESTed\Message\Request::getHeaderLines + * @uses WellRESTed\Message\Request::withUri + * @uses WellRESTed\Message\Request::__clone + * @uses WellRESTed\Message\Message + * @uses WellRESTed\Message\HeaderCollection + */ + public function testGetHeaderLinesReturnsHostFromUri() + { + $uri = $this->prophesize("\\Psr\\Http\\Message\\UriInterface"); + $uri->getHost()->willReturn("localhot"); + + $request = new Request(); + $request = $request->withUri($uri->reveal()); + $this->assertEquals(["localhot"], $request->getHeaderLines("host")); + } + + /** + * @covers WellRESTed\Message\Request::getHeaderLines + * @uses WellRESTed\Message\Request::withUri + * @uses WellRESTed\Message\Request::__clone + * @uses WellRESTed\Message\Message + * @uses WellRESTed\Message\HeaderCollection + */ + public function testGetHeaderLinesPrefersExplicitHostHeader() + { + $uri = $this->prophesize("\\Psr\\Http\\Message\\UriInterface"); + $uri->getHost()->willReturn("localhot"); + + $request = new Request(); + $request = $request->withUri($uri->reveal()); + $request = $request->withHeader("Host", "www.mysite.com"); + $this->assertEquals(["www.mysite.com"], $request->getHeaderLines("host")); + } + + /** + * @covers WellRESTed\Message\Request::getRequestTarget + * @uses WellRESTed\Message\Request::withRequestTarget + * @uses WellRESTed\Message\Request::__clone + * @uses WellRESTed\Message\Message + * @uses WellRESTed\Message\HeaderCollection + */ + public function testGetRequestTargetPrefersConreteRequestTarget() + { + $request = new Request(); + $request = $request->withRequestTarget("*"); + $this->assertEquals("*", $request->getRequestTarget()); + } + + /** + * @covers WellRESTed\Message\Request::getRequestTarget + * @uses WellRESTed\Message\Request::withUri + * @uses WellRESTed\Message\Request::__clone + * @uses WellRESTed\Message\Message + * @uses WellRESTed\Message\HeaderCollection + */ + public function testGetRequestTargetUsesOriginFormOfUri() + { + $uri = $this->prophesize("\\Psr\\Http\\Message\\UriInterface"); + $uri->getPath()->willReturn("/my/path"); + $uri->getQuery()->willReturn("cat=Molly&dog=Bear"); + + $request = new Request(); + $request = $request->withUri($uri->reveal()); + $this->assertEquals("/my/path?cat=Molly&dog=Bear", $request->getRequestTarget()); + } + + /** + * @covers WellRESTed\Message\Request::getRequestTarget + * @uses WellRESTed\Message\Message + * @uses WellRESTed\Message\HeaderCollection + */ + public function testGetRequestTargetReturnsSlashByDefault() + { + $request = new Request(); + $this->assertEquals("/", $request->getRequestTarget()); + } + + /** + * @covers WellRESTed\Message\Request::getMethod + * @uses WellRESTed\Message\Message + * @uses WellRESTed\Message\HeaderCollection + */ + public function testGetMethodReturnsGetByDefault() + { + $request = new Request(); + $this->assertEquals("GET", $request->getMethod()); + } + + /** + * @covers WellRESTed\Message\Request::withMethod + * @covers WellRESTed\Message\Request::getMethod + * @uses WellRESTed\Message\Request::__clone + * @uses WellRESTed\Message\Message + * @uses WellRESTed\Message\HeaderCollection + */ + public function testWithMethodCreatesNewInstance() + { + $request = new Request(); + $request = $request->withMethod("POST"); + $this->assertEquals("POST", $request->getMethod()); + } + + /** + * @covers WellRESTed\Message\Request::withRequestTarget + * @covers WellRESTed\Message\Request::getRequestTarget + * @uses WellRESTed\Message\Request::__clone + * @uses WellRESTed\Message\Message + * @uses WellRESTed\Message\HeaderCollection + */ + public function testWithRequestTargetCreatesNewInstance() + { + $request = new Request(); + $request = $request->withRequestTarget("*"); + $this->assertEquals("*", $request->getRequestTarget()); + } + + /** + * @covers WellRESTed\Message\Request::withUri + * @covers WellRESTed\Message\Request::getUri + * @uses WellRESTed\Message\Request::__clone + * @uses WellRESTed\Message\Message + * @uses WellRESTed\Message\HeaderCollection + */ + public function testWithUriCreatesNewInstance() + { + $uri = $this->prophesize("\\Psr\\Http\\Message\\UriInterface"); + $uri = $uri->reveal(); + + $request = new Request(); + $request = $request->withUri($uri); + $this->assertSame($uri, $request->getUri()); + } + + /** + * @covers WellRESTed\Message\Request::__clone + * @uses WellRESTed\Message\Request::getUri + * @uses WellRESTed\Message\Request::withUri + * @uses WellRESTed\Message\Request::getHeader + * @uses WellRESTed\Message\Request::withHeader + * @uses WellRESTed\Message\Request::getRequestTarget + * @uses WellRESTed\Message\Message + * @uses WellRESTed\Message\HeaderCollection + */ + public function testWithUriPreservesOriginalRequest() + { + $uri1 = $this->prophesize("\\Psr\\Http\\Message\\UriInterface"); + $uri1 = $uri1->reveal(); + + $uri2 = $this->prophesize("\\Psr\\Http\\Message\\UriInterface"); + $uri2 = $uri2->reveal(); + + $request1 = new Request(); + $request1 = $request1->withUri($uri1); + $request1 = $request1->withHeader("Accept", "application/json"); + + $request2 = $request1->withUri($uri2); + $request2 = $request2->withHeader("Accept", "text/plain"); + + $this->assertEquals($uri1, $request1->getUri()); + $this->assertEquals("application/json", $request1->getHeader("Accept")); + + $this->assertEquals($uri2, $request2->getUri()); + $this->assertEquals("text/plain", $request2->getHeader("Accept")); + } +}