Skip to content

Commit 3224271

Browse files
authored
Merge pull request #2860 from adriansuter/patch-route-context-base-path
[4.x] Add base path to `$request` and use `RouteContext` to read
2 parents 80a52f7 + de91cf0 commit 3224271

File tree

4 files changed

+63
-7
lines changed

4 files changed

+63
-7
lines changed

Slim/App.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public function __construct(
7070
);
7171

7272
$this->routeResolver = $routeResolver ?? new RouteResolver($this->routeCollector);
73-
$routeRunner = new RouteRunner($this->routeResolver, $this->routeCollector->getRouteParser());
73+
$routeRunner = new RouteRunner($this->routeResolver, $this->routeCollector->getRouteParser(), $this);
7474

7575
if (!$middlewareDispatcher) {
7676
$middlewareDispatcher = new MiddlewareDispatcher($routeRunner, $this->callableResolver, $container);

Slim/Routing/RouteContext.php

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,13 @@ public static function fromRequest(ServerRequestInterface $serverRequest): self
2525
$route = $serverRequest->getAttribute('route');
2626
$routeParser = $serverRequest->getAttribute('routeParser');
2727
$routingResults = $serverRequest->getAttribute('routingResults');
28+
$basePath = $serverRequest->getAttribute('basePath');
2829

2930
if ($routeParser === null || $routingResults === null) {
3031
throw new RuntimeException('Cannot create RouteContext before routing has been completed');
3132
}
3233

33-
return new self($route, $routeParser, $routingResults);
34+
return new self($route, $routeParser, $routingResults, $basePath);
3435
}
3536

3637
/**
@@ -48,19 +49,27 @@ public static function fromRequest(ServerRequestInterface $serverRequest): self
4849
*/
4950
private $routingResults;
5051

52+
/**
53+
* @var string|null
54+
*/
55+
private $basePath;
56+
5157
/**
5258
* @param RouteInterface|null $route
5359
* @param RouteParserInterface $routeParser
5460
* @param RoutingResults $routingResults
61+
* @param string|null $basePath
5562
*/
5663
private function __construct(
5764
?RouteInterface $route,
5865
RouteParserInterface $routeParser,
59-
RoutingResults $routingResults
66+
RoutingResults $routingResults,
67+
?string $basePath = null
6068
) {
6169
$this->route = $route;
6270
$this->routeParser = $routeParser;
6371
$this->routingResults = $routingResults;
72+
$this->basePath = $basePath;
6473
}
6574

6675
/**
@@ -86,4 +95,15 @@ public function getRoutingResults(): RoutingResults
8695
{
8796
return $this->routingResults;
8897
}
98+
99+
/**
100+
* @return string
101+
*/
102+
public function getBasePath(): string
103+
{
104+
if ($this->basePath === null) {
105+
throw new RuntimeException('No base path defined.');
106+
}
107+
return $this->basePath;
108+
}
89109
}

Slim/Routing/RouteRunner.php

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use Psr\Http\Server\RequestHandlerInterface;
1515
use Slim\Exception\HttpMethodNotAllowedException;
1616
use Slim\Exception\HttpNotFoundException;
17+
use Slim\Interfaces\RouteCollectorProxyInterface;
1718
use Slim\Interfaces\RouteParserInterface;
1819
use Slim\Interfaces\RouteResolverInterface;
1920
use Slim\Middleware\RoutingMiddleware;
@@ -31,13 +32,23 @@ class RouteRunner implements RequestHandlerInterface
3132
private $routeParser;
3233

