summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Http/Psr7ServiceProvider.php3
-rw-r--r--src/Http/Request.php320
-rw-r--r--tests/Unit/Http/Psr7ServiceProviderTest.php5
-rw-r--r--tests/Unit/Http/RequestTest.php183
4 files changed, 502 insertions, 9 deletions
diff --git a/src/Http/Psr7ServiceProvider.php b/src/Http/Psr7ServiceProvider.php
index 4a3c6583..72fdef8e 100644
--- a/src/Http/Psr7ServiceProvider.php
+++ b/src/Http/Psr7ServiceProvider.php
@@ -18,8 +18,7 @@ class Psr7ServiceProvider extends ServiceProvider
/** @var Request $request */
$request = $this->app->get('request');
- $psr7request = $psr7Factory->createRequest($request);
- $this->app->instance('psr7.request', $psr7request);
+ $this->app->instance('psr7.request', $request);
$this->app->bind(ServerRequestInterface::class, 'psr7.request');
/** @var Response $response */
diff --git a/src/Http/Request.php b/src/Http/Request.php
index fd3bff42..4729606f 100644
--- a/src/Http/Request.php
+++ b/src/Http/Request.php
@@ -2,12 +2,15 @@
namespace Engelsystem\Http;
-use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\ServerRequestInterface;
+use Psr\Http\Message\UploadedFileInterface;
use Psr\Http\Message\UriInterface;
+use Symfony\Component\HttpFoundation\File\UploadedFile as SymfonyFile;
use Symfony\Component\HttpFoundation\Request as SymfonyRequest;
+use Zend\Diactoros\UploadedFile;
use Zend\Diactoros\Uri;
-class Request extends SymfonyRequest implements RequestInterface
+class Request extends SymfonyRequest implements ServerRequestInterface
{
use MessageTrait;
@@ -193,4 +196,317 @@ class Request extends SymfonyRequest implements RequestInterface
return new Uri($uri);
}
+
+ /**
+ * Retrieve server parameters.
+ *
+ * Retrieves data related to the incoming request environment,
+ * typically derived from PHP's $_SERVER superglobal. The data IS NOT
+ * REQUIRED to originate from $_SERVER.
+ *
+ * @return array
+ */
+ public function getServerParams()
+ {
+ return $this->server->all();
+ }
+
+ /**
+ * Retrieve cookies.
+ *
+ * Retrieves cookies sent by the client to the server.
+ *
+ * The data MUST be compatible with the structure of the $_COOKIE
+ * superglobal.
+ *
+ * @return array
+ */
+ public function getCookieParams()
+ {
+ return $this->cookies->all();
+ }
+
+ /**
+ * Return an instance with the specified cookies.
+ *
+ * The data IS NOT REQUIRED to come from the $_COOKIE superglobal, but MUST
+ * be compatible with the structure of $_COOKIE. Typically, this data will
+ * be injected at instantiation.
+ *
+ * This method MUST NOT update the related Cookie header of the request
+ * instance, nor related values in the server params.
+ *
+ * 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
+ * updated cookie values.
+ *
+ * @param array $cookies Array of key/value pairs representing cookies.
+ * @return static
+ */
+ public function withCookieParams(array $cookies)
+ {
+ $new = clone $this;
+ $new->cookies = clone $this->cookies;
+ $new->cookies->replace($cookies);
+
+ return $new;
+ }
+
+ /**
+ * Retrieve query string arguments.
+ *
+ * Retrieves the deserialized query string arguments, if any.
+ *
+ * Note: the query params might not be in sync with the URI or server
+ * params. If you need to ensure you are only getting the original
+ * values, you may need to parse the query string from `getUri()->getQuery()`
+ * or from the `QUERY_STRING` server param.
+ *
+ * @return array
+ */
+ public function getQueryParams()
+ {
+ return $this->query->all();
+ }
+
+ /**
+ * Return an instance with the specified query string arguments.
+ *
+ * These values SHOULD remain immutable over the course of the incoming
+ * request. They MAY be injected during instantiation, such as from PHP's
+ * $_GET superglobal, or MAY be derived from some other value such as the
+ * URI. In cases where the arguments are parsed from the URI, the data
+ * MUST be compatible with what PHP's parse_str() would return for
+ * purposes of how duplicate query parameters are handled, and how nested
+ * sets are handled.
+ *
+ * Setting query string arguments MUST NOT change the URI stored by the
+ * request, nor the values in the server params.
+ *
+ * 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
+ * updated query string arguments.
+ *
+ * @param array $query Array of query string arguments, typically from
+ * $_GET.
+ * @return static
+ */
+ public function withQueryParams(array $query)
+ {
+ $new = clone $this;
+ $new->query = clone $this->query;
+ $new->query->replace($query);
+
+ return $new;
+ }
+
+ /**
+ * Retrieve normalized file upload data.
+ *
+ * This method returns upload metadata in a normalized tree, with each leaf
+ * an instance of Psr\Http\Message\UploadedFileInterface.
+ *
+ * These values MAY be prepared from $_FILES or the message body during
+ * instantiation, or MAY be injected via withUploadedFiles().
+ *
+ * @return array An array tree of UploadedFileInterface instances; an empty
+ * array MUST be returned if no data is present.
+ */
+ public function getUploadedFiles()
+ {
+ $files = [];
+ foreach ($this->files as $file) {
+ /** @var SymfonyFile $file */
+
+ $files[] = new UploadedFile(
+ $file->getPath(),
+ $file->getSize(),
+ $file->getError(),
+ $file->getClientOriginalName(),
+ $file->getClientMimeType()
+ );
+ }
+
+ return $files;
+ }
+
+ /**
+ * Create a new instance with the specified uploaded files.
+ *
+ * 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
+ * updated body parameters.
+ *
+ * @param array $uploadedFiles An array tree of UploadedFileInterface instances.
+ * @return static
+ * @throws \InvalidArgumentException if an invalid structure is provided.
+ */
+ public function withUploadedFiles(array $uploadedFiles)
+ {
+ $new = clone $this;
+ $new->files = clone $this->files;
+
+ $files = [];
+ foreach ($uploadedFiles as $file) {
+ /** @var UploadedFileInterface $file */
+ $filename = tempnam(sys_get_temp_dir(), 'upload');
+ $handle = fopen($filename, "w");
+ fwrite($handle, $file->getStream()->getContents());
+ fclose($handle);
+
+ $files[] = new SymfonyFile(
+ $filename,
+ $file->getClientFilename(),
+ $file->getClientMediaType(),
+ $file->getSize(),
+ $file->getError()
+ );
+ }
+ $new->files->add($files);
+
+ return $new;
+ }
+
+ /**
+ * Retrieve any parameters provided in the request body.
+ *
+ * If the request Content-Type is either application/x-www-form-urlencoded
+ * or multipart/form-data, and the request method is POST, this method MUST
+ * return the contents of $_POST.
+ *
+ * Otherwise, this method may return any results of deserializing
+ * the request body content; as parsing returns structured content, the
+ * potential types MUST be arrays or objects only. A null value indicates
+ * the absence of body content.
+ *
+ * @return null|array|object The deserialized body parameters, if any.
+ * These will typically be an array or object.
+ */
+ public function getParsedBody()
+ {
+ return $this->request->all();
+ }
+
+ /**
+ * Return an instance with the specified body parameters.
+ *
+ * These MAY be injected during instantiation.
+ *
+ * If the request Content-Type is either application/x-www-form-urlencoded
+ * or multipart/form-data, and the request method is POST, use this method
+ * ONLY to inject the contents of $_POST.
+ *
+ * The data IS NOT REQUIRED to come from $_POST, but MUST be the results of
+ * deserializing the request body content. Deserialization/parsing returns
+ * structured data, and, as such, this method ONLY accepts arrays or objects,
+ * or a null value if nothing was available to parse.
+ *
+ * As an example, if content negotiation determines that the request data
+ * is a JSON payload, this method could be used to create a request
+ * instance with the deserialized parameters.
+ *
+ * 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
+ * updated body parameters.
+ *
+ * @param null|array|object $data The deserialized body data. This will
+ * typically be in an array or object.
+ * @return static
+ * @throws \InvalidArgumentException if an unsupported argument type is
+ * provided.
+ */
+ public function withParsedBody($data)
+ {
+ $new = clone $this;
+ $new->request = clone $this->request;
+
+ $new->request->replace($data);
+
+ return $new;
+ }
+
+ /**
+ * Retrieve attributes derived from the request.
+ *
+ * The request "attributes" may be used to allow injection of any
+ * parameters derived from the request: e.g., the results of path
+ * match operations; the results of decrypting cookies; the results of
+ * deserializing non-form-encoded message bodies; etc. Attributes
+ * will be application and request specific, and CAN be mutable.
+ *
+ * @return array Attributes derived from the request.
+ */
+ public function getAttributes()
+ {
+ return $this->attributes->all();
+ }
+
+ /**
+ * Retrieve a single derived request attribute.
+ *
+ * Retrieves a single derived request attribute as described in
+ * getAttributes(). If the attribute has not been previously set, returns
+ * the default value as provided.
+ *
+ * This method obviates the need for a hasAttribute() method, as it allows
+ * specifying a default value to return if the attribute is not found.
+ *
+ * @see getAttributes()
+ * @param string $name The attribute name.
+ * @param mixed $default Default value to return if the attribute does not exist.
+ * @return mixed
+ */
+ public function getAttribute($name, $default = null)
+ {
+ return $this->attributes->get($name, $default);
+ }
+
+ /**
+ * Return an instance with the specified derived request attribute.
+ *
+ * This method allows setting a single derived request attribute as
+ * described in getAttributes().
+ *
+ * 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
+ * updated attribute.
+ *
+ * @see getAttributes()
+ * @param string $name The attribute name.
+ * @param mixed $value The value of the attribute.
+ * @return static
+ */
+ public function withAttribute($name, $value)
+ {
+ $new = clone $this;
+ $new->attributes = clone $this->attributes;
+
+ $new->attributes->set($name, $value);
+
+ return $new;
+ }
+
+ /**
+ * Return an instance that removes the specified derived request attribute.
+ *
+ * This method allows removing a single derived request attribute as
+ * described in getAttributes().
+ *
+ * This method MUST be implemented in such a way as to retain the
+ * immutability of the message, and MUST return an instance that removes
+ * the attribute.
+ *
+ * @see getAttributes()
+ * @param string $name The attribute name.
+ * @return static
+ */
+ public function withoutAttribute($name)
+ {
+ $new = clone $this;
+ $new->attributes = clone $this->attributes;
+
+ $new->attributes->remove($name);
+
+ return $new;
+ }
}
diff --git a/tests/Unit/Http/Psr7ServiceProviderTest.php b/tests/Unit/Http/Psr7ServiceProviderTest.php
index a09e9572..e14daf2a 100644
--- a/tests/Unit/Http/Psr7ServiceProviderTest.php
+++ b/tests/Unit/Http/Psr7ServiceProviderTest.php
@@ -50,11 +50,6 @@ class Psr7ServiceProviderTest extends ServiceProviderTest
[ResponseInterface::class, 'psr7.response']
);
- $psr7Factory->expects($this->once())
- ->method('createRequest')
- ->with($request)
- ->willReturn($psr7request);
-
$serviceProvider = new Psr7ServiceProvider($app);
$serviceProvider->register();
}
diff --git a/tests/Unit/Http/RequestTest.php b/tests/Unit/Http/RequestTest.php
index f7d69aff..916aac35 100644
--- a/tests/Unit/Http/RequestTest.php
+++ b/tests/Unit/Http/RequestTest.php
@@ -6,7 +6,9 @@ use Engelsystem\Http\Request;
use PHPUnit\Framework\TestCase;
use PHPUnit_Framework_MockObject_MockObject as MockObject;
use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\UploadedFileInterface;
use Psr\Http\Message\UriInterface;
+use Symfony\Component\HttpFoundation\File\UploadedFile as SymfonyFile;
use Symfony\Component\HttpFoundation\Request as SymfonyRequest;
class RequestTest extends TestCase
@@ -196,4 +198,185 @@ class RequestTest extends TestCase
$this->assertInstanceOf(UriInterface::class, $uri);
$this->assertEquals('http://lor.em/test?bla=foo', (string)$uri);
}
+
+ /**
+ * @covers \Engelsystem\Http\Request::getServerParams
+ */
+ public function testGetServerParams()
+ {
+ $server = ['foo' => 'bar'];
+ $request = new Request([], [], [], [], [], $server);
+
+ $this->assertEquals($server, $request->getServerParams());
+ }
+
+ /**
+ * @covers \Engelsystem\Http\Request::getCookieParams
+ */
+ public function testGetCookieParams()
+ {
+ $cookies = ['session' => 'LoremIpsumDolorSit'];
+ $request = new Request([], [], [], $cookies);
+
+ $this->assertEquals($cookies, $request->getCookieParams());
+ }
+
+ /**
+ * @covers \Engelsystem\Http\Request::withCookieParams
+ */
+ public function testWithCookieParams()
+ {
+ $cookies = ['lor' => 'em'];
+ $request = new Request();
+
+ $new = $request->withCookieParams($cookies);
+
+ $this->assertNotEquals($request, $new);
+ $this->assertEquals($cookies, $new->getCookieParams());
+ }
+
+ /**
+ * @covers \Engelsystem\Http\Request::getQueryParams
+ */
+ public function testGetQueryParams()
+ {
+ $params = ['foo' => 'baz'];
+ $request = new Request($params);
+
+ $this->assertEquals($params, $request->getQueryParams());
+ }
+
+ /**
+ * @covers \Engelsystem\Http\Request::withQueryParams
+ */
+ public function testWithQueryParams()
+ {
+ $params = ['test' => 'ing'];
+ $request = new Request();
+
+ $new = $request->withQueryParams($params);
+
+ $this->assertNotEquals($request, $new);
+ $this->assertEquals($params, $new->getQueryParams());
+ }
+
+ /**
+ * @covers \Engelsystem\Http\Request::getUploadedFiles
+ */
+ public function testGetUploadedFiles()
+ {
+ $filename = tempnam(sys_get_temp_dir(), 'test');
+ file_put_contents($filename, 'LoremIpsum!');
+ $files = [new SymfonyFile($filename, 'foo.html', 'text/html', 11)];
+ $request = new Request([], [], [], [], $files);
+
+ $uploadedFiles = $request->getUploadedFiles();
+ $this->assertNotEmpty($uploadedFiles);
+
+ /** @var UploadedFileInterface $file */
+ $file = $uploadedFiles[0];
+ $this->assertInstanceOf(UploadedFileInterface::class, $file);
+ $this->assertEquals('foo.html', $file->getClientFilename());
+ $this->assertEquals('text/html', $file->getClientMediaType());
+ $this->assertEquals(11, $file->getSize());
+ }
+
+ /**
+ * @covers \Engelsystem\Http\Request::withUploadedFiles
+ */
+ public function testWithUploadedFiles()
+ {
+ $filename = tempnam(sys_get_temp_dir(), 'test');
+ file_put_contents($filename, 'LoremIpsum!');
+ $file = new \Zend\Diactoros\UploadedFile($filename, 11, UPLOAD_ERR_OK, 'test.txt', 'text/plain');
+
+ $request = new Request();
+ $new = $request->withUploadedFiles([$file]);
+ $uploadedFiles = $new->getUploadedFiles();
+ $this->assertNotEquals($request, $new);
+ $this->assertNotEmpty($uploadedFiles);
+
+ /** @var UploadedFileInterface $file */
+ $file = $uploadedFiles[0];
+ $this->assertEquals('test.txt', $file->getClientFilename());
+ $this->assertEquals('text/plain', $file->getClientMediaType());
+ $this->assertEquals(11, $file->getSize());
+ }
+
+ /**
+ * @covers \Engelsystem\Http\Request::getParsedBody
+ */
+ public function testGetParsedBody()
+ {
+ $body = ['foo' => 'lorem'];
+ $request = new Request();
+ $request->request->add($body);
+
+ $this->assertEquals($body, $request->getParsedBody());
+ }
+
+ /**
+ * @covers \Engelsystem\Http\Request::withParsedBody
+ */
+ public function testWithParsedBody()
+ {
+ $data = ['test' => 'er'];
+ $request = new Request();
+
+ $new = $request->withParsedBody($data);
+
+ $this->assertNotEquals($request, $new);
+ $this->assertEquals($data, $new->getParsedBody());
+ }
+
+ /**
+ * @covers \Engelsystem\Http\Request::getAttributes
+ */
+ public function testGetAttributes()
+ {
+ $attributes = ['foo' => 'lorem', 'ipsum' => 'dolor'];
+ $request = new Request([], [], $attributes);
+
+ $this->assertEquals($attributes, $request->getAttributes());
+ }
+
+ /**
+ * @covers \Engelsystem\Http\Request::getAttribute
+ */
+ public function testGetAttribute()
+ {
+ $attributes = ['foo' => 'lorem', 'ipsum' => 'dolor'];
+ $request = new Request([], [], $attributes);
+
+ $this->assertEquals($attributes['ipsum'], $request->getAttribute('ipsum'));
+ $this->assertEquals(null, $request->getAttribute('dolor'));
+ $this->assertEquals(1234, $request->getAttribute('test', 1234));
+ }
+
+ /**
+ * @covers \Engelsystem\Http\Request::withAttribute
+ */
+ public function testWithAttribute()
+ {
+ $request = new Request();
+
+ $new = $request->withAttribute('lorem', 'ipsum');
+
+ $this->assertNotEquals($request, $new);
+ $this->assertEquals('ipsum', $new->getAttribute('lorem'));
+ }
+
+ /**
+ * @covers \Engelsystem\Http\Request::withoutAttribute
+ */
+ public function testWithoutAttribute()
+ {
+ $attributes = ['foo' => 'lorem', 'ipsum' => 'dolor'];
+ $request = new Request([], [], $attributes);
+
+ $new = $request->withoutAttribute('ipsum');
+
+ $this->assertNotEquals($request, $new);
+ $this->assertEquals(['foo' => 'lorem'], $new->getAttributes());
+ }
}