From dd3c56c9102c20b68bbaeee806dcbb9a52a6042c Mon Sep 17 00:00:00 2001 From: l0gicgate Date: Tue, 20 Aug 2019 09:58:02 -0600 Subject: [PATCH 1/9] add MiddlewareDispatcherInterface --- .../MiddlewareDispatcherInterface.php | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 Slim/Interfaces/MiddlewareDispatcherInterface.php diff --git a/Slim/Interfaces/MiddlewareDispatcherInterface.php b/Slim/Interfaces/MiddlewareDispatcherInterface.php new file mode 100644 index 000000000..78eff1485 --- /dev/null +++ b/Slim/Interfaces/MiddlewareDispatcherInterface.php @@ -0,0 +1,48 @@ + Date: Tue, 20 Aug 2019 09:58:17 -0600 Subject: [PATCH 2/9] implement MiddlewareDispatcherInterface --- Slim/MiddlewareDispatcher.php | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/Slim/MiddlewareDispatcher.php b/Slim/MiddlewareDispatcher.php index 8112e7909..284b44dc2 100644 --- a/Slim/MiddlewareDispatcher.php +++ b/Slim/MiddlewareDispatcher.php @@ -18,8 +18,9 @@ use RuntimeException; use Slim\Interfaces\AdvancedCallableResolverInterface; use Slim\Interfaces\CallableResolverInterface; +use Slim\Interfaces\MiddlewareDispatcherInterface; -class MiddlewareDispatcher implements RequestHandlerInterface +class MiddlewareDispatcher implements MiddlewareDispatcherInterface { /** * Tip of the middleware call stack @@ -29,7 +30,7 @@ class MiddlewareDispatcher implements RequestHandlerInterface protected $tip; /** - * @var CallableResolverInterface + * @var CallableResolverInterface|null */ protected $callableResolver; @@ -54,12 +55,9 @@ public function __construct( } /** - * Seed the middleware stack with the inner request handler - * - * @param RequestHandlerInterface $kernel - * @return void + * {@inheritdoc} */ - protected function seedMiddlewareStack(RequestHandlerInterface $kernel): void + public function seedMiddlewareStack(RequestHandlerInterface $kernel): void { $this->tip = $kernel; } @@ -83,9 +81,9 @@ public function handle(ServerRequestInterface $request): ResponseInterface * added one (last in, first out). * * @param MiddlewareInterface|string|callable $middleware - * @return self + * @return MiddlewareDispatcherInterface */ - public function add($middleware): self + public function add($middleware): MiddlewareDispatcherInterface { if ($middleware instanceof MiddlewareInterface) { return $this->addMiddleware($middleware); @@ -113,9 +111,9 @@ public function add($middleware): self * added one (last in, first out). * * @param MiddlewareInterface $middleware - * @return self + * @return MiddlewareDispatcherInterface */ - public function addMiddleware(MiddlewareInterface $middleware): self + public function addMiddleware(MiddlewareInterface $middleware): MiddlewareDispatcherInterface { $next = $this->tip; $this->tip = new class($middleware, $next) implements RequestHandlerInterface From ccb7caa9a1390122f4cc43e89f5ff99ea2dc55d8 Mon Sep 17 00:00:00 2001 From: l0gicgate Date: Tue, 20 Aug 2019 09:59:02 -0600 Subject: [PATCH 3/9] add constructor parameter for MiddlewareDispatcherInterface --- Slim/App.php | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/Slim/App.php b/Slim/App.php index 3b366e1f1..efd938e4b 100644 --- a/Slim/App.php +++ b/Slim/App.php @@ -17,6 +17,7 @@ use Psr\Http\Server\RequestHandlerInterface; use Slim\Factory\ServerRequestCreatorFactory; use Slim\Interfaces\CallableResolverInterface; +use Slim\Interfaces\MiddlewareDispatcherInterface; use Slim\Interfaces\RouteCollectorInterface; use Slim\Interfaces\RouteResolverInterface; use Slim\Middleware\BodyParsingMiddleware; @@ -46,18 +47,20 @@ class App extends RouteCollectorProxy implements RequestHandlerInterface protected $routeResolver; /** - * @param ResponseFactoryInterface $responseFactory - * @param ContainerInterface|null $container - * @param CallableResolverInterface|null $callableResolver - * @param RouteCollectorInterface|null $routeCollector - * @param RouteResolverInterface|null $routeResolver + * @param ResponseFactoryInterface $responseFactory + * @param ContainerInterface|null $container + * @param CallableResolverInterface|null $callableResolver + * @param RouteCollectorInterface|null $routeCollector + * @param RouteResolverInterface|null $routeResolver + * @param MiddlewareDispatcherInterface|null $middlewareDispatcher */ public function __construct( ResponseFactoryInterface $responseFactory, ?ContainerInterface $container = null, ?CallableResolverInterface $callableResolver = null, ?RouteCollectorInterface $routeCollector = null, - ?RouteResolverInterface $routeResolver = null + ?RouteResolverInterface $routeResolver = null, + ?MiddlewareDispatcherInterface $middlewareDispatcher = null ) { parent::__construct( $responseFactory, @@ -69,7 +72,11 @@ public function __construct( $this->routeResolver = $routeResolver ?? new RouteResolver($this->routeCollector); $routeRunner = new RouteRunner($this->routeResolver, $this->routeCollector->getRouteParser()); - $this->middlewareDispatcher = new MiddlewareDispatcher($routeRunner, $this->callableResolver, $container); + if ($middlewareDispatcher) { + $middlewareDispatcher->seedMiddlewareStack($routeRunner); + } + + $this->middlewareDispatcher = $middlewareDispatcher ?? new MiddlewareDispatcher($routeRunner, $this->callableResolver, $container); } /** @@ -80,6 +87,14 @@ public function getRouteResolver(): RouteResolverInterface return $this->routeResolver; } + /** + * @return MiddlewareDispatcherInterface + */ + public function getMiddlewareDispatcher(): MiddlewareDispatcherInterface + { + return $this->middlewareDispatcher; + } + /** * @param MiddlewareInterface|string|callable $middleware * @return self From c5f31e817ef0246dac7afba8e3ae574b00eb3227 Mon Sep 17 00:00:00 2001 From: l0gicgate Date: Tue, 20 Aug 2019 09:59:25 -0600 Subject: [PATCH 4/9] add ability to inject MiddlewareDispatcher --- Slim/Factory/AppFactory.php | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/Slim/Factory/AppFactory.php b/Slim/Factory/AppFactory.php index 331c6933e..56bab9eb2 100644 --- a/Slim/Factory/AppFactory.php +++ b/Slim/Factory/AppFactory.php @@ -18,6 +18,7 @@ use Slim\Factory\Psr17\Psr17FactoryProvider; use Slim\Factory\Psr17\SlimHttpPsr17Factory; use Slim\Interfaces\CallableResolverInterface; +use Slim\Interfaces\MiddlewareDispatcherInterface; use Slim\Interfaces\Psr17FactoryProviderInterface; use Slim\Interfaces\RouteCollectorInterface; use Slim\Interfaces\RouteResolverInterface; @@ -59,17 +60,23 @@ class AppFactory */ protected static $routeResolver; + /** + * @var MiddlewareDispatcherInterface|null + */ + protected static $middlewareDispatcher; + /** * @var bool */ protected static $slimHttpDecoratorsAutomaticDetectionEnabled = true; /** - * @param ResponseFactoryInterface|null $responseFactory - * @param ContainerInterface|null $container - * @param CallableResolverInterface|null $callableResolver - * @param RouteCollectorInterface|null $routeCollector - * @param RouteResolverInterface|null $routeResolver + * @param ResponseFactoryInterface|null $responseFactory + * @param ContainerInterface|null $container + * @param CallableResolverInterface|null $callableResolver + * @param RouteCollectorInterface|null $routeCollector + * @param RouteResolverInterface|null $routeResolver + * @param MiddlewareDispatcherInterface|null $middlewareDispatcher * @return App */ public static function create( @@ -77,7 +84,8 @@ public static function create( ?ContainerInterface $container = null, ?CallableResolverInterface $callableResolver = null, ?RouteCollectorInterface $routeCollector = null, - ?RouteResolverInterface $routeResolver = null + ?RouteResolverInterface $routeResolver = null, + ?MiddlewareDispatcherInterface $middlewareDispatcher = null ): App { static::$responseFactory = $responseFactory ?? static::$responseFactory; return new App( @@ -85,7 +93,8 @@ public static function create( $container ?? static::$container, $callableResolver ?? static::$callableResolver, $routeCollector ?? static::$routeCollector, - $routeResolver ?? static::$routeResolver + $routeResolver ?? static::$routeResolver, + $middlewareDispatcher ?? static::$middlewareDispatcher ); } @@ -111,7 +120,11 @@ public static function createFromContainer(ContainerInterface $container): App ? $container->get(RouteResolverInterface::class) : null; - return new App($responseFactory, $container, $callableResolver, $routeCollector, $routeResolver); + $middlewareDispatcher = $container->has(MiddlewareDispatcherInterface::class) + ? $container->get(MiddlewareDispatcherInterface::class) + : null; + + return new App($responseFactory, $container, $callableResolver, $routeCollector, $routeResolver, $middlewareDispatcher); } /** @@ -224,6 +237,14 @@ public static function setRouteResolver(RouteResolverInterface $routeResolver): static::$routeResolver = $routeResolver; } + /** + * @param MiddlewareDispatcherInterface $middlewareDispatcher + */ + public static function setMiddlewareDispatcher(MiddlewareDispatcherInterface $middlewareDispatcher): void + { + static::$middlewareDispatcher = $middlewareDispatcher; + } + /** * @param bool $enabled */ From 2375206a09910f44783ec8fa33a5d67d77144660 Mon Sep 17 00:00:00 2001 From: l0gicgate Date: Tue, 20 Aug 2019 09:59:44 -0600 Subject: [PATCH 5/9] add unit test coverage for MiddlewareDispatcherInterface --- tests/AppTest.php | 25 +++++++++++++++++++++++++ tests/Factory/AppFactoryTest.php | 21 +++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/tests/AppTest.php b/tests/AppTest.php index a9c22cfcc..899377ac0 100644 --- a/tests/AppTest.php +++ b/tests/AppTest.php @@ -25,6 +25,7 @@ use Slim\Exception\HttpNotFoundException; use Slim\Handlers\Strategies\RequestResponseArgs; use Slim\Interfaces\CallableResolverInterface; +use Slim\Interfaces\MiddlewareDispatcherInterface; use Slim\Interfaces\RouteCollectorInterface; use Slim\Interfaces\RouteCollectorProxyInterface; use Slim\Interfaces\RouteParserInterface; @@ -118,6 +119,30 @@ public function testCreatesRouteCollectorWhenNullWithInjectedContainer() $this->assertEquals($routeCollector, $app->getRouteCollector()); } + public function testGetMiddlewareDispatcherReturnsInjectedInstance() + { + $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); + $middlewareDispatcherProphecy = $this->prophesize(MiddlewareDispatcherInterface::class); + + $app = new App($responseFactoryProphecy->reveal(), null, null, null, null, $middlewareDispatcherProphecy->reveal()); + + $this->assertSame($middlewareDispatcherProphecy->reveal(), $app->getMiddlewareDispatcher()); + } + + public function testMiddlewareDispatcherGetsSeededWithInjectedInstance() + { + $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); + + $middlewareDispatcherProphecy = $this->prophesize(MiddlewareDispatcherInterface::class); + $middlewareDispatcherProphecy + ->seedMiddlewareStack(Argument::any()) + ->shouldBeCalledOnce(); + + $app = new App($responseFactoryProphecy->reveal(), null, null, null, null, $middlewareDispatcherProphecy->reveal()); + + $this->assertSame($middlewareDispatcherProphecy->reveal(), $app->getMiddlewareDispatcher()); + } + public function lowerCaseRequestMethodsProvider() { return [ diff --git a/tests/Factory/AppFactoryTest.php b/tests/Factory/AppFactoryTest.php index d490ff720..29211e3f7 100644 --- a/tests/Factory/AppFactoryTest.php +++ b/tests/Factory/AppFactoryTest.php @@ -26,6 +26,7 @@ use Slim\Http\Factory\DecoratedResponseFactory; use Slim\Http\Response as DecoratedResponse; use Slim\Interfaces\CallableResolverInterface; +use Slim\Interfaces\MiddlewareDispatcherInterface; use Slim\Interfaces\RouteCollectorInterface; use Slim\Interfaces\RouteParserInterface; use Slim\Interfaces\RouteResolverInterface; @@ -117,6 +118,7 @@ public function testAppIsCreatedWithInstancesFromSetters() $routeCollectorProphecy = $this->prophesize(RouteCollectorInterface::class); $routeParserProphecy = $this->prophesize(RouteParserInterface::class); $routeResolverProphecy = $this->prophesize(RouteResolverInterface::class); + $middlewareDispatcherProphecy = $this->prophesize(MiddlewareDispatcherInterface::class); $routeCollectorProphecy->getRouteParser()->willReturn($routeParserProphecy); @@ -126,6 +128,7 @@ public function testAppIsCreatedWithInstancesFromSetters() AppFactory::setCallableResolver($callableResolverProphecy->reveal()); AppFactory::setRouteCollector($routeCollectorProphecy->reveal()); AppFactory::setRouteResolver($routeResolverProphecy->reveal()); + AppFactory::setMiddlewareDispatcher($middlewareDispatcherProphecy->reveal()); $app = AppFactory::create(); @@ -153,6 +156,11 @@ public function testAppIsCreatedWithInstancesFromSetters() $routeResolverProphecy->reveal(), $app->getRouteResolver() ); + + $this->assertSame( + $middlewareDispatcherProphecy->reveal(), + $app->getMiddlewareDispatcher() + ); } public function testAppIsCreatedWithInjectedInstancesFromFunctionArguments() @@ -242,6 +250,8 @@ public function testCreateAppWithContainerUsesContainerDependenciesWhenPresent() ->willReturn($routeParserProphecy->reveal()) ->shouldBeCalledOnce(); + $middlewareDispatcherProphecy = $this->prophesize(MiddlewareDispatcherInterface::class); + $containerProphecy = $this->prophesize(ContainerInterface::class); $containerProphecy @@ -284,6 +294,16 @@ public function testCreateAppWithContainerUsesContainerDependenciesWhenPresent() ->willReturn($routeResolverProphecy->reveal()) ->shouldBeCalledOnce(); + $containerProphecy + ->has(MiddlewareDispatcherInterface::class) + ->willReturn(true) + ->shouldBeCalledOnce(); + + $containerProphecy + ->get(MiddlewareDispatcherInterface::class) + ->willReturn($middlewareDispatcherProphecy->reveal()) + ->shouldBeCalledOnce(); + AppFactory::setSlimHttpDecoratorsAutomaticDetection(false); $app = AppFactory::createFromContainer($containerProphecy->reveal()); @@ -292,5 +312,6 @@ public function testCreateAppWithContainerUsesContainerDependenciesWhenPresent() $this->assertSame($app->getCallableResolver(), $callableResolverProphecy->reveal()); $this->assertSame($app->getRouteCollector(), $routeCollectorProphecy->reveal()); $this->assertSame($app->getRouteResolver(), $routeResolverProphecy->reveal()); + $this->assertSame($app->getMiddlewareDispatcher(), $middlewareDispatcherProphecy->reveal()); } } From 8e0f8352ff193f37c4d3437ef613d1026a2a8616 Mon Sep 17 00:00:00 2001 From: l0gicgate Date: Tue, 20 Aug 2019 10:06:21 -0600 Subject: [PATCH 6/9] fix phpstan errors --- Slim/App.php | 8 ++++---- tests/AppTest.php | 18 ++++++++++++++++-- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/Slim/App.php b/Slim/App.php index efd938e4b..9d276ff5f 100644 --- a/Slim/App.php +++ b/Slim/App.php @@ -37,14 +37,14 @@ class App extends RouteCollectorProxy implements RequestHandlerInterface public const VERSION = '4.1.0'; /** - * @var MiddlewareDispatcher + * @var RouteResolverInterface */ - protected $middlewareDispatcher; + protected $routeResolver; /** - * @var RouteResolverInterface + * @var MiddlewareDispatcherInterface */ - protected $routeResolver; + protected $middlewareDispatcher; /** * @param ResponseFactoryInterface $responseFactory diff --git a/tests/AppTest.php b/tests/AppTest.php index 899377ac0..4cbe57c46 100644 --- a/tests/AppTest.php +++ b/tests/AppTest.php @@ -124,7 +124,14 @@ public function testGetMiddlewareDispatcherReturnsInjectedInstance() $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); $middlewareDispatcherProphecy = $this->prophesize(MiddlewareDispatcherInterface::class); - $app = new App($responseFactoryProphecy->reveal(), null, null, null, null, $middlewareDispatcherProphecy->reveal()); + $app = new App( + $responseFactoryProphecy->reveal(), + null, + null, + null, + null, + $middlewareDispatcherProphecy->reveal() + ); $this->assertSame($middlewareDispatcherProphecy->reveal(), $app->getMiddlewareDispatcher()); } @@ -138,7 +145,14 @@ public function testMiddlewareDispatcherGetsSeededWithInjectedInstance() ->seedMiddlewareStack(Argument::any()) ->shouldBeCalledOnce(); - $app = new App($responseFactoryProphecy->reveal(), null, null, null, null, $middlewareDispatcherProphecy->reveal()); + $app = new App( + $responseFactoryProphecy->reveal(), + null, + null, + null, + null, + $middlewareDispatcherProphecy->reveal() + ); $this->assertSame($middlewareDispatcherProphecy->reveal(), $app->getMiddlewareDispatcher()); } From aed55cf0a28009a319c53a06dd4810bb973ecb79 Mon Sep 17 00:00:00 2001 From: l0gicgate Date: Tue, 20 Aug 2019 10:06:21 -0600 Subject: [PATCH 7/9] fix code style errors --- Slim/App.php | 6 ++++-- Slim/Factory/AppFactory.php | 9 ++++++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/Slim/App.php b/Slim/App.php index 9d276ff5f..692369b86 100644 --- a/Slim/App.php +++ b/Slim/App.php @@ -72,11 +72,13 @@ public function __construct( $this->routeResolver = $routeResolver ?? new RouteResolver($this->routeCollector); $routeRunner = new RouteRunner($this->routeResolver, $this->routeCollector->getRouteParser()); - if ($middlewareDispatcher) { + if (!$middlewareDispatcher) { + $middlewareDispatcher = new MiddlewareDispatcher($routeRunner, $this->callableResolver, $container); + } else { $middlewareDispatcher->seedMiddlewareStack($routeRunner); } - $this->middlewareDispatcher = $middlewareDispatcher ?? new MiddlewareDispatcher($routeRunner, $this->callableResolver, $container); + $this->middlewareDispatcher = $middlewareDispatcher; } /** diff --git a/Slim/Factory/AppFactory.php b/Slim/Factory/AppFactory.php index 56bab9eb2..7cb6357af 100644 --- a/Slim/Factory/AppFactory.php +++ b/Slim/Factory/AppFactory.php @@ -124,7 +124,14 @@ public static function createFromContainer(ContainerInterface $container): App ? $container->get(MiddlewareDispatcherInterface::class) : null; - return new App($responseFactory, $container, $callableResolver, $routeCollector, $routeResolver, $middlewareDispatcher); + return new App( + $responseFactory, + $container, + $callableResolver, + $routeCollector, + $routeResolver, + $middlewareDispatcher + ); } /** From 80555a788af5783c63ce781d5771160c745fd24c Mon Sep 17 00:00:00 2001 From: l0gicgate Date: Tue, 20 Aug 2019 12:30:08 -0600 Subject: [PATCH 8/9] make CallableResolver nullable --- Slim/MiddlewareDispatcher.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Slim/MiddlewareDispatcher.php b/Slim/MiddlewareDispatcher.php index 284b44dc2..39029ae39 100644 --- a/Slim/MiddlewareDispatcher.php +++ b/Slim/MiddlewareDispatcher.php @@ -40,13 +40,13 @@ class MiddlewareDispatcher implements MiddlewareDispatcherInterface protected $container; /** - * @param RequestHandlerInterface $kernel - * @param CallableResolverInterface $callableResolver - * @param ContainerInterface|null $container + * @param RequestHandlerInterface $kernel + * @param CallableResolverInterface|null $callableResolver + * @param ContainerInterface|null $container */ public function __construct( RequestHandlerInterface $kernel, - CallableResolverInterface $callableResolver, + ?CallableResolverInterface $callableResolver = null, ?ContainerInterface $container = null ) { $this->seedMiddlewareStack($kernel); From e830a8c427f73ac24cf1f7c010fda812fd49a902 Mon Sep 17 00:00:00 2001 From: l0gicgate Date: Tue, 20 Aug 2019 12:30:29 -0600 Subject: [PATCH 9/9] remove extraneous test testMiddlewareDispatcherGetsSeededWithInjectedInstance() --- tests/AppTest.php | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/tests/AppTest.php b/tests/AppTest.php index 4cbe57c46..c0ec80461 100644 --- a/tests/AppTest.php +++ b/tests/AppTest.php @@ -119,24 +119,7 @@ public function testCreatesRouteCollectorWhenNullWithInjectedContainer() $this->assertEquals($routeCollector, $app->getRouteCollector()); } - public function testGetMiddlewareDispatcherReturnsInjectedInstance() - { - $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); - $middlewareDispatcherProphecy = $this->prophesize(MiddlewareDispatcherInterface::class); - - $app = new App( - $responseFactoryProphecy->reveal(), - null, - null, - null, - null, - $middlewareDispatcherProphecy->reveal() - ); - - $this->assertSame($middlewareDispatcherProphecy->reveal(), $app->getMiddlewareDispatcher()); - } - - public function testMiddlewareDispatcherGetsSeededWithInjectedInstance() + public function testGetMiddlewareDispatcherGetsSeededAndReturnsInjectedInstance() { $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class);