3334
/**
34-
* @param RouteResolverInterface $routeResolver
35-
* @param RouteParserInterface $routeParser
35+
* @var RouteCollectorProxyInterface|null
3636
*/
37-
public function __construct(RouteResolverInterface $routeResolver, RouteParserInterface $routeParser)
38-
{
37+
private $routeCollectorProxy;
38+
39+
/**
40+
* @param RouteResolverInterface $routeResolver
41+
* @param RouteParserInterface $routeParser
42+
* @param RouteCollectorProxyInterface|null $routeCollectorProxy
43+
*/
44+
public function __construct(
45+
RouteResolverInterface $routeResolver,
46+
RouteParserInterface $routeParser,
47+
?RouteCollectorProxyInterface $routeCollectorProxy = null
48+
) {
3949
$this->routeResolver = $routeResolver;
4050
$this->routeParser = $routeParser;
51+
$this->routeCollectorProxy = $routeCollectorProxy;
4152
}
4253

4354
/**
@@ -60,6 +71,10 @@ public function handle(ServerRequestInterface $request): ResponseInterface
6071
$request = $routingMiddleware->performRouting($request);
6172
}
6273

74+
if ($this->routeCollectorProxy !== null) {
75+
$request = $request->withAttribute('basePath', $this->routeCollectorProxy->getBasePath());
76+
}
77+
6378
/** @var Route $route */
6479
$route = $request->getAttribute('route');
6580
return $route->run($request);

tests/Routing/RouteContextTest.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
namespace Slim\Tests\Routing;
1111

1212
use Psr\Http\Message\ServerRequestInterface;
13+
use RuntimeException;
1314
use Slim\Interfaces\RouteInterface;
1415
use Slim\Interfaces\RouteParserInterface;
1516
use Slim\Routing\RouteContext;
@@ -25,6 +26,7 @@ public function testCanCreateInstanceFromServerRequest(): void
2526
$routingResults = $this->createMock(RoutingResults::class);
2627

2728
$serverRequest = $this->createServerRequest('/')
29+
->withAttribute('basePath', '')
2830
->withAttribute('route', $route)
2931
->withAttribute('routeParser', $routeParser)
3032
->withAttribute('routingResults', $routingResults);
@@ -34,6 +36,7 @@ public function testCanCreateInstanceFromServerRequest(): void
3436
$this->assertSame($route, $routeContext->getRoute());
3537
$this->assertSame($routeParser, $routeContext->getRouteParser());
3638
$this->assertSame($routingResults, $routeContext->getRoutingResults());
39+
$this->assertSame('', $routeContext->getBasePath());
3740
}
3841

3942
public function testCanCreateInstanceWithoutRoute(): void
@@ -47,6 +50,23 @@ public function testCanCreateInstanceWithoutRoute(): void
4750
$this->assertNull($routeContext->getRoute());
4851
$this->assertNotNull($routeContext->getRouteParser());
4952
$this->assertNotNull($routeContext->getRoutingResults());
53+
$this->assertNotNull($routeContext->getBasePath());
54+
}
55+
56+
public function testCanCreateInstanceWithoutBasePathAndThrowExceptionIfGetBasePathIsCalled(): void
57+
{
58+
$serverRequest = $this->createServerRequestWithRouteAttributes();
59+
60+
// Route attribute is not required
61+
$serverRequest = $serverRequest->withoutAttribute('basePath');
62+
63+
$routeContext = RouteContext::fromRequest($serverRequest);
64+
$this->assertNotNull($routeContext->getRoute());
65+
$this->assertNotNull($routeContext->getRouteParser());
66+
$this->assertNotNull($routeContext->getRoutingResults());
67+
68+
$this->expectException(RuntimeException::class);
69+
$routeContext->getBasePath();
5070
}
5171

5272
public function requiredRouteContextRequestAttributes(): array
@@ -76,6 +96,7 @@ private function createServerRequestWithRouteAttributes(): ServerRequestInterfac
7696
$routingResults = $this->createMock(RoutingResults::class);
7797

7898
return $this->createServerRequest('/')
99+
->withAttribute('basePath', '')
79100
->withAttribute('route', $route)
80101
->withAttribute('routeParser', $routeParser)
81102
->withAttribute('routingResults', $routingResults);

0 commit comments

Comments
 (0)