Refactor ServerRequestMarshaller and ServerRequest

This commit is contained in:
PJ Dietz 2020-08-16 08:52:33 -04:00
parent 20012dc671
commit 9243dd7663
3 changed files with 76 additions and 43 deletions

View File

@ -4,7 +4,9 @@ namespace WellRESTed\Message;
use InvalidArgumentException;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\StreamInterface;
use Psr\Http\Message\UploadedFileInterface;
use Psr\Http\Message\UriInterface;
/**
* Representation of an incoming, server-side HTTP request.
@ -51,9 +53,31 @@ class ServerRequest extends Request implements ServerRequestInterface
// -------------------------------------------------------------------------
public function __construct(array $serverParams = [])
{
parent::__construct();
/**
* Create a new ServerRequest.
*
* $headers is an optional associative array with header field names as
* string keys and values as either string or string[].
*
* If no StreamInterface is provided for $body, the instance will create
* a NullStream instance for the message body.
*
* @param string $method
* @param string|UriInterface $uri
* @param array $headers Associative array with header field names as
* keys and values as string|string[]
* @param StreamInterface|null $body A stream representation of the message
* entity body
* @param array $serverParams An array of Server API (SAPI) parameters
*/
public function __construct(
string $method = 'GET',
$uri = '',
array $headers = [],
?StreamInterface $body = null,
array $serverParams = []
){
parent::__construct($method, $uri, $headers, $body);
$this->serverParams = $serverParams;
$this->cookieParams = [];
$this->queryParams = [];

View File

@ -8,38 +8,28 @@ use Psr\Http\Message\UriInterface;
class ServerRequestMarshaller
{
public function getServerRequest(
?array $serverParams = null,
?array $cookieParams = null,
?array $queryParams = null,
?array $postParams = null,
?array $fileParams = null,
string $inputStream = 'php://input'
): ServerRequestInterface {
$serverParams = $serverParams ?? $_SERVER;
$cookieParams = $cookieParams ?? $_COOKIE;
$queryParams = $queryParams ?? self::parseQuery($serverParams);
$postParams = $postParams ?? $_POST;
$fileParams = $fileParams ?? $_FILES;
/**
* Read the request as sent from the client and construct a ServerRequest
* representation.
*
* @return ServerRequestInterface
* @internal
*/
public function getServerRequest(): ServerRequestInterface
{
$method = self::parseMethod($_SERVER);
$uri = self::readUri($_SERVER);
$headers = self::parseHeaders($_SERVER);
$body = self::readBody();
$request = new ServerRequest($serverParams);
$request = $request
->withProtocolVersion(self::parseProtocolVersion($serverParams))
->withMethod(self::parseMethod($serverParams))
->withBody(self::readBody($inputStream))
->withUri(self::readUri($serverParams))
->withUploadedFiles(self::readUploadedFiles($fileParams))
->withCookieParams($cookieParams)
->withQueryParams($queryParams);
$headers = self::parseHeaders($serverParams);
foreach ($headers as $name => $value) {
$request = $request->withAddedHeader($name, $value);
}
$request = (new ServerRequest($method, $uri, $headers, $body, $_SERVER))
->withProtocolVersion(self::parseProtocolVersion($_SERVER))
->withUploadedFiles(self::readUploadedFiles($_FILES))
->withCookieParams($_COOKIE)
->withQueryParams(self::parseQuery($_SERVER));
if (self::isForm($request)) {
$request = $request->withParsedBody($postParams);
$request = $request->withParsedBody($_POST);
}
return $request;
@ -95,9 +85,9 @@ class ServerRequestMarshaller
return $serverParams['REQUEST_METHOD'] ?? 'GET';
}
private static function readBody(string $inputStream): StreamInterface
private static function readBody(): StreamInterface
{
$input = fopen($inputStream, 'rb');
$input = fopen('php://input', 'rb');
$temp = fopen('php://temp', 'wb+');
stream_copy_to_stream($input, $temp);
rewind($temp);

View File

@ -28,6 +28,8 @@ class ServerRequestMarshallerTest extends TestCase
'hamster' => 'Dusty'
];
FopenHelper::$inputTempFile = null;
$this->marshaller = new ServerRequestMarshaller();
}
@ -103,15 +105,9 @@ class ServerRequestMarshallerTest extends TestCase
$tempFilePath = tempnam(sys_get_temp_dir(), 'test');
$content = 'Body content';
file_put_contents($tempFilePath, $content);
FopenHelper::$inputTempFile = $tempFilePath;
$request = $this->marshaller->getServerRequest(
null,
null,
null,
null,
null,
$tempFilePath
);
$request = $this->marshaller->getServerRequest();
unlink($tempFilePath);
$this->assertEquals($content, (string) $request->getBody());
@ -182,7 +178,8 @@ class ServerRequestMarshallerTest extends TestCase
*/
public function testProvidesUri(UriInterface $expected, array $serverParams): void
{
$request = $this->marshaller->getServerRequest($serverParams);
$_SERVER = $serverParams;
$request = $this->marshaller->getServerRequest();
$this->assertEquals($expected, $request->getUri());
}
@ -379,3 +376,25 @@ class ServerRequestMarshallerTest extends TestCase
];
}
}
// -----------------------------------------------------------------------------
// Declare fopen function in this namespace so the class under test will use
// this instead of the internal global functions during testing.
class FopenHelper
{
/**
* @var string Path to temp file to read in place of 'php://input'
*/
public static $inputTempFile;
}
function fopen($filename, $mode)
{
if (FopenHelper::$inputTempFile && $filename === 'php://input') {
$filename = FopenHelper::$inputTempFile;
}
return \fopen($filename, $mode);
}