From 168881d33491b442c0c28bef69e4f8ee8e16b250 Mon Sep 17 00:00:00 2001 From: sheridans Date: Thu, 8 Apr 2021 19:59:10 +0100 Subject: [PATCH 1/7] Inject request interface into helper Signed-off-by: sheridans --- src/UrlHelperMiddleware.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/UrlHelperMiddleware.php b/src/UrlHelperMiddleware.php index 2bb4f89..dba7d5f 100644 --- a/src/UrlHelperMiddleware.php +++ b/src/UrlHelperMiddleware.php @@ -32,11 +32,15 @@ public function __construct(UrlHelper $helper) } /** + * Inject the helper with the request instance. + * * Inject the UrlHelper instance with a RouteResult, if present as a request attribute. * Injects the helper, and then dispatches the next middleware. */ public function process(ServerRequestInterface $request, RequestHandlerInterface $handler) : ResponseInterface { + $this->helper->setRequest($request); + $result = $request->getAttribute(RouteResult::class, false); if ($result instanceof RouteResult) { From 552ec65239dc3cd5be72ea5fb2ba040cc01ab2c7 Mon Sep 17 00:00:00 2001 From: sheridans Date: Thu, 8 Apr 2021 19:59:52 +0100 Subject: [PATCH 2/7] Allow passing 'reuse_query_params' as option to merge request query params Signed-off-by: sheridans --- src/UrlHelper.php | 59 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/src/UrlHelper.php b/src/UrlHelper.php index 4945270..6bd393e 100644 --- a/src/UrlHelper.php +++ b/src/UrlHelper.php @@ -13,6 +13,7 @@ use InvalidArgumentException; use Mezzio\Router\RouteResult; use Mezzio\Router\RouterInterface; +use Psr\Http\Message\ServerRequestInterface; use function array_merge; use function count; @@ -40,6 +41,11 @@ class UrlHelper */ private $result; + /** + * @var ServerRequestInterface + */ + private $request; + /** * @var RouterInterface */ @@ -102,6 +108,13 @@ public function __invoke( $routeParams = $this->mergeParams($routeName, $result, $routeParams); } + $reuseQueryParams = ! isset($options['reuse_query_params']) || (bool) $options['reuse_query_params']; + + if ($result && $reuseQueryParams) { + // Merge current request params with passed query params + $queryParams = $this->mergeQueryParams($routeName, $result, $queryParams); + } + // Generate the route $path = $basePath . $this->router->generateUri($routeName, $routeParams, $routerOptions); @@ -153,6 +166,19 @@ public function getRouteResult() : ?RouteResult return $this->result; } + /** + * Set request instance + */ + public function setRequest(ServerRequestInterface $request) : void + { + $this->request = $request; + } + + public function getRequest() : ?ServerRequestInterface + { + return $this->request; + } + /** * Internal accessor for retrieving the base path. */ @@ -190,7 +216,9 @@ private function generateUriFromResult(array $params, RouteResult $result, array * invocation, with the latter having precedence. * * @param string $route Route name. - * @param array $params Parameters provided at invocation. + * @param RouteResult $result RouteResult instance + * @param array $params Route parameters + * @return array Merged parameters */ private function mergeParams(string $route, RouteResult $result, array $params) : array { @@ -205,6 +233,35 @@ private function mergeParams(string $route, RouteResult $result, array $params) return array_merge($result->getMatchedParams(), $params); } + /** + * Merge requested route query params with existing request query parameters. + * + * If route result represents routing failure, returns the params verbatim + * + * If the route result does not represent the same route name requested, + * returns the params verbatim. + * + * Otherwise, merges the current request query parameters with the specified query + * parameters with the latter having precedence. + * + * @param string $route Route name + * @param RouteResult $result RouteResult instance + * @param array $params Params to be merged with request params + * @return array + */ + private function mergeQueryParams(string $route, RouteResult $result, array $params) : array + { + if ($result->isFailure()) { + return $params; + } + + if ($result->getMatchedRouteName() !== $route) { + return $params; + } + + return array_merge($this->getRequest()->getQueryParams(), $params); + } + /** * Append query string arguments to a URI string, if any are present. */ From 327c05e5d8ab5419875cf8fc11866846a1edce5a Mon Sep 17 00:00:00 2001 From: sheridans Date: Fri, 9 Apr 2021 12:49:44 +0100 Subject: [PATCH 3/7] Inject request object into createHelper Signed-off-by: sheridans --- test/UrlHelperTest.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/test/UrlHelperTest.php b/test/UrlHelperTest.php index 7b82107..ad77afa 100644 --- a/test/UrlHelperTest.php +++ b/test/UrlHelperTest.php @@ -21,6 +21,7 @@ use PHPUnit\Framework\TestCase; use Prophecy\PhpUnit\ProphecyTrait; use Prophecy\Prophecy\ObjectProphecy; +use Psr\Http\Message\ServerRequestInterface; use ReflectionProperty; use stdClass; use TypeError; @@ -43,7 +44,12 @@ public function setUp(): void public function createHelper() { - return new UrlHelper($this->router->reveal()); + $request = $this->prophesize(ServerRequestInterface::class); + $request->getQueryParams()->willReturn([]); + + $helper = new UrlHelper($this->router->reveal()); + $helper->setRequest($request->reveal()); + return $helper; } public function testRaisesExceptionOnInvocationIfNoRouteProvidedAndNoResultPresent() From 60e4aefc3a1052b317a42410a2c452611c9549e4 Mon Sep 17 00:00:00 2001 From: sheridans Date: Fri, 9 Apr 2021 12:55:16 +0100 Subject: [PATCH 4/7] Inject request object into helper creation Signed-off-by: sheridans --- test/UrlHelperMiddlewareTest.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/UrlHelperMiddlewareTest.php b/test/UrlHelperMiddlewareTest.php index 3d2f5d1..1653f22 100644 --- a/test/UrlHelperMiddlewareTest.php +++ b/test/UrlHelperMiddlewareTest.php @@ -33,6 +33,11 @@ class UrlHelperMiddlewareTest extends TestCase public function setUp(): void { $this->helper = $this->prophesize(UrlHelper::class); + + $request = $this->prophesize(ServerRequestInterface::class); + $request->getQueryparams()->willReturn([]); + + $this->helper->setRequest($request->reveal()); } public function createMiddleware() From 3162480617d9ac172e60b750a5d55caa73386fdd Mon Sep 17 00:00:00 2001 From: sheridans Date: Fri, 9 Apr 2021 14:12:39 +0100 Subject: [PATCH 5/7] Added helper request instance to tests Signed-off-by: sheridans --- test/UrlHelperMiddlewareTest.php | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/test/UrlHelperMiddlewareTest.php b/test/UrlHelperMiddlewareTest.php index 1653f22..c78dd42 100644 --- a/test/UrlHelperMiddlewareTest.php +++ b/test/UrlHelperMiddlewareTest.php @@ -33,11 +33,6 @@ class UrlHelperMiddlewareTest extends TestCase public function setUp(): void { $this->helper = $this->prophesize(UrlHelper::class); - - $request = $this->prophesize(ServerRequestInterface::class); - $request->getQueryparams()->willReturn([]); - - $this->helper->setRequest($request->reveal()); } public function createMiddleware() @@ -53,6 +48,7 @@ public function testInvocationInjectsHelperWithRouteResultWhenPresentInRequest() $request = $this->prophesize(ServerRequestInterface::class); $request->getAttribute(RouteResult::class, false)->willReturn($routeResult); $this->helper->setRouteResult($routeResult)->shouldBeCalled(); + $this->helper->setRequest($request)->shouldBeCalled(); $handler = $this->prophesize(RequestHandlerInterface::class); $handler->handle(Argument::type(ServerRequestInterface::class))->will([$response, 'reveal']); @@ -70,6 +66,7 @@ public function testInvocationDoesNotInjectHelperWithRouteResultWhenAbsentInRequ $request = $this->prophesize(ServerRequestInterface::class); $request->getAttribute(RouteResult::class, false)->willReturn(false); + $this->helper->setRequest($request)->shouldBeCalled(); $this->helper->setRouteResult(Argument::any())->shouldNotBeCalled(); $handler = $this->prophesize(RequestHandlerInterface::class); From e2b5290c81f3d4b72e6f9546e96b39f1117c60ce Mon Sep 17 00:00:00 2001 From: sheridans Date: Fri, 9 Apr 2021 14:44:44 +0100 Subject: [PATCH 6/7] Added tests relating to 'reuse_query_params' Signed-off-by: sheridans --- test/UrlHelperTest.php | 77 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/test/UrlHelperTest.php b/test/UrlHelperTest.php index ad77afa..28a1951 100644 --- a/test/UrlHelperTest.php +++ b/test/UrlHelperTest.php @@ -22,6 +22,7 @@ use Prophecy\PhpUnit\ProphecyTrait; use Prophecy\Prophecy\ObjectProphecy; use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Server\RequestHandlerInterface; use ReflectionProperty; use stdClass; use TypeError; @@ -404,6 +405,82 @@ public function testGetRouteResultWithRouteResultSet() $this->assertInstanceOf(RouteResult::class, $helper->getRouteResult()); } + public function testWillNotReuseQueryParamsIfReuseQueryParamsFlagIsFalseWhenGeneratingUri() + { + $result = $this->prophesize(RouteResult::class); + $result->isFailure()->willReturn(false); + $result->getMatchedRouteName()->willReturn('resource'); + $result->getMatchedParams()->willReturn([]); + + $this->router->generateUri('resource', [], [])->willReturn('URL'); + + $request = $this->prophesize(ServerRequestInterface::class); + $request->getQueryParams()->wilLReturn(['foo' => 'bar']); + + $helper = $this->createHelper(); + $helper->setRouteResult($result->reveal()); + $helper->setRequest($request->reveal()); + + $this->assertEquals('URL', $helper('resource', [], [], null, ['reuse_query_params' => false])); + } + + public function testWillReuseQueryParamsIfReuseQueryParamsFlagIsTrueWhenGeneratingUri() + { + $result = $this->prophesize(RouteResult::class); + $result->isFailure()->willReturn(false); + $result->getMatchedRouteName()->willReturn('resource'); + $result->getMatchedParams()->willReturn([]); + + $this->router->generateUri('resource', [], [])->willReturn('URL'); + + $request = $this->prophesize(ServerRequestInterface::class); + $request->getQueryParams()->wilLReturn(['foo' => 'bar']); + + $helper = $this->createHelper(); + $helper->setRouteResult($result->reveal()); + $helper->setRequest($request->reveal()); + + $this->assertEquals('URL?foo=bar', $helper('resource', [], [], null, ['reuse_query_params' => true])); + } + + public function testWillReuseQueryParamsIfReuseQueryParamsFlagIsMissingGeneratingUri() + { + $result = $this->prophesize(RouteResult::class); + $result->isFailure()->willReturn(false); + $result->getMatchedRouteName()->willReturn('resource'); + $result->getMatchedParams()->willReturn([]); + + $this->router->generateUri('resource', [], [])->willReturn('URL'); + + $request = $this->prophesize(ServerRequestInterface::class); + $request->getQueryParams()->wilLReturn(['foo' => 'bar']); + + $helper = $this->createHelper(); + $helper->setRouteResult($result->reveal()); + $helper->setRequest($request->reveal()); + + $this->assertEquals('URL?foo=bar', $helper('resource')); + } + + public function testCanOverrideRequestQueryParams() + { + $result = $this->prophesize(RouteResult::class); + $result->isFailure()->willReturn(false); + $result->getMatchedRouteName()->willReturn('resource'); + $result->getMatchedParams()->willReturn([]); + + $this->router->generateUri('resource', [], [])->willReturn('URL'); + + $request = $this->prophesize(ServerRequestInterface::class); + $request->getQueryParams()->wilLReturn(['foo' => 'bar']); + + $helper = $this->createHelper(); + $helper->setRouteResult($result->reveal()); + $helper->setRequest($request->reveal()); + + $this->assertEquals('URL?foo=foo', $helper('resource', [], ['foo' => 'foo'])); + } + private function assertAttributeSame($expected, $attribute, $object) { $r = new ReflectionProperty($object, $attribute); From 2a32eab3f92d8de7dde00c2499ecd91154613da5 Mon Sep 17 00:00:00 2001 From: sheridans Date: Fri, 9 Apr 2021 15:11:43 +0100 Subject: [PATCH 7/7] Added tests relating to 'reuse_query_params' Signed-off-by: sheridans --- test/UrlHelperTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/UrlHelperTest.php b/test/UrlHelperTest.php index 28a1951..58d65be 100644 --- a/test/UrlHelperTest.php +++ b/test/UrlHelperTest.php @@ -238,7 +238,7 @@ public function testGenerateProxiesToInvokeMethod() $fragmentIdentifier = 'foobar'; $options = ['router' => ['foobar' => 'baz'], 'reuse_result_params' => false]; - $helper = Mockery::mock(UrlHelper::class)->shouldDeferMissing(); + $helper = Mockery::mock(UrlHelper::class)->makePartial(); $helper->shouldReceive('__invoke') ->once() ->with($routeName, $routeParams, $queryParams, $fragmentIdentifier, $options)