From d0072c271f72bb6742942a4d0984d2fccc1a3eec Mon Sep 17 00:00:00 2001 From: Adrian Suter Date: Fri, 4 Oct 2019 22:28:18 +0200 Subject: [PATCH 1/4] Pass app to the route runner --- Slim/App.php | 2 +- Slim/Routing/RouteRunner.php | 19 +++++++++++++++---- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/Slim/App.php b/Slim/App.php index 0ce4094c5..47ce67093 100644 --- a/Slim/App.php +++ b/Slim/App.php @@ -70,7 +70,7 @@ public function __construct( ); $this->routeResolver = $routeResolver ?? new RouteResolver($this->routeCollector); - $routeRunner = new RouteRunner($this->routeResolver, $this->routeCollector->getRouteParser()); + $routeRunner = new RouteRunner($this->routeResolver, $this->routeCollector->getRouteParser(), $this); if (!$middlewareDispatcher) { $middlewareDispatcher = new MiddlewareDispatcher($routeRunner, $this->callableResolver, $container); diff --git a/Slim/Routing/RouteRunner.php b/Slim/Routing/RouteRunner.php index aaf7f9883..4de18bc51 100644 --- a/Slim/Routing/RouteRunner.php +++ b/Slim/Routing/RouteRunner.php @@ -14,6 +14,7 @@ use Psr\Http\Server\RequestHandlerInterface; use Slim\Exception\HttpMethodNotAllowedException; use Slim\Exception\HttpNotFoundException; +use Slim\Interfaces\RouteCollectorProxyInterface; use Slim\Interfaces\RouteParserInterface; use Slim\Interfaces\RouteResolverInterface; use Slim\Middleware\RoutingMiddleware; @@ -31,13 +32,23 @@ class RouteRunner implements RequestHandlerInterface private $routeParser; /** - * @param RouteResolverInterface $routeResolver - * @param RouteParserInterface $routeParser + * @var RouteCollectorProxyInterface|null */ - public function __construct(RouteResolverInterface $routeResolver, RouteParserInterface $routeParser) - { + private $routeCollectorProxy; + + /** + * @param RouteResolverInterface $routeResolver + * @param RouteParserInterface $routeParser + * @param RouteCollectorProxyInterface|null $routeCollectorProxy + */ + public function __construct( + RouteResolverInterface $routeResolver, + RouteParserInterface $routeParser, + ?RouteCollectorProxyInterface $routeCollectorProxy = null + ) { $this->routeResolver = $routeResolver; $this->routeParser = $routeParser; + $this->routeCollectorProxy = $routeCollectorProxy; } /** From 4d31c8b6f7f854a03b7b31b4c706b14636febda3 Mon Sep 17 00:00:00 2001 From: Adrian Suter Date: Fri, 4 Oct 2019 22:28:44 +0200 Subject: [PATCH 2/4] Add base path to request attributes --- Slim/Routing/RouteRunner.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Slim/Routing/RouteRunner.php b/Slim/Routing/RouteRunner.php index 4de18bc51..ff9e6f0db 100644 --- a/Slim/Routing/RouteRunner.php +++ b/Slim/Routing/RouteRunner.php @@ -71,6 +71,10 @@ public function handle(ServerRequestInterface $request): ResponseInterface $request = $routingMiddleware->performRouting($request); } + if ($this->routeCollectorProxy !== null) { + $request = $request->withAttribute('basePath', $this->routeCollectorProxy->getBasePath()); + } + /** @var Route $route */ $route = $request->getAttribute('route'); return $route->run($request); From f5faf0cc155094110d04dcea34409a473b177899 Mon Sep 17 00:00:00 2001 From: Adrian Suter Date: Fri, 4 Oct 2019 22:29:17 +0200 Subject: [PATCH 3/4] Add `getBasePath()` method --- Slim/Routing/RouteContext.php | 24 ++++++++++++++++++++++-- tests/Routing/RouteContextTest.php | 20 ++++++++++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/Slim/Routing/RouteContext.php b/Slim/Routing/RouteContext.php index 93b4e4cf0..5005da46c 100644 --- a/Slim/Routing/RouteContext.php +++ b/Slim/Routing/RouteContext.php @@ -25,12 +25,13 @@ public static function fromRequest(ServerRequestInterface $serverRequest): self $route = $serverRequest->getAttribute('route'); $routeParser = $serverRequest->getAttribute('routeParser'); $routingResults = $serverRequest->getAttribute('routingResults'); + $basePath = $serverRequest->getAttribute('basePath'); if ($routeParser === null || $routingResults === null) { throw new RuntimeException('Cannot create RouteContext before routing has been completed'); } - return new self($route, $routeParser, $routingResults); + return new self($route, $routeParser, $routingResults, $basePath); } /** @@ -48,19 +49,27 @@ public static function fromRequest(ServerRequestInterface $serverRequest): self */ private $routingResults; + /** + * @var string|null + */ + private $basePath; + /** * @param RouteInterface|null $route * @param RouteParserInterface $routeParser * @param RoutingResults $routingResults + * @param string|null $basePath */ private function __construct( ?RouteInterface $route, RouteParserInterface $routeParser, - RoutingResults $routingResults + RoutingResults $routingResults, + ?string $basePath = null ) { $this->route = $route; $this->routeParser = $routeParser; $this->routingResults = $routingResults; + $this->basePath = $basePath; } /** @@ -86,4 +95,15 @@ public function getRoutingResults(): RoutingResults { return $this->routingResults; } + + /** + * @return string + */ + public function getBasePath(): string + { + if ($this->basePath === null) { + throw new RuntimeException('No base path defined.'); + } + return $this->basePath; + } } diff --git a/tests/Routing/RouteContextTest.php b/tests/Routing/RouteContextTest.php index 81fb66cb7..53b8f3b75 100644 --- a/tests/Routing/RouteContextTest.php +++ b/tests/Routing/RouteContextTest.php @@ -26,6 +26,7 @@ public function testCanCreateInstanceFromServerRequest(): void $routingResults = $this->createMock(RoutingResults::class); $serverRequest = $this->createServerRequest('/') + ->withAttribute('basePath', '') ->withAttribute('route', $route) ->withAttribute('routeParser', $routeParser) ->withAttribute('routingResults', $routingResults); @@ -35,6 +36,7 @@ public function testCanCreateInstanceFromServerRequest(): void $this->assertSame($route, $routeContext->getRoute()); $this->assertSame($routeParser, $routeContext->getRouteParser()); $this->assertSame($routingResults, $routeContext->getRoutingResults()); + $this->assertSame('', $routeContext->getBasePath()); } public function testCanCreateInstanceWithoutRoute(): void @@ -48,6 +50,23 @@ public function testCanCreateInstanceWithoutRoute(): void $this->assertNull($routeContext->getRoute()); $this->assertNotNull($routeContext->getRouteParser()); $this->assertNotNull($routeContext->getRoutingResults()); + $this->assertNotNull($routeContext->getBasePath()); + } + + public function testCanCreateInstanceWithoutBasePathAndThrowExceptionIfGetBasePathIsCalled(): void + { + $serverRequest = $this->createServerRequestWithRouteAttributes(); + + // Route attribute is not required + $serverRequest = $serverRequest->withoutAttribute('basePath'); + + $routeContext = RouteContext::fromRequest($serverRequest); + $this->assertNotNull($routeContext->getRoute()); + $this->assertNotNull($routeContext->getRouteParser()); + $this->assertNotNull($routeContext->getRoutingResults()); + + $this->expectException(RuntimeException::class); + $routeContext->getBasePath(); } public function requiredRouteContextRequestAttributes(): array @@ -77,6 +96,7 @@ private function createServerRequestWithRouteAttributes(): ServerRequestInterfac $routingResults = $this->createMock(RoutingResults::class); return $this->createServerRequest('/') + ->withAttribute('basePath', '') ->withAttribute('route', $route) ->withAttribute('routeParser', $routeParser) ->withAttribute('routingResults', $routingResults); From de91cf01c1e86da366772510806aaa7c2535c497 Mon Sep 17 00:00:00 2001 From: Adrian Suter Date: Fri, 4 Oct 2019 22:39:02 +0200 Subject: [PATCH 4/4] Use RuntimeException --- tests/Routing/RouteContextTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Routing/RouteContextTest.php b/tests/Routing/RouteContextTest.php index 8a5492247..53b8f3b75 100644 --- a/tests/Routing/RouteContextTest.php +++ b/tests/Routing/RouteContextTest.php @@ -10,6 +10,7 @@ namespace Slim\Tests\Routing; use Psr\Http\Message\ServerRequestInterface; +use RuntimeException; use Slim\Interfaces\RouteInterface; use Slim\Interfaces\RouteParserInterface; use Slim\Routing\RouteContext;