Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[4.x] Add base path to $request and use RouteContext to read #2860

Merged
merged 5 commits into from Oct 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion Slim/App.php
Expand Up @@ -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);
Expand Down
24 changes: 22 additions & 2 deletions Slim/Routing/RouteContext.php
Expand Up @@ -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);
}

/**
Expand All @@ -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;
}

/**
Expand All @@ -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;
}
}
23 changes: 19 additions & 4 deletions Slim/Routing/RouteRunner.php
Expand Up @@ -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;
Expand All @@ -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;
}

/**
Expand All @@ -60,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);
Expand Down
21 changes: 21 additions & 0 deletions tests/Routing/RouteContextTest.php
Expand Up @@ -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;
Expand All @@ -25,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);
Expand All @@ -34,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
Expand All @@ -47,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
Expand Down Expand Up @@ -76,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);
Expand Down