summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Http/MessageTrait.php21
-rw-r--r--src/Http/Request.php131
-rw-r--r--tests/Unit/Http/MessageTraitRequestTest.php50
-rw-r--r--tests/Unit/Http/MessageTraitResponseTest.php (renamed from tests/Unit/Http/MessageTraitTest.php)26
-rw-r--r--tests/Unit/Http/RequestTest.php90
-rw-r--r--tests/Unit/Http/Stub/MessageTraitRequestImplementation.php12
-rw-r--r--tests/Unit/Http/Stub/MessageTraitResponseImplementation.php (renamed from tests/Unit/Http/Stub/MessageTraitImplementation.php)2
7 files changed, 313 insertions, 19 deletions
diff --git a/src/Http/MessageTrait.php b/src/Http/MessageTrait.php
index fa3a1459..e46d291e 100644
--- a/src/Http/MessageTrait.php
+++ b/src/Http/MessageTrait.php
@@ -4,7 +4,6 @@ namespace Engelsystem\Http;
use Psr\Http\Message\StreamInterface;
-use Symfony\Component\HttpFoundation\ResponseHeaderBag;
use Zend\Diactoros\Stream;
/**
@@ -41,7 +40,12 @@ trait MessageTrait
public function withProtocolVersion($version)
{
$new = clone $this;
- $new->setProtocolVersion($version);
+ if (method_exists($new, 'setProtocolVersion')) {
+ $new->setProtocolVersion($version);
+ } else {
+ $new->server->set('SERVER_PROTOCOL', $version);
+ }
+
return $new;
}
@@ -72,7 +76,11 @@ trait MessageTrait
*/
public function getHeaders()
{
- return $this->headers->allPreserveCase();
+ if (method_exists($this->headers, 'allPreserveCase')) {
+ return $this->headers->allPreserveCase();
+ }
+
+ return $this->headers->all();
}
/**
@@ -228,7 +236,12 @@ trait MessageTrait
public function withBody(StreamInterface $body)
{
$new = clone $this;
- $new->setContent($body);
+
+ if (method_exists($new, 'setContent')) {
+ $new->setContent($body);
+ } else {
+ $new->content = $body;
+ }
return $new;
}
diff --git a/src/Http/Request.php b/src/Http/Request.php
index c6a9e5ad..fd3bff42 100644
--- a/src/Http/Request.php
+++ b/src/Http/Request.php
@@ -2,10 +2,15 @@
namespace Engelsystem\Http;
+use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\UriInterface;
use Symfony\Component\HttpFoundation\Request as SymfonyRequest;
+use Zend\Diactoros\Uri;
-class Request extends SymfonyRequest
+class Request extends SymfonyRequest implements RequestInterface
{
+ use MessageTrait;
+
/**
* Get POST input
*
@@ -64,4 +69,128 @@ class Request extends SymfonyRequest
{
return rtrim(preg_replace('/\?.*/', '', $this->getUri()), '/');
}
+
+ /**
+ * 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()
+ {
+ $query = $this->getQueryString();
+ return '/' . $this->path() . (!empty($query) ? '?' . $query : '');
+ }
+
+ /**
+ * Return an instance with the 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 an instance that has the
+ * changed request target.
+ *
+ * @link http://tools.ietf.org/html/rfc7230#section-5.3 (for the various
+ * request-target forms allowed in request messages)
+ * @param mixed $requestTarget
+ * @return static
+ */
+ public function withRequestTarget($requestTarget)
+ {
+ return $this->create($requestTarget);
+ }
+
+ /**
+ * Return an 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 an instance that has the
+ * changed request method.
+ *
+ * @param string $method Case-sensitive method.
+ * @return static
+ * @throws \InvalidArgumentException for invalid HTTP methods.
+ */
+ public function withMethod($method)
+ {
+ $new = clone $this;
+ $new->setMethod($method);
+
+ return $new;
+ }
+
+ /**
+ * Returns an instance with the provided URI.
+ *
+ * This method MUST update the Host header of the returned request by
+ * default if the URI contains a host component. If the URI does not
+ * contain a host component, any pre-existing Host header MUST be carried
+ * over to the returned request.
+ *
+ * You can opt-in to preserving the original state of the Host header by
+ * setting `$preserveHost` to `true`. When `$preserveHost` is set to
+ * `true`, this method interacts with the Host header in the following ways:
+ *
+ * - If the Host header is missing or empty, and the new URI contains
+ * a host component, this method MUST update the Host header in the returned
+ * request.
+ * - If the Host header is missing or empty, and the new URI does not contain a
+ * host component, this method MUST NOT update the Host header in the returned
+ * request.
+ * - If a Host header is present and non-empty, this method MUST NOT update
+ * the Host header in the returned request.
+ *
+ * This method MUST be implemented in such a way as to retain the
+ * immutability of the message, and MUST return an 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.
+ * @param bool $preserveHost Preserve the original state of the Host header.
+ * @return static
+ */
+ public function withUri(UriInterface $uri, $preserveHost = false)
+ {
+ $new = $this->create($uri);
+ if ($preserveHost) {
+ $new->headers->set('HOST', $this->getHost());
+ }
+
+ return $new;
+ }
+
+ /**
+ * Retrieves the URI instance.
+ *
+ * This method MUST return a UriInterface instance.
+ *
+ * @link http://tools.ietf.org/html/rfc3986#section-4.3
+ * @return string|UriInterface Returns a UriInterface instance
+ * representing the URI of the request.
+ */
+ public function getUri()
+ {
+ $uri = parent::getUri();
+
+ return new Uri($uri);
+ }
}
diff --git a/tests/Unit/Http/MessageTraitRequestTest.php b/tests/Unit/Http/MessageTraitRequestTest.php
new file mode 100644
index 00000000..7430b5d7
--- /dev/null
+++ b/tests/Unit/Http/MessageTraitRequestTest.php
@@ -0,0 +1,50 @@
+<?php
+
+namespace Engelsystem\Test\Unit\Http;
+
+use Engelsystem\Test\Unit\Http\Stub\MessageTraitRequestImplementation;
+use PHPUnit\Framework\TestCase;
+use Zend\Diactoros\Stream;
+
+class MessageTraitRequestTest extends TestCase
+{
+ /**
+ * @covers \Engelsystem\Http\MessageTrait::withProtocolVersion
+ */
+ public function testWithProtocolVersion()
+ {
+ $message = new MessageTraitRequestImplementation();
+ $newMessage = $message->withProtocolVersion('0.1');
+ $this->assertNotEquals($message, $newMessage);
+ $this->assertEquals('0.1', $newMessage->getProtocolVersion());
+ }
+
+ /**
+ * @covers \Engelsystem\Http\MessageTrait::getHeaders
+ */
+ public function testGetHeaders()
+ {
+ $message = new MessageTraitRequestImplementation();
+ $newMessage = $message->withHeader('lorem', 'ipsum');
+
+ $this->assertNotEquals($message, $newMessage);
+ $this->assertArraySubset(['lorem' => ['ipsum']], $newMessage->getHeaders());
+ }
+
+ /**
+ * @covers \Engelsystem\Http\MessageTrait::withBody
+ */
+ public function testWithBody()
+ {
+ /** @var Stream $stream */
+ $stream = new Stream('php://memory', 'wb+');
+ $stream->write('Test content');
+ $stream->rewind();
+
+ $message = new MessageTraitRequestImplementation();
+ $newMessage = $message->withBody($stream);
+
+ $this->assertNotEquals($message, $newMessage);
+ $this->assertEquals('Test content', $newMessage->getContent());
+ }
+}
diff --git a/tests/Unit/Http/MessageTraitTest.php b/tests/Unit/Http/MessageTraitResponseTest.php
index 46076a67..f60360a3 100644
--- a/tests/Unit/Http/MessageTraitTest.php
+++ b/tests/Unit/Http/MessageTraitResponseTest.php
@@ -2,21 +2,21 @@
namespace Engelsystem\Test\Unit\Http;
-use Engelsystem\Test\Unit\Http\Stub\MessageTraitImplementation;
+use Engelsystem\Test\Unit\Http\Stub\MessageTraitResponseImplementation;
use PHPUnit\Framework\TestCase;
use Psr\Http\Message\MessageInterface;
use Psr\Http\Message\StreamInterface;
use Symfony\Component\HttpFoundation\Response as SymfonyResponse;
use Zend\Diactoros\Stream;
-class MessageTraitTest extends TestCase
+class MessageTraitResponseTest extends TestCase
{
/**
* @covers \Engelsystem\Http\MessageTrait
*/
public function testCreate()
{
- $message = new MessageTraitImplementation();
+ $message = new MessageTraitResponseImplementation();
$this->assertInstanceOf(MessageInterface::class, $message);
$this->assertInstanceOf(SymfonyResponse::class, $message);
}
@@ -27,7 +27,7 @@ class MessageTraitTest extends TestCase
*/
public function testGetProtocolVersion()
{
- $message = new MessageTraitImplementation();
+ $message = new MessageTraitResponseImplementation();
$newMessage = $message->withProtocolVersion('0.1');
$this->assertNotEquals($message, $newMessage);
$this->assertEquals('0.1', $newMessage->getProtocolVersion());
@@ -38,7 +38,7 @@ class MessageTraitTest extends TestCase
*/
public function testGetHeaders()
{
- $message = new MessageTraitImplementation();
+ $message = new MessageTraitResponseImplementation();
$newMessage = $message->withHeader('Foo', 'bar');
$this->assertNotEquals($message, $newMessage);
@@ -53,7 +53,7 @@ class MessageTraitTest extends TestCase
*/
public function testHasHeader()
{
- $message = new MessageTraitImplementation();
+ $message = new MessageTraitResponseImplementation();
$this->assertFalse($message->hasHeader('test'));
$newMessage = $message->withHeader('test', '12345');
@@ -66,7 +66,7 @@ class MessageTraitTest extends TestCase
*/
public function testGetHeader()
{
- $message = new MessageTraitImplementation();
+ $message = new MessageTraitResponseImplementation();
$newMessage = $message->withHeader('foo', 'bar');
$this->assertEquals(['bar'], $newMessage->getHeader('Foo'));
@@ -78,7 +78,7 @@ class MessageTraitTest extends TestCase
*/
public function testGetHeaderLine()
{
- $message = new MessageTraitImplementation();
+ $message = new MessageTraitResponseImplementation();
$newMessage = $message->withHeader('foo', ['bar', 'bla']);
$this->assertEquals('', $newMessage->getHeaderLine('Lorem-Ipsum'));
@@ -90,7 +90,7 @@ class MessageTraitTest extends TestCase
*/
public function testWithHeader()
{
- $message = new MessageTraitImplementation();
+ $message = new MessageTraitResponseImplementation();
$newMessage = $message->withHeader('foo', 'bar');
$this->assertNotEquals($message, $newMessage);
@@ -105,7 +105,7 @@ class MessageTraitTest extends TestCase
*/
public function testWithAddedHeader()
{
- $message = new MessageTraitImplementation();
+ $message = new MessageTraitResponseImplementation();
$newMessage = $message->withHeader('foo', 'bar');
$this->assertNotEquals($message, $newMessage);
@@ -120,7 +120,7 @@ class MessageTraitTest extends TestCase
*/
public function testWithoutHeader()
{
- $message = (new MessageTraitImplementation())->withHeader('foo', 'bar');
+ $message = (new MessageTraitResponseImplementation())->withHeader('foo', 'bar');
$this->assertTrue($message->hasHeader('foo'));
$newMessage = $message->withoutHeader('Foo');
@@ -133,7 +133,7 @@ class MessageTraitTest extends TestCase
*/
public function testGetBody()
{
- $message = (new MessageTraitImplementation())->setContent('Foo bar!');
+ $message = (new MessageTraitResponseImplementation())->setContent('Foo bar!');
$body = $message->getBody();
$this->assertInstanceOf(StreamInterface::class, $body);
@@ -150,7 +150,7 @@ class MessageTraitTest extends TestCase
$stream->write('Test content');
$stream->rewind();
- $message = new MessageTraitImplementation();
+ $message = new MessageTraitResponseImplementation();
$newMessage = $message->withBody($stream);
$this->assertNotEquals($message, $newMessage);
diff --git a/tests/Unit/Http/RequestTest.php b/tests/Unit/Http/RequestTest.php
index f8444b84..f7d69aff 100644
--- a/tests/Unit/Http/RequestTest.php
+++ b/tests/Unit/Http/RequestTest.php
@@ -5,6 +5,8 @@ namespace Engelsystem\Test\Unit\Http;
use Engelsystem\Http\Request;
use PHPUnit\Framework\TestCase;
use PHPUnit_Framework_MockObject_MockObject as MockObject;
+use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\UriInterface;
use Symfony\Component\HttpFoundation\Request as SymfonyRequest;
class RequestTest extends TestCase
@@ -16,6 +18,7 @@ class RequestTest extends TestCase
{
$response = new Request();
$this->assertInstanceOf(SymfonyRequest::class, $response);
+ $this->assertInstanceOf(RequestInterface::class, $response);
}
/**
@@ -106,4 +109,91 @@ class RequestTest extends TestCase
$this->assertEquals('http://foo.bar/bla/foo', $request->url());
$this->assertEquals('https://lorem.ipsum/dolor/sit', $request->url());
}
+
+ /**
+ * @covers \Engelsystem\Http\Request::getRequestTarget
+ */
+ public function testGetRequestTarget()
+ {
+ /** @var Request|MockObject $request */
+ $request = $this
+ ->getMockBuilder(Request::class)
+ ->setMethods(['getQueryString', 'path'])
+ ->getMock();
+
+ $request->expects($this->exactly(2))
+ ->method('getQueryString')
+ ->willReturnOnConsecutiveCalls(null, 'foo=bar&lorem=ipsum');
+ $request->expects($this->exactly(2))
+ ->method('path')
+ ->willReturn('foo/bar');
+
+ $this->assertEquals('/foo/bar', $request->getRequestTarget());
+ $this->assertEquals('/foo/bar?foo=bar&lorem=ipsum', $request->getRequestTarget());
+ }
+
+ /**
+ * @covers \Engelsystem\Http\Request::withRequestTarget
+ */
+ public function testWithRequestTarget()
+ {
+ $request = new Request();
+ foreach (
+ [
+ '*',
+ '/foo/bar',
+ 'https://lorem.ipsum/test?lor=em'
+ ] as $target
+ ) {
+ $new = $request->withRequestTarget($target);
+ $this->assertNotEquals($request, $new);
+ }
+ }
+
+ /**
+ * @covers \Engelsystem\Http\Request::withMethod
+ */
+ public function testWithMethod()
+ {
+ $request = new Request();
+
+ $new = $request->withMethod('PUT');
+
+ $this->assertNotEquals($request, $new);
+ $this->assertEquals('PUT', $new->getMethod());
+ }
+
+ /**
+ * @covers \Engelsystem\Http\Request::withUri
+ */
+ public function testWithUri()
+ {
+ /** @var UriInterface|MockObject $uri */
+ $uri = $this->getMockForAbstractClass(UriInterface::class);
+
+ $uri->expects($this->atLeastOnce())
+ ->method('__toString')
+ ->willReturn('http://foo.bar/bla?foo=bar');
+
+ $request = Request::create('http://lor.em/');
+
+ $new = $request->withUri($uri);
+ $this->assertNotEquals($request, $new);
+ $this->assertEquals('http://foo.bar/bla?foo=bar', (string)$new->getUri());
+
+ $new = $request->withUri($uri, true);
+ $this->assertEquals('http://lor.em/bla?foo=bar', (string)$new->getUri());
+ }
+
+ /**
+ * @covers \Engelsystem\Http\Request::getUri
+ */
+ public function testGetUri()
+ {
+ $request = Request::create('http://lor.em/test?bla=foo');
+
+ $uri = $request->getUri();
+ $this->assertInstanceOf(UriInterface::class, $uri);
+ $this->assertEquals('http://lor.em/test?bla=foo', (string)$uri);
+ }
}
diff --git a/tests/Unit/Http/Stub/MessageTraitRequestImplementation.php b/tests/Unit/Http/Stub/MessageTraitRequestImplementation.php
new file mode 100644
index 00000000..04d08913
--- /dev/null
+++ b/tests/Unit/Http/Stub/MessageTraitRequestImplementation.php
@@ -0,0 +1,12 @@
+<?php
+
+namespace Engelsystem\Test\Unit\Http\Stub;
+
+use Engelsystem\Http\MessageTrait;
+use Psr\Http\Message\MessageInterface;
+use Symfony\Component\HttpFoundation\Request;
+
+class MessageTraitRequestImplementation extends Request implements MessageInterface
+{
+ use MessageTrait;
+}
diff --git a/tests/Unit/Http/Stub/MessageTraitImplementation.php b/tests/Unit/Http/Stub/MessageTraitResponseImplementation.php
index d78fd0b2..2ec4b943 100644
--- a/tests/Unit/Http/Stub/MessageTraitImplementation.php
+++ b/tests/Unit/Http/Stub/MessageTraitResponseImplementation.php
@@ -6,7 +6,7 @@ use Engelsystem\Http\MessageTrait;
use Psr\Http\Message\MessageInterface;
use Symfony\Component\HttpFoundation\Response;
-class MessageTraitImplementation extends Response implements MessageInterface
+class MessageTraitResponseImplementation extends Response implements MessageInterface
{
use MessageTrait;
}