Skip to content

Commit

Permalink
Merge pull request #3132 from adoy/request-response-namedarg-strategy
Browse files Browse the repository at this point in the history
Add new `RequestResponseNamedArgs` route strategy
  • Loading branch information
l0gicgate authored Jan 14, 2022
2 parents 6aa522d + 65b1ad4 commit 0c6c36b
Show file tree
Hide file tree
Showing 3 changed files with 260 additions and 1 deletion.
49 changes: 49 additions & 0 deletions Slim/Handlers/Strategies/RequestResponseNamedArgs.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/

declare(strict_types=1);

namespace Slim\Handlers\Strategies;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Slim\Interfaces\InvocationStrategyInterface;
use RuntimeException;

/**
* Route callback strategy with route parameters as individual arguments.
*/
class RequestResponseNamedArgs implements InvocationStrategyInterface
{
public function __construct()
{
if (PHP_VERSION_ID < 80000) {
throw new RuntimeException('Named arguments are only available for PHP >= 8.0.0');
}
}

/**
* Invoke a route callable with request, response and all route parameters
* as individual arguments.
*
* @param callable $callable
* @param ServerRequestInterface $request
* @param ResponseInterface $response
* @param array<string, string> $routeArguments
*
* @return ResponseInterface
*/
public function __invoke(
callable $callable,
ServerRequestInterface $request,
ResponseInterface $response,
array $routeArguments
): ResponseInterface {
return $callable($request, $response, ...$routeArguments);
}
}
51 changes: 50 additions & 1 deletion tests/AppTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
use Slim\Exception\HttpMethodNotAllowedException;
use Slim\Exception\HttpNotFoundException;
use Slim\Handlers\Strategies\RequestResponseArgs;
use Slim\Handlers\Strategies\RequestResponseNamedArgs;
use Slim\Interfaces\CallableResolverInterface;
use Slim\Interfaces\MiddlewareDispatcherInterface;
use Slim\Interfaces\RouteCollectorInterface;
Expand Down Expand Up @@ -1214,7 +1215,7 @@ public function testInvokeWithMatchingRouteWithSetArguments()
$this->assertEquals('Hello World', (string) $response->getBody());
}

public function testInvokeWithMatchingRouteWithNamedParameter()
public function testInvokeWithMatchingRouteWithNamedParameterRequestResponseStrategy()
{
$streamProphecy = $this->prophesize(StreamInterface::class);
$streamProphecy->__toString()->willReturn('');
Expand Down Expand Up @@ -1295,6 +1296,54 @@ public function testInvokeWithMatchingRouteWithNamedParameterRequestResponseArgS
$this->assertEquals('Hello World', (string) $response->getBody());
}

public function testInvokeWithMatchingRouteWithNamedParameterRequestResponseNamedArgsStrategy()
{
if (PHP_VERSION_ID < 80000) {
$this->markTestSkipped('Named arguments are not supported in PHP versions prior to 8.0');
}

$streamProphecy = $this->prophesize(StreamInterface::class);
$streamProphecy->__toString()->willReturn('');
$streamProphecy->write(Argument::type('string'))->will(function ($args) {
$body = $this->reveal()->__toString();
$body .= $args[0];
$this->__toString()->willReturn($body);
});

$responseProphecy = $this->prophesize(ResponseInterface::class);
$responseProphecy->getBody()->willReturn($streamProphecy->reveal());

$responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class);
$responseFactoryProphecy->createResponse()->willReturn($responseProphecy->reveal());

$app = new App($responseFactoryProphecy->reveal());
$app->getRouteCollector()->setDefaultInvocationStrategy(new RequestResponseNamedArgs());
$app->get(
'/{greeting}/{name}',
function (ServerRequestInterface $request, ResponseInterface $response, $name, $greeting) {
$response->getBody()->write("{$greeting} {$name}");
return $response;
}
);

$uriProphecy = $this->prophesize(UriInterface::class);
$uriProphecy->getPath()->willReturn('/Hello/World');

$requestProphecy = $this->prophesize(ServerRequestInterface::class);
$requestProphecy->getMethod()->willReturn('GET');
$requestProphecy->getUri()->willReturn($uriProphecy->reveal());
$requestProphecy->getAttribute(RouteContext::ROUTING_RESULTS)->willReturn(null);
$requestProphecy->withAttribute(Argument::type('string'), Argument::any())->will(function ($args) {
$this->getAttribute($args[0])->willReturn($args[1]);
return $this;
});

$response = $app->handle($requestProphecy->reveal());

$this->assertInstanceOf(ResponseInterface::class, $response);
$this->assertEquals('Hello World', (string) $response->getBody());
}

