From 79f96384f2307637398f2f1aebb9147a72ba98be Mon Sep 17 00:00:00 2001 From: Petr Heinz Date: Fri, 4 Feb 2022 15:43:16 +0100 Subject: [PATCH] Disallow extra fields in config to protect from typos (#52) --- src/Route/InvalidRouteDefinitionException.php | 20 ++++++++++++++++ src/Route/RouteDefinition.php | 8 +++++++ src/Route/RouteRegister.php | 24 +++++++++++++++++++ tests/SlimApplicationFactoryTest.php | 10 ++++++++ tests/typo-in-config.neon | 21 ++++++++++++++++ 5 files changed, 83 insertions(+) create mode 100644 src/Route/InvalidRouteDefinitionException.php create mode 100644 tests/typo-in-config.neon diff --git a/src/Route/InvalidRouteDefinitionException.php b/src/Route/InvalidRouteDefinitionException.php new file mode 100644 index 0000000..60df4f9 --- /dev/null +++ b/src/Route/InvalidRouteDefinitionException.php @@ -0,0 +1,20 @@ +detectTyposInRouteConfiguration([$apiNamespace, $routePattern, $method], $routeDefinitionData); + $routeDefinition = $this->routeDefinitionFactory->create($method, $routeDefinitionData); $routeName = $routeDefinition->getName() ?? $resolveRoutePath; @@ -121,4 +125,24 @@ private function getEmptyRouteDefinitionData(): array RouteDefinition::NAME => null, ]; } + + + /** + * @param string[] $path + * @param mixed[] $routeDefinitionData + */ + private function detectTyposInRouteConfiguration(array $path, array $routeDefinitionData): void + { + $usedKeys = array_keys($routeDefinitionData); + foreach ($usedKeys as $usedKey) { + foreach (RouteDefinition::ALL_DEFINED_KEYS as $definedKey) { + $levenshteinDistance = levenshtein($usedKey, $definedKey); + if ($levenshteinDistance > 0 && $levenshteinDistance < 2) { + $path[] = $usedKey; + + throw new InvalidRouteDefinitionException($path, $definedKey); + } + } + } + } } diff --git a/tests/SlimApplicationFactoryTest.php b/tests/SlimApplicationFactoryTest.php index 8c3b1a4..66a5de8 100644 --- a/tests/SlimApplicationFactoryTest.php +++ b/tests/SlimApplicationFactoryTest.php @@ -233,4 +233,14 @@ private function prepareEnvironment(string $requestMethod, string $requestUrlPat $_SERVER[$name] = $value; } } + + + public function testRouteConfigWillFailWhenMisconfigured(): void + { + $this->expectExceptionMessage( + 'Unexpected route definition key in "app › /hello-world › get › middleware", did you mean "middlewares"?' + ); + + SlimAppTester::createSlimApp(__DIR__ . '/typo-in-config.neon'); + } } diff --git a/tests/typo-in-config.neon b/tests/typo-in-config.neon new file mode 100644 index 0000000..49276c4 --- /dev/null +++ b/tests/typo-in-config.neon @@ -0,0 +1,21 @@ +extensions: + slimApi: \BrandEmbassy\Slim\DI\SlimApiExtension + + +services: + - BrandEmbassyTest\Slim\Sample\BeforeRouteMiddleware + - BrandEmbassyTest\Slim\Sample\HelloWorldRoute + +slimApi: + apiPrefix: '/tests' + slimConfiguration: + settings: + removeDefaultHandlers: true + + routes: + "app": + "/hello-world": + get: + service: BrandEmbassyTest\Slim\Sample\HelloWorldRoute + middleware: + - BrandEmbassyTest\Slim\Sample\BeforeRouteMiddleware