diff --git a/README.md b/README.md index 9207c25..b53734c 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ slimApi: # Configure it ``` -### First API enpoint +### First API endpoint Now let's say you want to make a REST endpoint creating channels, `[POST] /new-api/2.0/channels` You need to define in `parameters.api` section in `config.neon`. @@ -71,7 +71,14 @@ parameters: - App\SomeOtherMiddleware # last in row - App\UsuallyRequestDataValidationMiddleware # second in row - App\SomeAuthMiddleware # this one is called first - + + beforeRouteMiddlewares: + # this is called for each route, before route middlewares + - App\SomeBeforeRequestMiddleware + + beforeRequestMiddlewares: + # this is called for each request, even when route does NOT exist (404 requests) + - App\SomeBeforeRouteMiddleware tests/Dummy/BeforeRequestMiddleware.php ``` You can also reference the named service by it's name. diff --git a/src/SlimApplicationFactory.php b/src/SlimApplicationFactory.php index b669e29..687e50c 100644 --- a/src/SlimApplicationFactory.php +++ b/src/SlimApplicationFactory.php @@ -22,6 +22,11 @@ final class SlimApplicationFactory */ private $container; + /** + * @var Middleware[] + */ + private $beforeRoutesMiddlewares; + /** * @param array $configuration * @param Container $container @@ -30,6 +35,7 @@ public function __construct(array $configuration, Container $container) { $this->configuration = $configuration; $this->container = $container; + $this->beforeRoutesMiddlewares = []; } /** @@ -41,6 +47,8 @@ public function create() $configuration = $this->getConfiguration($this->configuration['apiDefinitionKey']); + $this->registerBeforeRouteMiddlewares($app, $configuration); + foreach ($configuration['routes'] as $apiName => $api) { $this->registerApis($app, $api, $apiName); } @@ -55,6 +63,12 @@ public function create() $this->registerHandlers($app, $configuration['handlers']); } + if (isset($configuration['beforeRequestMiddlewares'])) { + foreach ($configuration['beforeRequestMiddlewares'] as $middleware) { + $this->registerBeforeRequestMiddleware($app, $middleware); + } + } + return $app; } @@ -146,7 +160,9 @@ private function registerHandlers(SlimApp $app, array $handlers) */ private function registerServiceIntoContainer(SlimApp $app, $serviceName) { - $app->getContainer()[$serviceName] = $this->getServiceProvider($serviceName); + if (!$app->getContainer()->has($serviceName)) { + $app->getContainer()[$serviceName] = $this->getServiceProvider($serviceName); + } } /** @@ -210,17 +226,17 @@ private function registerInvokableActionRoutes(SlimApp $app, array $routeData, $ $this->registerServiceIntoContainer($app, $service); $routeToAdd = $app->map([$method], $urlPattern, $service); - if (isset($config['middleware']) && count($config['middleware']) > 0) { + if (isset($config['middleware'])) { foreach ($config['middleware'] as $middleware) { - $container = $app->getContainer(); - - if (!$container->has($middleware)) { - $this->registerServiceIntoContainer($app, $middleware); - } + $this->registerServiceIntoContainer($app, $middleware); $routeToAdd->add($middleware); } } + + foreach ($this->beforeRoutesMiddlewares as $middleware) { + $routeToAdd->add($middleware); + } } } @@ -235,4 +251,27 @@ private function createUrlPattern($apiName, $version, $routeName) return sprintf('/%s/%s%s', $apiName, $version, $routeName); } + /** + * @param SlimApp $app + * @param string $middleware + */ + private function registerBeforeRequestMiddleware(SlimApp $app, $middleware) + { + $this->registerServiceIntoContainer($app, $middleware); + $app->add($middleware); + } + + /** + * @param SlimApp $app + * @param array $configuration + */ + private function registerBeforeRouteMiddlewares(SlimApp $app, $configuration) + { + if (isset($configuration['beforeRouteMiddlewares'])) { + foreach ($configuration['beforeRouteMiddlewares'] as $globalMiddleware) { + $this->registerServiceIntoContainer($app, $globalMiddleware); + $this->beforeRoutesMiddlewares[] = $app->getContainer()->get($globalMiddleware); + } + } + } } diff --git a/tests/Dummy/BeforeRequestMiddleware.php b/tests/Dummy/BeforeRequestMiddleware.php new file mode 100644 index 0000000..72338b4 --- /dev/null +++ b/tests/Dummy/BeforeRequestMiddleware.php @@ -0,0 +1,27 @@ +withAddedHeader( + 'processed-by-before-request-middleware', + 'proof-for-before-request' + ); + + return $next($request, $response); + } +} diff --git a/tests/Dummy/BeforeRouteMiddleware.php b/tests/Dummy/BeforeRouteMiddleware.php new file mode 100644 index 0000000..e8b1fe3 --- /dev/null +++ b/tests/Dummy/BeforeRouteMiddleware.php @@ -0,0 +1,27 @@ +withAddedHeader( + 'processed-by-before-route-middlewares', + 'proof-for-before-route' + ); + + return $next($request, $response); + } +} diff --git a/tests/SlimApplicationFactoryTest.php b/tests/SlimApplicationFactoryTest.php index c502abb..a9c6040 100644 --- a/tests/SlimApplicationFactoryTest.php +++ b/tests/SlimApplicationFactoryTest.php @@ -7,7 +7,6 @@ use BrandEmbassy\Slim\SlimApplicationFactory; use BrandEmbassy\Slim\Request\Request; use BrandEmbassy\Slim\Response\Response; -use LogicException; use Nette\DI\Compiler; use Nette\DI\Container; use Nette\DI\ContainerLoader; @@ -87,6 +86,37 @@ public function testShouldAllowRequestByAccessMiddleware() $this->assertEquals('{"channelId":"fb_1234"}', $this->getContents($response)); } + public function testShouldProcessBothGlobalMiddlewares() + { + $request = $this->createRequest('POST', '/new-api/2.0/channels'); + + /** @var ResponseInterface $response */ + $response = $this->createSlimApp()->process($request, new Response(new \Slim\Http\Response())); + + $this->assertEquals( + ['proof-for-before-request'], + $response->getHeader('processed-by-before-request-middleware') + ); + + $this->assertEquals( + ['proof-for-before-route'], + $response->getHeader('processed-by-before-route-middlewares') + ); + } + + public function testShouldProcessBeforeRequestMiddleware() + { + $request = $this->createRequest('POST', '/non-existing/path'); + + /** @var ResponseInterface $response */ + $response = $this->createSlimApp()->process($request, new Response(new \Slim\Http\Response())); + + $this->assertEquals( + ['proof-for-before-request'], + $response->getHeader('processed-by-before-request-middleware') + ); + } + /** * @param string $configPath * @return Container diff --git a/tests/config.neon b/tests/config.neon index 66ae14a..f78d01f 100644 --- a/tests/config.neon +++ b/tests/config.neon @@ -9,6 +9,8 @@ services: - BrandEmbassyTest\Slim\Dummy\GoldenKeyAuthMiddleware - BrandEmbassyTest\Slim\Dummy\CreateChannelAction - BrandEmbassyTest\Slim\Dummy\ErroringAction + - BrandEmbassyTest\Slim\Dummy\BeforeRequestMiddleware + - BrandEmbassyTest\Slim\Dummy\BeforeRouteMiddleware parameters: api: @@ -30,6 +32,13 @@ parameters: post: service: BrandEmbassyTest\Slim\Dummy\ErroringAction + beforeRouteMiddlewares: + - BrandEmbassyTest\Slim\Dummy\BeforeRouteMiddleware + + beforeRequestMiddlewares: + - BrandEmbassyTest\Slim\Dummy\BeforeRequestMiddleware + + slimApi: slimConfiguration: settings: