Skip to content

Commit 1f3ec14

Browse files
authored
fix(router): require hard-coded uris to start with a slash in Router::toUri (#1205)
1 parent 670da14 commit 1f3ec14

File tree

3 files changed

+33
-17
lines changed

3 files changed

+33
-17
lines changed

packages/router/src/GenericRouter.php

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -131,27 +131,20 @@ private function getCallable(MatchedRoute $matchedRoute): HttpMiddlewareCallable
131131

132132
public function toUri(array|string $action, ...$params): string
133133
{
134-
try {
135-
if (is_array($action)) {
136-
$controllerClass = $action[0];
137-
$reflection = new ClassReflector($controllerClass);
138-
$controllerMethod = $reflection->getMethod($action[1]);
139-
} else {
140-
$controllerClass = $action;
141-
$reflection = new ClassReflector($controllerClass);
142-
$controllerMethod = $reflection->getMethod('__invoke');
143-
}
134+
if (is_string($action) && str_starts_with($action, '/')) {
135+
$uri = $action;
136+
} else {
137+
[$controllerClass, $controllerMethod] = is_array($action) ? $action : [$action, '__invoke'];
144138

145-
/** @var Route|null $routeAttribute */
146-
$routeAttribute = $controllerMethod->getAttribute(Route::class);
139+
$routeAttribute = new ClassReflector($controllerClass)
140+
->getMethod($controllerMethod)
141+
->getAttribute(Route::class);
147142

148-
$uri = $routeAttribute->uri;
149-
} catch (ReflectionException) {
150-
if (is_array($action)) {
151-
throw new InvalidRouteException($action[0], $action[1]);
143+
if ($routeAttribute === null) {
144+
throw new InvalidRouteException($controllerClass, $controllerMethod);
152145
}
153146

154-
$uri = $action;
147+
$uri = $routeAttribute->uri;
155148
}
156149

157150
$uri = str($uri);

packages/router/src/Router.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,25 @@ public function dispatch(Request|PsrRequest $request): Response;
1414

1515
/**
1616
* Creates a valid URI to the given `$action`.
17+
*
18+
* `$action` is one of :
19+
* - Controller FQCN and its method as a tuple
20+
* - Invokable controller FQCN
21+
* - URI string starting with `/`
22+
*
23+
* @param array{class-string, string}|class-string|string $action
1724
*/
1825
public function toUri(array|string $action, ...$params): string;
1926

2027
/**
2128
* Checks if the URI to the given `$action` would match the current route.
29+
*
30+
* `$action` is one of :
31+
* - Controller FQCN and its method as a tuple
32+
* - Invokable controller FQCN
33+
* - URI string starting with `/`
34+
*
35+
* @param array{class-string, string}|class-string|string $action
2236
*/
2337
public function isCurrentUri(array|string $action, ...$params): bool;
2438
}

tests/Integration/Route/RouterTest.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Laminas\Diactoros\ServerRequest;
88
use Laminas\Diactoros\Stream;
99
use Laminas\Diactoros\Uri;
10+
use ReflectionException;
1011
use Tempest\Core\AppConfig;
1112
use Tempest\Core\Environment;
1213
use Tempest\Database\Migrations\CreateMigrationsTable;
@@ -101,6 +102,14 @@ public function test_generate_uri(): void
101102
$this->assertEquals('https://test.com/test/1/a/b/c/d', $router->toUri([TestController::class, 'withCustomRegexParams'], id: 1, name: 'a/b/c/d'));
102103
}
103104

105+
public function test_uri_generation_with_invalid_fqcn(): void
106+
{
107+
$router = $this->container->get(GenericRouter::class);
108+
109+
$this->expectException(ReflectionException::class);
110+
$router->toUri(TestController::class . 'Invalid');
111+
}
112+
104113
public function test_uri_generation_with_query_param(): void
105114
{
106115
$router = $this->container->get(GenericRouter::class);

0 commit comments

Comments
 (0)