From 6ff4b08627f20a876dd3d9dcfe96849577aea85d Mon Sep 17 00:00:00 2001 From: Daniel Opitz Date: Fri, 3 Apr 2026 19:21:25 +0200 Subject: [PATCH 1/3] Clean up routing middleware --- Slim/Interfaces/RouteInterface.php | 2 +- Slim/Middleware/BasePathMiddleware.php | 2 -- Slim/Middleware/RoutingMiddleware.php | 6 +++--- Slim/Routing/Route.php | 2 +- tests/Middleware/RoutingMiddlewareTest.php | 5 ++--- tests/Routing/RouteMatchTest.php | 8 ++------ 6 files changed, 9 insertions(+), 16 deletions(-) diff --git a/Slim/Interfaces/RouteInterface.php b/Slim/Interfaces/RouteInterface.php index 5f8955c03..a815256e3 100644 --- a/Slim/Interfaces/RouteInterface.php +++ b/Slim/Interfaces/RouteInterface.php @@ -63,7 +63,7 @@ public function getArgument(string $name, ?string $default = null): ?string; /** * Get route arguments. * - * @return array + * @return array */ public function getArguments(): array; diff --git a/Slim/Middleware/BasePathMiddleware.php b/Slim/Middleware/BasePathMiddleware.php index 1a26ad1d0..f8f1e474c 100644 --- a/Slim/Middleware/BasePathMiddleware.php +++ b/Slim/Middleware/BasePathMiddleware.php @@ -45,8 +45,6 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface $basePath = $this->getBasePathByRequestUri($request); } - // $request = $request->withAttribute(RouteMatch::BASE_PATH_ATTRIBUTE, $basePath); - $this->router->setBasePath($basePath); return $handler->handle($request); diff --git a/Slim/Middleware/RoutingMiddleware.php b/Slim/Middleware/RoutingMiddleware.php index 6c69ab5ab..ab996f7c8 100644 --- a/Slim/Middleware/RoutingMiddleware.php +++ b/Slim/Middleware/RoutingMiddleware.php @@ -42,14 +42,14 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface { $requestPath = $request->getUri()->getPath(); $basePath = $this->router->getBasePath(); - $dispatchPath = $this->stripBasePath($requestPath, $this->router->getBasePath()); + $dispatchPath = $this->stripBasePath($requestPath, $basePath); $routingResult = $this->dispatcher->dispatch( $request->getMethod(), rawurldecode($dispatchPath) ); - $routeMatch = $this->createRouteMatch($routingResult, $basePath); + $routeMatch = $this->createRouteMatch($routingResult); $request = $request->withAttribute(RouteMatch::class, $routeMatch); return $handler->handle($request); @@ -58,7 +58,7 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface /** * @param array $routingResult */ - private function createRouteMatch(array $routingResult, string $basePath): RouteMatch + private function createRouteMatch(array $routingResult): RouteMatch { $status = $routingResult[0] ?? null; diff --git a/Slim/Routing/Route.php b/Slim/Routing/Route.php index b5cf5dc7a..0cbe45f14 100644 --- a/Slim/Routing/Route.php +++ b/Slim/Routing/Route.php @@ -45,7 +45,7 @@ final class Route implements RouteInterface, MiddlewareCollectionInterface * * @var array */ - private array $arguments; + private array $arguments = []; /** * @param array $methods diff --git a/tests/Middleware/RoutingMiddlewareTest.php b/tests/Middleware/RoutingMiddlewareTest.php index 55180ad17..80108d9e3 100644 --- a/tests/Middleware/RoutingMiddlewareTest.php +++ b/tests/Middleware/RoutingMiddlewareTest.php @@ -23,7 +23,6 @@ use Slim\Middleware\JsonBodyParserMiddleware; use Slim\Middleware\RoutingMiddleware; use Slim\Routing\RouteMatch; -use Slim\Routing\RoutingResults; use Slim\Tests\Traits\AppTestTrait; final class RoutingMiddlewareTest extends TestCase @@ -97,7 +96,7 @@ public function testRouteIsNotStoredOnMethodNotAllowed() } catch (HttpMethodNotAllowedException $exception) { $request = $exception->getRequest(); - // routingResults is available + // RouteMatch is available /** @var RouteMatch $routeMatch */ $routeMatch = $request->getAttribute(RouteMatch::class); $test->assertSame(DispatcherInterface::METHOD_NOT_ALLOWED, $routeMatch->getStatus()); @@ -140,7 +139,7 @@ public function testRouteIsNotStoredOnNotFound() } catch (HttpNotFoundException $exception) { $request = $exception->getRequest(); - // routingResults is available + // RouteMatch is available $routeMatch = $request->getAttribute(RouteMatch::class); $test->assertSame(DispatcherInterface::NOT_FOUND, $routeMatch->getStatus()); diff --git a/tests/Routing/RouteMatchTest.php b/tests/Routing/RouteMatchTest.php index ca9bdf0f6..a8fb94bc8 100644 --- a/tests/Routing/RouteMatchTest.php +++ b/tests/Routing/RouteMatchTest.php @@ -41,9 +41,7 @@ public function testFoundRouteMatch(): void public function testNotFoundRouteMatch(): void { - $basePath = '/api'; - - $routeMatch = RouteMatch::notFound($basePath); + $routeMatch = RouteMatch::notFound(); $this->assertFalse($routeMatch->isFound()); $this->assertTrue($routeMatch->isNotFound()); @@ -57,9 +55,7 @@ public function testNotFoundRouteMatch(): void public function testMethodNotAllowedRouteMatch(): void { $allowedMethods = ['GET', 'POST']; - $basePath = '/api'; - - $routeMatch = RouteMatch::methodNotAllowed($allowedMethods, $basePath); + $routeMatch = RouteMatch::methodNotAllowed($allowedMethods); $this->assertFalse($routeMatch->isFound()); $this->assertFalse($routeMatch->isNotFound()); From bb06306e987b7d647fa8fec0e3558fa5d12d65d0 Mon Sep 17 00:00:00 2001 From: Daniel Opitz Date: Sat, 4 Apr 2026 13:18:25 +0200 Subject: [PATCH 2/3] Clean up routing middleware --- Slim/Interfaces/RouteInterface.php | 4 +-- Slim/Routing/Route.php | 2 ++ tests/Middleware/RoutingMiddlewareTest.php | 40 ++++++++++++++++++++++ tests/Routing/RouteTest.php | 34 ++++++++++++++++++ 4 files changed, 78 insertions(+), 2 deletions(-) diff --git a/Slim/Interfaces/RouteInterface.php b/Slim/Interfaces/RouteInterface.php index a815256e3..ad3cc29b8 100644 --- a/Slim/Interfaces/RouteInterface.php +++ b/Slim/Interfaces/RouteInterface.php @@ -63,14 +63,14 @@ public function getArgument(string $name, ?string $default = null): ?string; /** * Get route arguments. * - * @return array + * @return array */ public function getArguments(): array; /** * Set route arguments. * - * @param array $arguments The arguments. + * @param array $arguments The arguments. * * @return RouteInterface */ diff --git a/Slim/Routing/Route.php b/Slim/Routing/Route.php index 0cbe45f14..d71468990 100644 --- a/Slim/Routing/Route.php +++ b/Slim/Routing/Route.php @@ -11,6 +11,8 @@ use Slim\Interfaces\MiddlewareCollectionInterface; use Slim\Interfaces\RouteInterface; +use function array_key_exists; + final class Route implements RouteInterface, MiddlewareCollectionInterface { use MiddlewareCollectionTrait; diff --git a/tests/Middleware/RoutingMiddlewareTest.php b/tests/Middleware/RoutingMiddlewareTest.php index 80108d9e3..7da0ebe2e 100644 --- a/tests/Middleware/RoutingMiddlewareTest.php +++ b/tests/Middleware/RoutingMiddlewareTest.php @@ -13,11 +13,14 @@ use PHPUnit\Framework\TestCase; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Message\UriInterface; use Psr\Http\Server\RequestHandlerInterface; +use RuntimeException; use Slim\Exception\HttpMethodNotAllowedException; use Slim\Exception\HttpNotFoundException; use Slim\Factory\AppFactory; use Slim\Interfaces\DispatcherInterface; +use Slim\Interfaces\RouterInterface; use Slim\Interfaces\UrlGeneratorInterface; use Slim\Middleware\EndpointMiddleware; use Slim\Middleware\JsonBodyParserMiddleware; @@ -194,4 +197,41 @@ public function testRoutingWithBasePath(): void $this->assertSame('/api/users/123?page=2', $response->getHeaderLine('X-relativeUrlFor')); $this->assertSame('/api/users/123?page=2', $response->getHeaderLine('X-fullUrlFor')); } + + public function testMethodNotAllowedThrowsRuntimeExceptionWhenAllowedMethodsPayloadIsInvalid(): void + { + $dispatcher = $this->createMock(DispatcherInterface::class); + $dispatcher + ->method('dispatch') + ->willReturn([ + DispatcherInterface::METHOD_NOT_ALLOWED, + 'GET', + ]); + + $router = $this->createMock(RouterInterface::class); + $router + ->method('getBasePath') + ->willReturn(''); + + $middleware = new RoutingMiddleware($dispatcher, $router); + + $request = $this->createMock(ServerRequestInterface::class); + $uri = $this->createMock(UriInterface::class); + $uri + ->method('getPath') + ->willReturn('/hello/foo'); + $request + ->method('getUri') + ->willReturn($uri); + $request + ->method('getMethod') + ->willReturn('GET'); + + $handler = $this->createMock(RequestHandlerInterface::class); + + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('Dispatcher returned invalid allowed methods.'); + + $middleware->process($request, $handler); + } } diff --git a/tests/Routing/RouteTest.php b/tests/Routing/RouteTest.php index 4889e19b3..988ae2f54 100644 --- a/tests/Routing/RouteTest.php +++ b/tests/Routing/RouteTest.php @@ -10,6 +10,7 @@ namespace Slim\Tests\Routing; +use InvalidArgumentException; use PHPUnit\Framework\TestCase; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; @@ -137,6 +138,39 @@ public function testGetMethodsReturnsCorrectMethods(): void $this->assertSame($methods, $route->getMethods()); } + public function testSetArgumentsStoresStringArguments(): void + { + $methods = ['GET']; + $pattern = '/users/{id}'; + $handler = function () { + return 'handler'; + }; + + $route = new Route($methods, $pattern, $handler); + + $arguments = ['id' => '123', 'slug' => 'john-doe']; + $route->setArguments($arguments); + + $this->assertSame($arguments, $route->getArguments()); + $this->assertSame('123', $route->getArgument('id')); + } + + public function testSetArgumentsRejectsNonStringValues(): void + { + $methods = ['GET']; + $pattern = '/users/{id}'; + $handler = function () { + return 'handler'; + }; + + $route = new Route($methods, $pattern, $handler); + + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Route arguments must be an array.'); + + $route->setArguments(['id' => 123]); + } + private function createMiddleware(): MiddlewareInterface { return new class implements MiddlewareInterface { From d612560fa7f0b70b4c1ab6f2df5ac8da8217a591 Mon Sep 17 00:00:00 2001 From: Daniel Opitz Date: Sat, 4 Apr 2026 13:20:23 +0200 Subject: [PATCH 3/3] Update test --- tests/Routing/RouteTest.php | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/tests/Routing/RouteTest.php b/tests/Routing/RouteTest.php index 988ae2f54..3449b33df 100644 --- a/tests/Routing/RouteTest.php +++ b/tests/Routing/RouteTest.php @@ -10,7 +10,6 @@ namespace Slim\Tests\Routing; -use InvalidArgumentException; use PHPUnit\Framework\TestCase; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; @@ -155,22 +154,6 @@ public function testSetArgumentsStoresStringArguments(): void $this->assertSame('123', $route->getArgument('id')); } - public function testSetArgumentsRejectsNonStringValues(): void - { - $methods = ['GET']; - $pattern = '/users/{id}'; - $handler = function () { - return 'handler'; - }; - - $route = new Route($methods, $pattern, $handler); - - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('Route arguments must be an array.'); - - $route->setArguments(['id' => 123]); - } - private function createMiddleware(): MiddlewareInterface { return new class implements MiddlewareInterface {