public function testInvokeWithMatchingRouteWithNamedParameterOverwritesSetArgument()
{
$streamProphecy = $this->prophesize(StreamInterface::class);
Expand Down
161 changes: 161 additions & 0 deletions tests/Handlers/Strategies/RequestResponseNamedArgsTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
<?php

/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/

declare(strict_types=1);

namespace Slim\Tests\Handlers\Strategies;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use RuntimeException;
use Slim\Handlers\Strategies\RequestResponseNamedArgs;
use Slim\Tests\TestCase;

class RequestResponseNamedArgsTest extends TestCase
{
private ServerRequestInterface $request;
private ResponseInterface $response;

public function setUp(): void
{
$this->request = $this->createMock(ServerRequestInterface::class);
$this->response = $this->createMock(ResponseInterface::class);
}

public function testCreatingRequestResponseNamedArgsThrowsRuntimeExceptionForPHPOlderThan80()
{
if (PHP_VERSION_ID >= 80000) {
$this->markTestSkipped('Test only valid for PHP versions older than 8.0');
}

$this->expectException(RuntimeException::class);
new RequestResponseNamedArgs();
}

public function testCallingWithEmptyArguments()
{
if (PHP_VERSION_ID < 80000) {
$this->markTestSkipped('Named arguments are not supported in PHP versions prior to 8.0');
}

$args = [];
$invocationStrategy = new RequestResponseNamedArgs();

$callback = function ($request, $response) {
$this->assertSame($this->request, $request);
$this->assertSame($this->response, $response);

return $response;
};

$this->assertSame($this->response, $invocationStrategy($callback, $this->request, $this->response, $args));
}

public function testCallingWithKnownArguments()
{
if (PHP_VERSION_ID < 80000) {
$this->markTestSkipped('Named arguments are not supported in PHP versions prior to 8.0');
}

$args = [
'name' => 'world',
'greeting' => 'hello',
];

$invocationStrategy = new RequestResponseNamedArgs();

$callback = function ($request, $response, $greeting, $name) use ($args) {
$this->assertSame($this->request, $request);
$this->assertSame($this->response, $response);
$this->assertSame($greeting, $args['greeting']);
$this->assertSame($name, $args['name']);

return $response;
};

$this->assertSame($this->response, $invocationStrategy($callback, $this->request, $this->response, $args));
}

public function testCallingWithOptionalArguments()
{
if (PHP_VERSION_ID < 80000) {
$this->markTestSkipped('Named arguments are not supported in PHP versions prior to 8.0');
}

$args = [
'name' => 'world',
];

$invocationStrategy = new RequestResponseNamedArgs();

$callback = function ($request, $response, $greeting = 'Hello', $name = 'Rob') use ($args) {
$this->assertSame($this->request, $request);
$this->assertSame($this->response, $response);
$this->assertSame($greeting, 'Hello');
$this->assertSame($name, $args['name']);

return $response;
};

$this->assertSame($this->response, $invocationStrategy($callback, $this->request, $this->response, $args));
}

public function testCallingWithUnknownAndVariadic()
{
if (PHP_VERSION_ID < 80000) {
$this->markTestSkipped('Named arguments are not supported in PHP versions prior to 8.0');
}

$args = [
'name' => 'world',
'greeting' => 'hello',
];

$invocationStrategy = new RequestResponseNamedArgs();

$callback = function ($request, $response, ...$arguments) use ($args) {
$this->assertSame($this->request, $request);
$this->assertSame($this->response, $response);
$this->assertSame($args, $arguments);

return $response;
};

$this->assertSame($this->response, $invocationStrategy($callback, $this->request, $this->response, $args));
}

public function testCallingWithMixedKnownAndUnknownParametersAndVariadic()
{
if (PHP_VERSION_ID < 80000) {
$this->markTestSkipped('Named arguments are not supported in PHP versions prior to 8.0');
}

$known = [
'name' => 'world',
'greeting' => 'hello',
];
$unknown = [
'foo' => 'foo',
'bar' => 'bar',
];
$args = array_merge($known, $unknown);
$invocationStrategy = new RequestResponseNamedArgs();

$callback = function ($request, $response, $name, $greeting, ...$arguments) use ($known, $unknown) {
$this->assertSame($this->request, $request);
$this->assertSame($this->response, $response);
$this->assertSame($name, $known['name']);
$this->assertSame($greeting, $known['greeting']);
$this->assertSame($unknown, $arguments);

return $response;
};

$this->assertSame($this->response, $invocationStrategy($callback, $this->request, $this->response, $args));
}
}

0 comments on commit 0c6c36b

Please sign in to comment.