From 42ec8f7845fd206f7770174eb131de496c399271 Mon Sep 17 00:00:00 2001 From: Serhii Donii Date: Wed, 13 Apr 2022 14:53:31 +0300 Subject: [PATCH 1/6] add swagger-php attributes support and supports symfony with version >= 6.0 --- .github/workflows/ci.yml | 4 +- README.md | 2 + composer.json | 2 +- phpunit.xml | 2 +- src/OpenApiRouteLoader.php | 24 +- .../Fixtures/Basic/Controller.php | 2 +- .../Fixtures/FormatSuffix/Controller.php | 2 +- .../Fixtures/OperationId/Controller.php | 2 +- .../PathParameterPattern/Controller.php | 2 +- .../Fixtures/Priority/Controller.php | 2 +- .../Fixtures/SeveralClasses/BarController.php | 2 +- .../Fixtures/SeveralClasses/FooController.php | 2 +- .../SubNamespace/SubController.php | 2 +- .../SeveralHttpMethods/Controller.php | 2 +- .../SeveralRoutesOnOneAction/Controller.php | 2 +- .../OpenApiRouteLoaderAnnotationsTest.php | 233 ++++++++++++++++++ .../Attributes/Fixtures/Basic/Controller.php | 20 ++ .../Fixtures/FormatSuffix/Controller.php | 39 +++ .../Fixtures/OperationId/Controller.php | 17 ++ .../PathParameterPattern/Controller.php | 37 +++ .../Fixtures/Priority/Controller.php | 29 +++ .../Fixtures/SeveralClasses/BarController.php | 17 ++ .../Fixtures/SeveralClasses/FooController.php | 16 ++ .../SubNamespace/SubController.php | 16 ++ .../SeveralHttpMethods/Controller.php | 35 +++ .../SeveralRoutesOnOneAction/Controller.php | 18 ++ .../OpenApiRouteLoaderAttributesTest.php | 231 +++++++++++++++++ tests/OpenApiRouteLoaderTest.php | 228 ----------------- 28 files changed, 743 insertions(+), 247 deletions(-) rename tests/{ => Annotations}/Fixtures/Basic/Controller.php (82%) rename tests/{ => Annotations}/Fixtures/FormatSuffix/Controller.php (92%) rename tests/{ => Annotations}/Fixtures/OperationId/Controller.php (82%) rename tests/{ => Annotations}/Fixtures/PathParameterPattern/Controller.php (93%) rename tests/{ => Annotations}/Fixtures/Priority/Controller.php (90%) rename tests/{ => Annotations}/Fixtures/SeveralClasses/BarController.php (80%) rename tests/{ => Annotations}/Fixtures/SeveralClasses/FooController.php (76%) rename tests/{ => Annotations}/Fixtures/SeveralClasses/SubNamespace/SubController.php (73%) rename tests/{ => Annotations}/Fixtures/SeveralHttpMethods/Controller.php (91%) rename tests/{ => Annotations}/Fixtures/SeveralRoutesOnOneAction/Controller.php (87%) create mode 100644 tests/Annotations/OpenApiRouteLoaderAnnotationsTest.php create mode 100644 tests/Attributes/Fixtures/Basic/Controller.php create mode 100644 tests/Attributes/Fixtures/FormatSuffix/Controller.php create mode 100644 tests/Attributes/Fixtures/OperationId/Controller.php create mode 100644 tests/Attributes/Fixtures/PathParameterPattern/Controller.php create mode 100644 tests/Attributes/Fixtures/Priority/Controller.php create mode 100644 tests/Attributes/Fixtures/SeveralClasses/BarController.php create mode 100644 tests/Attributes/Fixtures/SeveralClasses/FooController.php create mode 100644 tests/Attributes/Fixtures/SeveralClasses/SubNamespace/SubController.php create mode 100644 tests/Attributes/Fixtures/SeveralHttpMethods/Controller.php create mode 100644 tests/Attributes/Fixtures/SeveralRoutesOnOneAction/Controller.php create mode 100644 tests/Attributes/OpenApiRouteLoaderAttributesTest.php delete mode 100644 tests/OpenApiRouteLoaderTest.php diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index df4bdd0..a1753ce 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,7 @@ jobs: - name: Set up PHP uses: shivammathur/setup-php@v2 with: - php-version: '7.2' + php-version: '8.1' coverage: 'none' - name: Checkout code @@ -76,4 +76,4 @@ jobs: - name: Run tests continue-on-error: true - run: vendor/bin/simple-phpunit + run: vendor/bin/simple-phpunit tests diff --git a/README.md b/README.md index ccf544b..90a9b32 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,8 @@ Version < 1.2 requires zircote/swagger-php 2.x which works with the OpenAPI Spec So tobion/openapi-symfony-routing can be used with both OpenAPI v2 and v3 and composer will select the compatible one for your dependencies. Route loading stays the same between those versions. You just need to update the annotations when migrating from OpenAPI v2 to v3. +Version >= 1.3 requires zircote/swagger-php 4.x which is compatible with the OpenAPI Specification version 3.0.1 and supports attributes. This package need php >= 8.1 for attributes support from zircote/swagger-php. + ## Basic Usage This library allows to (re-)use your OpenAPI documentation to configure the routing of your Symfony-based API. diff --git a/composer.json b/composer.json index 7d211ef..4bc5a5b 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,7 @@ "symfony/finder": "^4.4|^5.0|^6.0", "symfony/framework-bundle": "^4.4|^5.0|^6.0", "symfony/routing": "^4.4|^5.0|^6.0", - "zircote/swagger-php": "^3.0.3" + "zircote/swagger-php": "^3.0.3|^4.0" }, "require-dev": { "symfony/phpunit-bridge": "^5.2|^6.0" diff --git a/phpunit.xml b/phpunit.xml index b069900..7c908cb 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -9,7 +9,7 @@ > - tests/ + tests/Annotations diff --git a/src/OpenApiRouteLoader.php b/src/OpenApiRouteLoader.php index ad6deb4..62f8ac0 100644 --- a/src/OpenApiRouteLoader.php +++ b/src/OpenApiRouteLoader.php @@ -4,6 +4,9 @@ namespace Tobion\OpenApiSymfonyRouting; +use OpenApi\Analysers\AttributeAnnotationFactory; +use OpenApi\Analysers\DocBlockAnnotationFactory; +use OpenApi\Analysers\ReflectionAnalyser; use OpenApi\Analysis; use OpenApi\Annotations\OpenApi; use OpenApi\Annotations\Operation; @@ -86,12 +89,23 @@ private function createOpenApi(): OpenApi return \OpenApi\scan($this->finder); } - $processors = array_filter(Analysis::processors(), static function ($processor): bool { - // remove OperationId processor which would hash the controller starting in 3.2.2 breaking the default route name logic - return !$processor instanceof OperationId && !$processor instanceof DocBlockDescriptions; - }); + if (method_exists(Analysis::class, 'processors')) { + $processors = array_filter(Analysis::processors(), static function ($processor): bool { + // remove OperationId processor which would hash the controller starting in 3.2.2 breaking the default route name logic + return !$processor instanceof OperationId && !$processor instanceof DocBlockDescriptions; + }); - return (new Generator())->setProcessors($processors)->generate($this->finder); + return (new Generator())->setProcessors($processors)->generate($this->finder); + } + + $analyser = new ReflectionAnalyser([ + new AttributeAnnotationFactory(), + new DocBlockAnnotationFactory()] + ); + + return (new Generator()) + ->setAnalyser($analyser) + ->generate($this->finder); } /** diff --git a/tests/Fixtures/Basic/Controller.php b/tests/Annotations/Fixtures/Basic/Controller.php similarity index 82% rename from tests/Fixtures/Basic/Controller.php rename to tests/Annotations/Fixtures/Basic/Controller.php index bb8aa6b..c9bbdb7 100644 --- a/tests/Fixtures/Basic/Controller.php +++ b/tests/Annotations/Fixtures/Basic/Controller.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Tobion\OpenApiSymfonyRouting\Tests\Fixtures\Basic; +namespace Tobion\OpenApiSymfonyRouting\Tests\Annotations\Fixtures\Basic; use OpenApi\Annotations as OA; diff --git a/tests/Fixtures/FormatSuffix/Controller.php b/tests/Annotations/Fixtures/FormatSuffix/Controller.php similarity index 92% rename from tests/Fixtures/FormatSuffix/Controller.php rename to tests/Annotations/Fixtures/FormatSuffix/Controller.php index d08b11a..776dd8e 100644 --- a/tests/Fixtures/FormatSuffix/Controller.php +++ b/tests/Annotations/Fixtures/FormatSuffix/Controller.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Tobion\OpenApiSymfonyRouting\Tests\Fixtures\FormatSuffix; +namespace Tobion\OpenApiSymfonyRouting\Tests\Annotations\Fixtures\FormatSuffix; use OpenApi\Annotations as OA; diff --git a/tests/Fixtures/OperationId/Controller.php b/tests/Annotations/Fixtures/OperationId/Controller.php similarity index 82% rename from tests/Fixtures/OperationId/Controller.php rename to tests/Annotations/Fixtures/OperationId/Controller.php index 3784059..be63143 100644 --- a/tests/Fixtures/OperationId/Controller.php +++ b/tests/Annotations/Fixtures/OperationId/Controller.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Tobion\OpenApiSymfonyRouting\Tests\Fixtures\OperationId; +namespace Tobion\OpenApiSymfonyRouting\Tests\Annotations\Fixtures\OperationId; use OpenApi\Annotations as OA; diff --git a/tests/Fixtures/PathParameterPattern/Controller.php b/tests/Annotations/Fixtures/PathParameterPattern/Controller.php similarity index 93% rename from tests/Fixtures/PathParameterPattern/Controller.php rename to tests/Annotations/Fixtures/PathParameterPattern/Controller.php index 101bcc3..c175881 100644 --- a/tests/Fixtures/PathParameterPattern/Controller.php +++ b/tests/Annotations/Fixtures/PathParameterPattern/Controller.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Tobion\OpenApiSymfonyRouting\Tests\Fixtures\PathParameterPattern; +namespace Tobion\OpenApiSymfonyRouting\Tests\Annotations\Fixtures\PathParameterPattern; use OpenApi\Annotations as OA; diff --git a/tests/Fixtures/Priority/Controller.php b/tests/Annotations/Fixtures/Priority/Controller.php similarity index 90% rename from tests/Fixtures/Priority/Controller.php rename to tests/Annotations/Fixtures/Priority/Controller.php index 9876c69..e93790a 100644 --- a/tests/Fixtures/Priority/Controller.php +++ b/tests/Annotations/Fixtures/Priority/Controller.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Tobion\OpenApiSymfonyRouting\Tests\Fixtures\Priority; +namespace Tobion\OpenApiSymfonyRouting\Tests\Annotations\Fixtures\Priority; use OpenApi\Annotations as OA; diff --git a/tests/Fixtures/SeveralClasses/BarController.php b/tests/Annotations/Fixtures/SeveralClasses/BarController.php similarity index 80% rename from tests/Fixtures/SeveralClasses/BarController.php rename to tests/Annotations/Fixtures/SeveralClasses/BarController.php index cfc7b25..e8c0e14 100644 --- a/tests/Fixtures/SeveralClasses/BarController.php +++ b/tests/Annotations/Fixtures/SeveralClasses/BarController.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Tobion\OpenApiSymfonyRouting\Tests\Fixtures\SeveralClasses; +namespace Tobion\OpenApiSymfonyRouting\Tests\Annotations\Fixtures\SeveralClasses; use OpenApi\Annotations as OA; diff --git a/tests/Fixtures/SeveralClasses/FooController.php b/tests/Annotations/Fixtures/SeveralClasses/FooController.php similarity index 76% rename from tests/Fixtures/SeveralClasses/FooController.php rename to tests/Annotations/Fixtures/SeveralClasses/FooController.php index 1759110..71b915a 100644 --- a/tests/Fixtures/SeveralClasses/FooController.php +++ b/tests/Annotations/Fixtures/SeveralClasses/FooController.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Tobion\OpenApiSymfonyRouting\Tests\Fixtures\SeveralClasses; +namespace Tobion\OpenApiSymfonyRouting\Tests\Annotations\Fixtures\SeveralClasses; use OpenApi\Annotations as OA; diff --git a/tests/Fixtures/SeveralClasses/SubNamespace/SubController.php b/tests/Annotations/Fixtures/SeveralClasses/SubNamespace/SubController.php similarity index 73% rename from tests/Fixtures/SeveralClasses/SubNamespace/SubController.php rename to tests/Annotations/Fixtures/SeveralClasses/SubNamespace/SubController.php index cea9f38..22d835a 100644 --- a/tests/Fixtures/SeveralClasses/SubNamespace/SubController.php +++ b/tests/Annotations/Fixtures/SeveralClasses/SubNamespace/SubController.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Tobion\OpenApiSymfonyRouting\Tests\Fixtures\SeveralClasses\SubNamespace; +namespace Tobion\OpenApiSymfonyRouting\Tests\Annotations\Fixtures\SeveralClasses\SubNamespace; use OpenApi\Annotations as OA; diff --git a/tests/Fixtures/SeveralHttpMethods/Controller.php b/tests/Annotations/Fixtures/SeveralHttpMethods/Controller.php similarity index 91% rename from tests/Fixtures/SeveralHttpMethods/Controller.php rename to tests/Annotations/Fixtures/SeveralHttpMethods/Controller.php index 16cb272..0f73f35 100644 --- a/tests/Fixtures/SeveralHttpMethods/Controller.php +++ b/tests/Annotations/Fixtures/SeveralHttpMethods/Controller.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Tobion\OpenApiSymfonyRouting\Tests\Fixtures\SeveralHttpMethods; +namespace Tobion\OpenApiSymfonyRouting\Tests\Annotations\Fixtures\SeveralHttpMethods; use OpenApi\Annotations as OA; diff --git a/tests/Fixtures/SeveralRoutesOnOneAction/Controller.php b/tests/Annotations/Fixtures/SeveralRoutesOnOneAction/Controller.php similarity index 87% rename from tests/Fixtures/SeveralRoutesOnOneAction/Controller.php rename to tests/Annotations/Fixtures/SeveralRoutesOnOneAction/Controller.php index 6c34762..6749df2 100644 --- a/tests/Fixtures/SeveralRoutesOnOneAction/Controller.php +++ b/tests/Annotations/Fixtures/SeveralRoutesOnOneAction/Controller.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Tobion\OpenApiSymfonyRouting\Tests\Fixtures\SeveralRoutesOnOneAction; +namespace Tobion\OpenApiSymfonyRouting\Tests\Annotations\Fixtures\SeveralRoutesOnOneAction; use OpenApi\Annotations as OA; diff --git a/tests/Annotations/OpenApiRouteLoaderAnnotationsTest.php b/tests/Annotations/OpenApiRouteLoaderAnnotationsTest.php new file mode 100644 index 0000000..a921afe --- /dev/null +++ b/tests/Annotations/OpenApiRouteLoaderAnnotationsTest.php @@ -0,0 +1,233 @@ +__invoke(); + + foreach ($routes as $route) { + $this->assertEquals( + $route, + (new Route('/foobar')) + ->setMethods('GET') + ->setDefault('_controller', BasicController::class.'::__invoke') + ); + } + } + + public function testFormatSuffix(): void + { + $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures//FormatSuffix'); + + $routes = $routeLoader->__invoke(); + + $expectedRoutes = []; + $expectedRoutes[] = (new Route('/a.{_format}')) + ->setDefault('_format', null) + ->setMethods('GET') + ->setDefault('_controller', FormatSuffixController::class.'::inheritEnabledFormatSuffix'); + $expectedRoutes[] = (new Route('/b.{_format}')) + ->setDefault('_format', null) + ->setRequirement('_format', 'json|xml') + ->setMethods('GET') + ->setDefault('_controller', FormatSuffixController::class.'::defineFormatPattern'); + $expectedRoutes[] = (new Route('/c')) + ->setMethods('GET') + ->setDefault('_controller', FormatSuffixController::class.'::disableFormatSuffix'); + + $index = 0; + foreach ($routes as $route) { + $this->assertEquals($route, $expectedRoutes[$index++]); + } + } + + public function testOperationId(): void + { + $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures//OperationId'); + + $routes = $routeLoader->__invoke(); + + $expectedRoutes = new RouteCollection(); + $expectedRoutes->add( + 'my-name', + (new Route('/foobar'))->setMethods('GET')->setDefault('_controller', OperationIdController::class.'::__invoke') + ); + + self::assertEquals($expectedRoutes, $routes); + } + + public function testPathParameterPattern(): void + { + $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures//PathParameterPattern'); + + $routes = $routeLoader->__invoke(); + + $expectedRoutes = []; + $expectedRoutes[] = (new Route('/foo/{id}')) + ->setMethods('GET') + ->setDefault('_controller', PathParameterPatternController::class.'::noPattern'); + $expectedRoutes[] = (new Route('/baz/{id}')) + ->setMethods('GET') + ->setDefault('_controller', PathParameterPatternController::class.'::noSchema'); + $expectedRoutes[] = (new Route('/bar/{id}')) + ->setRequirement('id', '^[a-zA-Z0-9]+$') + ->setMethods('GET') + ->setDefault('_controller', PathParameterPatternController::class.'::withPattern'); + + $index = 0; + foreach ($routes as $route) { + $this->assertEquals($route, $expectedRoutes[$index++]); + } + } + + public function testPriority(): void + { + $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures//Priority'); + + $routes = $routeLoader->__invoke(); + + $expectedRoutes = []; + $expectedRoutes[] = (new Route('/bar')) + ->setMethods('GET') + ->setDefault('_controller', PriorityController::class.'::bar'); + $expectedRoutes[] = (new Route('/foo')) + ->setMethods('GET') + ->setDefault('_controller', PriorityController::class.'::foo'); + $expectedRoutes[] = (new Route('/{catchall}')) + ->setMethods('GET') + ->setDefault('_controller', PriorityController::class.'::catchall'); + + $index = 0; + foreach ($routes as $route) { + $this->assertEquals($route, $expectedRoutes[$index++]); + } + } + + public function testSeveralClasses(): void + { + $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures//SeveralClasses'); + + $routes = $routeLoader->__invoke(); + + $expectedRoutes = []; + $expectedRoutes[] = (new Route('/bar')) + ->setMethods('GET') + ->setDefault('_controller', BarController::class.'::__invoke'); + $expectedRoutes[] = (new Route('/foo')) + ->setMethods('GET') + ->setDefault('_controller', FooController::class.'::__invoke'); + $expectedRoutes[] = (new Route('/sub')) + ->setMethods('GET') + ->setDefault('_controller', SubController::class.'::__invoke'); + + $index = 0; + foreach ($routes as $route) { + $this->assertEquals($route, $expectedRoutes[$index++]); + } + } + + public function testSeveralHttpMethods(): void + { + $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures//SeveralHttpMethods'); + + $routes = $routeLoader->__invoke(); + + $expectedRoutes = []; + $expectedRoutes[] = (new Route('/foobar')) + ->setMethods('GET') + ->setDefault('_controller', SeveralHttpMethodsController::class.'::get'); + $expectedRoutes[] = (new Route('/foobar')) + ->setMethods('PUT') + ->setDefault('_controller', SeveralHttpMethodsController::class.'::put'); + $expectedRoutes[] = (new Route('/foobar')) + ->setMethods('POST') + ->setDefault('_controller', SeveralHttpMethodsController::class.'::post'); + $expectedRoutes[] = (new Route('/foobar')) + ->setMethods('DELETE') + ->setDefault('_controller', SeveralHttpMethodsController::class.'::delete'); + + $index = 0; + foreach ($routes as $route) { + $this->assertEquals($route, $expectedRoutes[$index++]); + } + } + + public function testSeveralRoutesOnOneAction(): void + { + $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures//SeveralRoutesOnOneAction'); + + $routes = $routeLoader->__invoke(); + + $expectedRoutes = []; + $expectedRoutes[] = (new Route('/foobar')) + ->setMethods('GET') + ->setDefault('_controller', SeveralRoutesOnOneActionController::class.'::__invoke'); + $expectedRoutes[] = (new Route('/foobar')) + ->setMethods('POST') + ->setDefault('_controller', SeveralRoutesOnOneActionController::class.'::__invoke'); + $expectedRoutes[] = (new Route('/foo-bar')) + ->setMethods('GET') + ->setDefault('_controller', SeveralRoutesOnOneActionController::class.'::__invoke'); + + $index = 0; + foreach ($routes as $route) { + $this->assertEquals($route, $expectedRoutes[$index++]); + } + } + + public function testSeveralDirectories(): void + { + $routeLoader = OpenApiRouteLoader::fromDirectories( + __DIR__.'/Fixtures//Basic', + __DIR__.'/Fixtures//SeveralClasses/SubNamespace' + ); + + $routes = $routeLoader->__invoke(); + + $expectedRoutes = []; + $expectedRoutes[] = (new Route('/foobar')) + ->setMethods('GET') + ->setDefault('_controller', BasicController::class.'::__invoke'); + $expectedRoutes[] = (new Route('/sub')) + ->setMethods('GET') + ->setDefault('_controller', SubController::class.'::__invoke'); + + $index = 0; + foreach ($routes as $route) { + $this->assertEquals($route, $expectedRoutes[$index++]); + } + } + + public function testSrcDirectoryDoesNotExist(): void + { + self::expectException(DirectoryNotFoundException::class); + self::expectExceptionMessage('/../../../../src" directory does not exist'); + + OpenApiRouteLoader::fromSrcDirectory(); + } +} diff --git a/tests/Attributes/Fixtures/Basic/Controller.php b/tests/Attributes/Fixtures/Basic/Controller.php new file mode 100644 index 0000000..d59c712 --- /dev/null +++ b/tests/Attributes/Fixtures/Basic/Controller.php @@ -0,0 +1,20 @@ + [ + "enabled" => true + ] + ] +)] +class Controller +{ + #[OAT\Get(path: "/a",)] + #[OAT\Response(response: "200", description: "Success")] + public function inheritEnabledFormatSuffix(): void + { + } + + #[OAT\Get(path: "/b", x: ["format-suffix" => ["pattern" => "json|xml"]])] + #[OAT\Response(response: "200", description: "Success")] + public function defineFormatPattern(): void + { + } + + #[OAT\Get(path: "/c", x: ["format-suffix" => false])] + #[OAT\Response(response: "200", description: "Success")] + public function disableFormatSuffix(): void + { + } +} diff --git a/tests/Attributes/Fixtures/OperationId/Controller.php b/tests/Attributes/Fixtures/OperationId/Controller.php new file mode 100644 index 0000000..223b55a --- /dev/null +++ b/tests/Attributes/Fixtures/OperationId/Controller.php @@ -0,0 +1,17 @@ + -100])] + #[OAT\Response(response:"200", description:"Success")] + public function catchall(): void + { + } + + #[OAT\Get(path:"/bar", x: ["priority" => 10])] + #[OAT\Response(response:"200", description:"Success")] + public function bar(): void + { + } +} diff --git a/tests/Attributes/Fixtures/SeveralClasses/BarController.php b/tests/Attributes/Fixtures/SeveralClasses/BarController.php new file mode 100644 index 0000000..81a6c98 --- /dev/null +++ b/tests/Attributes/Fixtures/SeveralClasses/BarController.php @@ -0,0 +1,17 @@ +__invoke(); + + foreach ($routes as $route) { + $this->assertEquals( + $route, + (new Route('/foobar')) + ->setMethods('GET') + ->setDefault('_controller', BasicController::class.'::__invoke') + ); + } + } + + public function testFormatSuffix(): void + { + $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures//FormatSuffix'); + + $routes = $routeLoader->__invoke(); + + $expectedRoutes = []; + $expectedRoutes[] = (new Route('/a.{_format}')) + ->setDefault('_format', null) + ->setMethods('GET') + ->setDefault('_controller', FormatSuffixController::class.'::inheritEnabledFormatSuffix'); + $expectedRoutes[] = (new Route('/b.{_format}')) + ->setDefault('_format', null) + ->setRequirement('_format', 'json|xml') + ->setMethods('GET') + ->setDefault('_controller', FormatSuffixController::class.'::defineFormatPattern'); + $expectedRoutes[] = (new Route('/c')) + ->setMethods('GET') + ->setDefault('_controller', FormatSuffixController::class.'::disableFormatSuffix'); + + $index = 0; + foreach ($routes as $route) { + $this->assertEquals($route, $expectedRoutes[$index++]); + } + } + + public function testOperationId(): void + { + $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures//OperationId'); + + $routes = $routeLoader->__invoke(); + + $expectedRoutes = new RouteCollection(); + $expectedRoutes->add( + 'my-name', + (new Route('/foobar'))->setMethods('GET')->setDefault('_controller', OperationIdController::class.'::__invoke') + ); + + self::assertEquals($expectedRoutes, $routes); + } + + public function testPathParameterPattern(): void + { + $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures//PathParameterPattern'); + + $routes = $routeLoader->__invoke(); + + $expectedRoutes = []; + $expectedRoutes[] = (new Route('/foo/{id}')) + ->setMethods('GET') + ->setDefault('_controller', PathParameterPatternController::class.'::noPattern'); + $expectedRoutes[] = (new Route('/baz/{id}')) + ->setMethods('GET') + ->setDefault('_controller', PathParameterPatternController::class.'::noSchema'); + $expectedRoutes[] = (new Route('/bar/{id}')) + ->setRequirement('id', '^[a-zA-Z0-9]+$') + ->setMethods('GET') + ->setDefault('_controller', PathParameterPatternController::class.'::withPattern'); + + $index = 0; + foreach ($routes as $route) { + $this->assertEquals($route, $expectedRoutes[$index++]); + } + } + + public function testPriority(): void + { + $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures//Priority'); + + $routes = $routeLoader->__invoke(); + + $expectedRoutes = []; + $expectedRoutes[] = (new Route('/bar')) + ->setMethods('GET') + ->setDefault('_controller', PriorityController::class.'::bar'); + $expectedRoutes[] = (new Route('/foo')) + ->setMethods('GET') + ->setDefault('_controller', PriorityController::class.'::foo'); + $expectedRoutes[] = (new Route('/{catchall}')) + ->setMethods('GET') + ->setDefault('_controller', PriorityController::class.'::catchall'); + + $index = 0; + foreach ($routes as $route) { + $this->assertEquals($route, $expectedRoutes[$index++]); + } + } + + public function testSeveralClasses(): void + { + $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures//SeveralClasses'); + + $routes = $routeLoader->__invoke(); + + $expectedRoutes = []; + $expectedRoutes[] = (new Route('/bar')) + ->setMethods('GET') + ->setDefault('_controller', BarController::class.'::__invoke'); + $expectedRoutes[] = (new Route('/foo')) + ->setMethods('GET') + ->setDefault('_controller', FooController::class.'::__invoke'); + $expectedRoutes[] = (new Route('/sub')) + ->setMethods('GET') + ->setDefault('_controller', SubController::class.'::__invoke'); + + $index = 0; + foreach ($routes as $route) { + $this->assertEquals($route, $expectedRoutes[$index++]); + } + } + + public function testSeveralHttpMethods(): void + { + $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures//SeveralHttpMethods'); + + $routes = $routeLoader->__invoke(); + + $expectedRoutes = []; + $expectedRoutes[] = (new Route('/foobar')) + ->setMethods('GET') + ->setDefault('_controller', SeveralHttpMethodsController::class.'::get'); + $expectedRoutes[] = (new Route('/foobar')) + ->setMethods('PUT') + ->setDefault('_controller', SeveralHttpMethodsController::class.'::put'); + $expectedRoutes[] = (new Route('/foobar')) + ->setMethods('POST') + ->setDefault('_controller', SeveralHttpMethodsController::class.'::post'); + $expectedRoutes[] = (new Route('/foobar')) + ->setMethods('DELETE') + ->setDefault('_controller', SeveralHttpMethodsController::class.'::delete'); + + $index = 0; + foreach ($routes as $route) { + $this->assertEquals($route, $expectedRoutes[$index++]); + } + } + + public function testSeveralRoutesOnOneAction(): void + { + $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures//SeveralRoutesOnOneAction'); + + $routes = $routeLoader->__invoke(); + + $expectedRoutes = []; + $expectedRoutes[] = (new Route('/foobar')) + ->setMethods('GET') + ->setDefault('_controller', SeveralRoutesOnOneActionController::class.'::__invoke'); + $expectedRoutes[] = (new Route('/foobar')) + ->setMethods('POST') + ->setDefault('_controller', SeveralRoutesOnOneActionController::class.'::__invoke'); + $expectedRoutes[] = (new Route('/foo-bar')) + ->setMethods('GET') + ->setDefault('_controller', SeveralRoutesOnOneActionController::class.'::__invoke'); + + $index = 0; + foreach ($routes as $route) { + $this->assertEquals($route, $expectedRoutes[$index++]); + } + } + + public function testSeveralDirectories(): void + { + $routeLoader = OpenApiRouteLoader::fromDirectories( + __DIR__.'/Fixtures//Basic', + __DIR__.'/Fixtures//SeveralClasses/SubNamespace' + ); + + $routes = $routeLoader->__invoke(); + + $expectedRoutes = []; + $expectedRoutes[] = (new Route('/foobar')) + ->setMethods('GET') + ->setDefault('_controller', BasicController::class.'::__invoke'); + $expectedRoutes[] = (new Route('/sub')) + ->setMethods('GET') + ->setDefault('_controller', SubController::class.'::__invoke'); + + $index = 0; + foreach ($routes as $route) { + $this->assertEquals($route, $expectedRoutes[$index++]); + } + } + + public function testSrcDirectoryDoesNotExist(): void + { + self::expectException(DirectoryNotFoundException::class); + self::expectExceptionMessage('/../../../../src" directory does not exist'); + + OpenApiRouteLoader::fromSrcDirectory(); + } +} diff --git a/tests/OpenApiRouteLoaderTest.php b/tests/OpenApiRouteLoaderTest.php deleted file mode 100644 index 2003010..0000000 --- a/tests/OpenApiRouteLoaderTest.php +++ /dev/null @@ -1,228 +0,0 @@ -__invoke(); - - $expectedRoutes = new RouteCollection(); - $expectedRoutes->add( - self::FIXTURES_ROUTE_NAME_PREFIX.'basic__invoke', - (new Route('/foobar'))->setMethods('GET')->setDefault('_controller', BasicController::class.'::__invoke') - ); - - self::assertEquals($expectedRoutes, $routes); - } - - public function testFormatSuffix(): void - { - $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures/FormatSuffix'); - - $routes = $routeLoader->__invoke(); - - $expectedRoutes = new RouteCollection(); - $expectedRoutes->add( - self::FIXTURES_ROUTE_NAME_PREFIX.'formatsuffix_inheritenabledformatsuffix', - (new Route('/a.{_format}'))->setDefault('_format', null)->setMethods('GET')->setDefault('_controller', FormatSuffixController::class.'::inheritEnabledFormatSuffix') - ); - $expectedRoutes->add( - self::FIXTURES_ROUTE_NAME_PREFIX.'formatsuffix_defineformatpattern', - (new Route('/b.{_format}'))->setDefault('_format', null)->setRequirement('_format', 'json|xml')->setMethods('GET')->setDefault('_controller', FormatSuffixController::class.'::defineFormatPattern') - ); - $expectedRoutes->add( - self::FIXTURES_ROUTE_NAME_PREFIX.'formatsuffix_disableformatsuffix', - (new Route('/c'))->setMethods('GET')->setDefault('_controller', FormatSuffixController::class.'::disableFormatSuffix') - ); - - self::assertEquals($expectedRoutes, $routes); - } - - public function testOperationId(): void - { - $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures/OperationId'); - - $routes = $routeLoader->__invoke(); - - $expectedRoutes = new RouteCollection(); - $expectedRoutes->add( - 'my-name', - (new Route('/foobar'))->setMethods('GET')->setDefault('_controller', OperationIdController::class.'::__invoke') - ); - - self::assertEquals($expectedRoutes, $routes); - } - - public function testPathParameterPattern(): void - { - $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures/PathParameterPattern'); - - $routes = $routeLoader->__invoke(); - - $expectedRoutes = new RouteCollection(); - $expectedRoutes->add( - self::FIXTURES_ROUTE_NAME_PREFIX.'pathparameterpattern_nopattern', - (new Route('/foo/{id}'))->setMethods('GET')->setDefault('_controller', PathParameterPatternController::class.'::noPattern') - ); - $expectedRoutes->add( - self::FIXTURES_ROUTE_NAME_PREFIX.'pathparameterpattern_noschema', - (new Route('/baz/{id}'))->setMethods('GET')->setDefault('_controller', PathParameterPatternController::class.'::noSchema') - ); - // OpenAPI needs the param pattern to be anchored (^$) to have the desired effect. Symfony automatically trims those to get a valid full path regex. - $expectedRoutes->add( - self::FIXTURES_ROUTE_NAME_PREFIX.'pathparameterpattern_withpattern', - (new Route('/bar/{id}'))->setRequirement('id', '^[a-zA-Z0-9]+$')->setMethods('GET')->setDefault('_controller', PathParameterPatternController::class.'::withPattern') - ); - - self::assertEquals($expectedRoutes, $routes); - } - - public function testPriority(): void - { - $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures/Priority'); - - $routes = $routeLoader->__invoke(); - - $expectedRoutes = new RouteCollection(); - $expectedRoutes->add( - self::FIXTURES_ROUTE_NAME_PREFIX.'priority_foo', - (new Route('/foo'))->setMethods('GET')->setDefault('_controller', PriorityController::class.'::foo') - ); - $expectedRoutes->add( - self::FIXTURES_ROUTE_NAME_PREFIX.'priority_catchall', - (new Route('/{catchall}'))->setMethods('GET')->setDefault('_controller', PriorityController::class.'::catchall'), - -100 - ); - $expectedRoutes->add( - self::FIXTURES_ROUTE_NAME_PREFIX.'priority_bar', - (new Route('/bar'))->setMethods('GET')->setDefault('_controller', PriorityController::class.'::bar'), - 10 - ); - - self::assertEquals($expectedRoutes, $routes); - } - - public function testSeveralClasses(): void - { - $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures/SeveralClasses'); - - $routes = $routeLoader->__invoke(); - - $expectedRoutes = new RouteCollection(); - $expectedRoutes->add( - self::FIXTURES_ROUTE_NAME_PREFIX.'severalclasses_bar__invoke', - (new Route('/bar'))->setMethods('GET')->setDefault('_controller', BarController::class.'::__invoke') - ); - $expectedRoutes->add( - self::FIXTURES_ROUTE_NAME_PREFIX.'severalclasses_foo__invoke', - (new Route('/foo'))->setMethods('GET')->setDefault('_controller', FooController::class.'::__invoke') - ); - $expectedRoutes->add( - self::FIXTURES_ROUTE_NAME_PREFIX.'severalclasses_subnamespace_sub__invoke', - (new Route('/sub'))->setMethods('GET')->setDefault('_controller', SubController::class.'::__invoke') - ); - - self::assertEquals($expectedRoutes, $routes); - } - - public function testSeveralHttpMethods(): void - { - $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures/SeveralHttpMethods'); - - $routes = $routeLoader->__invoke(); - - $expectedRoutes = new RouteCollection(); - $expectedRoutes->add( - self::FIXTURES_ROUTE_NAME_PREFIX.'severalhttpmethods_get', - (new Route('/foobar'))->setMethods('GET')->setDefault('_controller', SeveralHttpMethodsController::class.'::get') - ); - $expectedRoutes->add( - self::FIXTURES_ROUTE_NAME_PREFIX.'severalhttpmethods_put', - (new Route('/foobar'))->setMethods('PUT')->setDefault('_controller', SeveralHttpMethodsController::class.'::put') - ); - $expectedRoutes->add( - self::FIXTURES_ROUTE_NAME_PREFIX.'severalhttpmethods_post', - (new Route('/foobar'))->setMethods('POST')->setDefault('_controller', SeveralHttpMethodsController::class.'::post') - ); - $expectedRoutes->add( - self::FIXTURES_ROUTE_NAME_PREFIX.'severalhttpmethods_delete', - (new Route('/foobar'))->setMethods('DELETE')->setDefault('_controller', SeveralHttpMethodsController::class.'::delete') - ); - - self::assertEquals($expectedRoutes, $routes); - } - - public function testSeveralRoutesOnOneAction(): void - { - $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures/SeveralRoutesOnOneAction'); - - $routes = $routeLoader->__invoke(); - - $expectedRoutes = new RouteCollection(); - $expectedRoutes->add( - self::FIXTURES_ROUTE_NAME_PREFIX.'severalroutesononeaction__invoke', - (new Route('/foobar'))->setMethods('GET')->setDefault('_controller', SeveralRoutesOnOneActionController::class.'::__invoke') - ); - $expectedRoutes->add( - self::FIXTURES_ROUTE_NAME_PREFIX.'severalroutesononeaction__invoke_1', - (new Route('/foobar'))->setMethods('POST')->setDefault('_controller', SeveralRoutesOnOneActionController::class.'::__invoke') - ); - $expectedRoutes->add( - 'my-name', - (new Route('/foo-bar'))->setMethods('GET')->setDefault('_controller', SeveralRoutesOnOneActionController::class.'::__invoke') - ); - - self::assertEquals($expectedRoutes, $routes); - } - - public function testSeveralDirectories(): void - { - $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures/Basic', __DIR__.'/Fixtures/SeveralClasses/SubNamespace'); - - $routes = $routeLoader->__invoke(); - - $expectedRoutes = new RouteCollection(); - $expectedRoutes->add( - self::FIXTURES_ROUTE_NAME_PREFIX.'basic__invoke', - (new Route('/foobar'))->setMethods('GET')->setDefault('_controller', BasicController::class.'::__invoke') - ); - $expectedRoutes->add( - self::FIXTURES_ROUTE_NAME_PREFIX.'severalclasses_subnamespace_sub__invoke', - (new Route('/sub'))->setMethods('GET')->setDefault('_controller', SubController::class.'::__invoke') - ); - - self::assertEquals($expectedRoutes, $routes); - } - - public function testSrcDirectoryDoesNotExist(): void - { - self::expectException(DirectoryNotFoundException::class); - self::expectExceptionMessage('/../../../../src" directory does not exist'); - - OpenApiRouteLoader::fromSrcDirectory(); - } -} From 84095e62c1a8d2d027c2e2cfc79058bfd51c963f Mon Sep 17 00:00:00 2001 From: Donii Sergii Date: Wed, 13 Apr 2022 15:02:09 +0300 Subject: [PATCH 2/6] Create php.yml --- .github/workflows/php.yml | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 .github/workflows/php.yml diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml new file mode 100644 index 0000000..5ff27cd --- /dev/null +++ b/.github/workflows/php.yml @@ -0,0 +1,39 @@ +name: PHP Composer + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +permissions: + contents: read + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - name: Validate composer.json and composer.lock + run: composer validate --strict + + - name: Cache Composer packages + id: composer-cache + uses: actions/cache@v3 + with: + path: vendor + key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} + restore-keys: | + ${{ runner.os }}-php- + + - name: Install dependencies + run: composer install --prefer-dist --no-progress + + # Add a test script to composer.json, for instance: "test": "vendor/bin/phpunit" + # Docs: https://getcomposer.org/doc/articles/scripts.md + + # - name: Run test suite + # run: composer run-script test From 0bd46daee5a6066366f30580d290a457e00ba02e Mon Sep 17 00:00:00 2001 From: Serhii Donii Date: Wed, 13 Apr 2022 15:03:26 +0300 Subject: [PATCH 3/6] remove unusages workflow --- .github/workflows/php.yml | 39 --------------------------------------- 1 file changed, 39 deletions(-) delete mode 100644 .github/workflows/php.yml diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml deleted file mode 100644 index 5ff27cd..0000000 --- a/.github/workflows/php.yml +++ /dev/null @@ -1,39 +0,0 @@ -name: PHP Composer - -on: - push: - branches: [ master ] - pull_request: - branches: [ master ] - -permissions: - contents: read - -jobs: - build: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - - - name: Validate composer.json and composer.lock - run: composer validate --strict - - - name: Cache Composer packages - id: composer-cache - uses: actions/cache@v3 - with: - path: vendor - key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} - restore-keys: | - ${{ runner.os }}-php- - - - name: Install dependencies - run: composer install --prefer-dist --no-progress - - # Add a test script to composer.json, for instance: "test": "vendor/bin/phpunit" - # Docs: https://getcomposer.org/doc/articles/scripts.md - - # - name: Run test suite - # run: composer run-script test From 68dadeef902095d28c4801b84f2826a75e739ffb Mon Sep 17 00:00:00 2001 From: Serhii Donii Date: Wed, 13 Apr 2022 15:35:32 +0300 Subject: [PATCH 4/6] remove double slashes --- .../OpenApiRouteLoaderAnnotationsTest.php | 20 +++++++++---------- .../OpenApiRouteLoaderAttributesTest.php | 20 +++++++++---------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/tests/Annotations/OpenApiRouteLoaderAnnotationsTest.php b/tests/Annotations/OpenApiRouteLoaderAnnotationsTest.php index a921afe..d0ca392 100644 --- a/tests/Annotations/OpenApiRouteLoaderAnnotationsTest.php +++ b/tests/Annotations/OpenApiRouteLoaderAnnotationsTest.php @@ -26,7 +26,7 @@ class OpenApiRouteLoaderAnnotationsTest extends TestCase public function testBasic(): void { - $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures//Basic'); + $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures/Basic'); $routes = $routeLoader->__invoke(); @@ -42,7 +42,7 @@ public function testBasic(): void public function testFormatSuffix(): void { - $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures//FormatSuffix'); + $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures/FormatSuffix'); $routes = $routeLoader->__invoke(); @@ -68,7 +68,7 @@ public function testFormatSuffix(): void public function testOperationId(): void { - $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures//OperationId'); + $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures/OperationId'); $routes = $routeLoader->__invoke(); @@ -83,7 +83,7 @@ public function testOperationId(): void public function testPathParameterPattern(): void { - $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures//PathParameterPattern'); + $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures/PathParameterPattern'); $routes = $routeLoader->__invoke(); @@ -107,7 +107,7 @@ public function testPathParameterPattern(): void public function testPriority(): void { - $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures//Priority'); + $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures/Priority'); $routes = $routeLoader->__invoke(); @@ -130,7 +130,7 @@ public function testPriority(): void public function testSeveralClasses(): void { - $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures//SeveralClasses'); + $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures/SeveralClasses'); $routes = $routeLoader->__invoke(); @@ -153,7 +153,7 @@ public function testSeveralClasses(): void public function testSeveralHttpMethods(): void { - $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures//SeveralHttpMethods'); + $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures/SeveralHttpMethods'); $routes = $routeLoader->__invoke(); @@ -179,7 +179,7 @@ public function testSeveralHttpMethods(): void public function testSeveralRoutesOnOneAction(): void { - $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures//SeveralRoutesOnOneAction'); + $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures/SeveralRoutesOnOneAction'); $routes = $routeLoader->__invoke(); @@ -203,8 +203,8 @@ public function testSeveralRoutesOnOneAction(): void public function testSeveralDirectories(): void { $routeLoader = OpenApiRouteLoader::fromDirectories( - __DIR__.'/Fixtures//Basic', - __DIR__.'/Fixtures//SeveralClasses/SubNamespace' + __DIR__.'/Fixtures/Basic', + __DIR__.'/Fixtures/SeveralClasses/SubNamespace' ); $routes = $routeLoader->__invoke(); diff --git a/tests/Attributes/OpenApiRouteLoaderAttributesTest.php b/tests/Attributes/OpenApiRouteLoaderAttributesTest.php index 03e7305..9e55d1e 100644 --- a/tests/Attributes/OpenApiRouteLoaderAttributesTest.php +++ b/tests/Attributes/OpenApiRouteLoaderAttributesTest.php @@ -24,7 +24,7 @@ class OpenApiRouteLoaderAttributesTest extends TestCase { public function testBasic(): void { - $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures//Basic'); + $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures/Basic'); $routes = $routeLoader->__invoke(); @@ -40,7 +40,7 @@ public function testBasic(): void public function testFormatSuffix(): void { - $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures//FormatSuffix'); + $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures/FormatSuffix'); $routes = $routeLoader->__invoke(); @@ -66,7 +66,7 @@ public function testFormatSuffix(): void public function testOperationId(): void { - $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures//OperationId'); + $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures/OperationId'); $routes = $routeLoader->__invoke(); @@ -81,7 +81,7 @@ public function testOperationId(): void public function testPathParameterPattern(): void { - $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures//PathParameterPattern'); + $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures/PathParameterPattern'); $routes = $routeLoader->__invoke(); @@ -105,7 +105,7 @@ public function testPathParameterPattern(): void public function testPriority(): void { - $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures//Priority'); + $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures/Priority'); $routes = $routeLoader->__invoke(); @@ -128,7 +128,7 @@ public function testPriority(): void public function testSeveralClasses(): void { - $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures//SeveralClasses'); + $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures/SeveralClasses'); $routes = $routeLoader->__invoke(); @@ -151,7 +151,7 @@ public function testSeveralClasses(): void public function testSeveralHttpMethods(): void { - $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures//SeveralHttpMethods'); + $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures/SeveralHttpMethods'); $routes = $routeLoader->__invoke(); @@ -177,7 +177,7 @@ public function testSeveralHttpMethods(): void public function testSeveralRoutesOnOneAction(): void { - $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures//SeveralRoutesOnOneAction'); + $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures/SeveralRoutesOnOneAction'); $routes = $routeLoader->__invoke(); @@ -201,8 +201,8 @@ public function testSeveralRoutesOnOneAction(): void public function testSeveralDirectories(): void { $routeLoader = OpenApiRouteLoader::fromDirectories( - __DIR__.'/Fixtures//Basic', - __DIR__.'/Fixtures//SeveralClasses/SubNamespace' + __DIR__.'/Fixtures/Basic', + __DIR__.'/Fixtures/SeveralClasses/SubNamespace' ); $routes = $routeLoader->__invoke(); From fa7fa3587ab49aa1e306d3486b1c25a272ee4568 Mon Sep 17 00:00:00 2001 From: Serhii Donii Date: Wed, 13 Apr 2022 20:26:43 +0300 Subject: [PATCH 5/6] fix tests --- .github/workflows/ci.yml | 2 +- .gitignore | 1 + docker-compose.yml | 20 +++++++++++++++++++ .../OpenApiRouteLoaderAnnotationsTest.php | 10 +++++----- 4 files changed, 27 insertions(+), 6 deletions(-) create mode 100644 docker-compose.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a1753ce..2fe4b79 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,7 @@ jobs: - name: Set up PHP uses: shivammathur/setup-php@v2 with: - php-version: '8.1' + php-version: '7.2' coverage: 'none' - name: Checkout code diff --git a/.gitignore b/.gitignore index 0fbf908..533803b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .phpunit.result.cache composer.lock vendor/ +docker-compose.override.yml diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..e65ec00 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,20 @@ +services: + php7: + image: php:7.2-fpm + user: "1000:1000" + working_dir: /var/www/html + volumes: + - ./:/var/www/html + php8.0: + image: php:8.0-fpm + user: "1000:1000" + working_dir: /var/www/html + volumes: + - ./:/var/www/html + php8.1: + image: php:8.1-fpm + working_dir: /var/www/html + user: "1000:1000" + volumes: + - ./:/var/www/html + diff --git a/tests/Annotations/OpenApiRouteLoaderAnnotationsTest.php b/tests/Annotations/OpenApiRouteLoaderAnnotationsTest.php index d0ca392..e75a448 100644 --- a/tests/Annotations/OpenApiRouteLoaderAnnotationsTest.php +++ b/tests/Annotations/OpenApiRouteLoaderAnnotationsTest.php @@ -112,19 +112,19 @@ public function testPriority(): void $routes = $routeLoader->__invoke(); $expectedRoutes = []; - $expectedRoutes[] = (new Route('/bar')) + $expectedRoutes['/bar'] = (new Route('/bar')) ->setMethods('GET') ->setDefault('_controller', PriorityController::class.'::bar'); - $expectedRoutes[] = (new Route('/foo')) + $expectedRoutes['/foo'] = (new Route('/foo')) ->setMethods('GET') ->setDefault('_controller', PriorityController::class.'::foo'); - $expectedRoutes[] = (new Route('/{catchall}')) + $expectedRoutes['/{catchall}'] = (new Route('/{catchall}')) ->setMethods('GET') ->setDefault('_controller', PriorityController::class.'::catchall'); - $index = 0; foreach ($routes as $route) { - $this->assertEquals($route, $expectedRoutes[$index++]); + $this->assertArrayHasKey($route->getPath(), $expectedRoutes); + $this->assertEquals($route, $expectedRoutes[$route->getPath()]); } } From 68ccbbcc73a842a9988056a39cab09ebf5f5fa99 Mon Sep 17 00:00:00 2001 From: Serhii Donii Date: Mon, 18 Apr 2022 15:18:27 +0300 Subject: [PATCH 6/6] add php attributes support https://github.com/Tobion/OpenAPI-Symfony-Routing/issues/12 add path parameter enum Also need to add tests for new features like OA\PathParameter and enums, see example zircote/swagger-php#1060 --- .github/workflows/ci.yml | 2 +- .gitignore | 1 - README.md | 2 +- add_composer.sh | 10 + composer.json | 2 +- phpunit.xml | 2 +- src/OpenApiRouteLoader.php | 46 +++- .../OpenApiRouteLoaderAnnotationsTest.php | 241 +++++++++-------- .../Attributes/Fixtures/Basic/Controller.php | 11 +- .../Fixtures/FormatSuffix/Controller.php | 18 +- .../Fixtures/OperationId/Controller.php | 8 +- .../PathParameterPattern/Controller.php | 40 +-- .../Fixtures/Priority/Controller.php | 16 +- .../Fixtures/SeveralClasses/BarController.php | 8 +- .../Fixtures/SeveralClasses/FooController.php | 6 +- .../SubNamespace/SubController.php | 6 +- .../SeveralHttpMethods/Controller.php | 20 +- .../SeveralRoutesOnOneAction/Controller.php | 10 +- .../OpenApiRouteLoaderAttributesTest.php | 248 +++++++++--------- 19 files changed, 363 insertions(+), 334 deletions(-) create mode 100644 add_composer.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2fe4b79..df4bdd0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -76,4 +76,4 @@ jobs: - name: Run tests continue-on-error: true - run: vendor/bin/simple-phpunit tests + run: vendor/bin/simple-phpunit diff --git a/.gitignore b/.gitignore index 533803b..0fbf908 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ .phpunit.result.cache composer.lock vendor/ -docker-compose.override.yml diff --git a/README.md b/README.md index 90a9b32..761addf 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Version < 1.2 requires zircote/swagger-php 2.x which works with the OpenAPI Spec So tobion/openapi-symfony-routing can be used with both OpenAPI v2 and v3 and composer will select the compatible one for your dependencies. Route loading stays the same between those versions. You just need to update the annotations when migrating from OpenAPI v2 to v3. -Version >= 1.3 requires zircote/swagger-php 4.x which is compatible with the OpenAPI Specification version 3.0.1 and supports attributes. This package need php >= 8.1 for attributes support from zircote/swagger-php. +Version >= 1.3 requires zircote/swagger-php >=4.1 which is compatible with the OpenAPI Specification version 3.0.1 and supports attributes. This package need php >= 8.1 for attributes support from zircote/swagger-php. ## Basic Usage diff --git a/add_composer.sh b/add_composer.sh new file mode 100644 index 0000000..3dc47eb --- /dev/null +++ b/add_composer.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +export COMPOSER_HOME=/tmp/composer + +php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" +php -r "if (hash_file('sha384', 'composer-setup.php') === '906a84df04cea2aa72f40b5f787e49f22d4c2f19492ac310e8cba5b96ac8b64115ac402c8cd292b8a03482574915d1a8') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" +php composer-setup.php +php -r "unlink('composer-setup.php');" +chmod +x composer.phar +mv composer.phar composer diff --git a/composer.json b/composer.json index 4bc5a5b..0fcaf40 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,7 @@ "symfony/finder": "^4.4|^5.0|^6.0", "symfony/framework-bundle": "^4.4|^5.0|^6.0", "symfony/routing": "^4.4|^5.0|^6.0", - "zircote/swagger-php": "^3.0.3|^4.0" + "zircote/swagger-php": "^3.0.3|^4.1" }, "require-dev": { "symfony/phpunit-bridge": "^5.2|^6.0" diff --git a/phpunit.xml b/phpunit.xml index 7c908cb..b069900 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -9,7 +9,7 @@ > - tests/Annotations + tests/ diff --git a/src/OpenApiRouteLoader.php b/src/OpenApiRouteLoader.php index 62f8ac0..67622c4 100644 --- a/src/OpenApiRouteLoader.php +++ b/src/OpenApiRouteLoader.php @@ -4,9 +4,6 @@ namespace Tobion\OpenApiSymfonyRouting; -use OpenApi\Analysers\AttributeAnnotationFactory; -use OpenApi\Analysers\DocBlockAnnotationFactory; -use OpenApi\Analysers\ReflectionAnalyser; use OpenApi\Analysis; use OpenApi\Annotations\OpenApi; use OpenApi\Annotations\Operation; @@ -30,6 +27,11 @@ class OpenApiRouteLoader implements RouteLoaderInterface */ private $routeNames = []; + /** + * @var null|Generator + */ + private $generator = null; + /** * @var string */ @@ -89,23 +91,30 @@ private function createOpenApi(): OpenApi return \OpenApi\scan($this->finder); } + if (null !== $this->generator) { + return $this->generator->generate($this->finder); + } + if (method_exists(Analysis::class, 'processors')) { $processors = array_filter(Analysis::processors(), static function ($processor): bool { // remove OperationId processor which would hash the controller starting in 3.2.2 breaking the default route name logic return !$processor instanceof OperationId && !$processor instanceof DocBlockDescriptions; }); - return (new Generator())->setProcessors($processors)->generate($this->finder); + $this->generator = (new Generator())->setProcessors($this->filterProcessors($processors)); + + return $this->generator->generate($this->finder); } - $analyser = new ReflectionAnalyser([ - new AttributeAnnotationFactory(), - new DocBlockAnnotationFactory()] + $this->generator = new Generator(); + + $this->generator->setProcessors( + $this->filterProcessors( + $this->generator->getProcessors() + ) ); - return (new Generator()) - ->setAnalyser($analyser) - ->generate($this->finder); + return $this->generator->generate($this->finder); } /** @@ -142,8 +151,14 @@ private function createRoute(Operation $operation, string $controller, FormatSuf } if (self::$openApiUndefined !== $operation->parameters) { foreach ($operation->parameters as $parameter) { - if ('path' === $parameter->in && self::$openApiUndefined !== $parameter->schema && self::$openApiUndefined !== $parameter->schema->pattern) { - $route->setRequirement($parameter->name, $parameter->schema->pattern); + if ('path' === $parameter->in && self::$openApiUndefined !== $parameter->schema) { + if (self::$openApiUndefined !== $parameter->schema->pattern) { + $route->setRequirement($parameter->name, $parameter->schema->pattern); + } + + if (self::$openApiUndefined !== $parameter->schema->enum) { + $route->setRequirement($parameter->name, implode('|', $parameter->schema->enum)); + } } } } @@ -204,4 +219,11 @@ private function getDefaultRouteName(string $controller): string return $name; } + + private function filterProcessors(array $processors): array + { + return array_filter($processors, static function ($processor): bool { + return !$processor instanceof OperationId && !$processor instanceof DocBlockDescriptions; + }); + } } diff --git a/tests/Annotations/OpenApiRouteLoaderAnnotationsTest.php b/tests/Annotations/OpenApiRouteLoaderAnnotationsTest.php index e75a448..59e2ac1 100644 --- a/tests/Annotations/OpenApiRouteLoaderAnnotationsTest.php +++ b/tests/Annotations/OpenApiRouteLoaderAnnotationsTest.php @@ -20,9 +20,9 @@ use Tobion\OpenApiSymfonyRouting\Tests\Annotations\Fixtures\SeveralHttpMethods\Controller as SeveralHttpMethodsController; use Tobion\OpenApiSymfonyRouting\Tests\Annotations\Fixtures\SeveralRoutesOnOneAction\Controller as SeveralRoutesOnOneActionController; -class OpenApiRouteLoaderAnnotationsTest extends TestCase +final class OpenApiRouteLoaderAnnotationsTest extends TestCase { - private const FIXTURES_ROUTE_NAME_PREFIX = 'tobion_openapisymfonyrouting_tests_fixtures_annotations_'; + private const FIXTURES_ROUTE_NAME_PREFIX = 'tobion_openapisymfonyrouting_tests_annotations_fixtures_'; public function testBasic(): void { @@ -30,14 +30,13 @@ public function testBasic(): void $routes = $routeLoader->__invoke(); - foreach ($routes as $route) { - $this->assertEquals( - $route, - (new Route('/foobar')) - ->setMethods('GET') - ->setDefault('_controller', BasicController::class.'::__invoke') - ); - } + $expectedRoutes = new RouteCollection(); + $expectedRoutes->add( + self::FIXTURES_ROUTE_NAME_PREFIX.'basic__invoke', + (new Route('/foobar'))->setMethods('GET')->setDefault('_controller', BasicController::class.'::__invoke') + ); + + self::assertEquals($expectedRoutes, $routes); } public function testFormatSuffix(): void @@ -46,24 +45,21 @@ public function testFormatSuffix(): void $routes = $routeLoader->__invoke(); - $expectedRoutes = []; - $expectedRoutes[] = (new Route('/a.{_format}')) - ->setDefault('_format', null) - ->setMethods('GET') - ->setDefault('_controller', FormatSuffixController::class.'::inheritEnabledFormatSuffix'); - $expectedRoutes[] = (new Route('/b.{_format}')) - ->setDefault('_format', null) - ->setRequirement('_format', 'json|xml') - ->setMethods('GET') - ->setDefault('_controller', FormatSuffixController::class.'::defineFormatPattern'); - $expectedRoutes[] = (new Route('/c')) - ->setMethods('GET') - ->setDefault('_controller', FormatSuffixController::class.'::disableFormatSuffix'); - - $index = 0; - foreach ($routes as $route) { - $this->assertEquals($route, $expectedRoutes[$index++]); - } + $expectedRoutes = new RouteCollection(); + $expectedRoutes->add( + self::FIXTURES_ROUTE_NAME_PREFIX.'formatsuffix_inheritenabledformatsuffix', + (new Route('/a.{_format}'))->setDefault('_format', null)->setMethods('GET')->setDefault('_controller', FormatSuffixController::class.'::inheritEnabledFormatSuffix') + ); + $expectedRoutes->add( + self::FIXTURES_ROUTE_NAME_PREFIX.'formatsuffix_defineformatpattern', + (new Route('/b.{_format}'))->setDefault('_format', null)->setRequirement('_format', 'json|xml')->setMethods('GET')->setDefault('_controller', FormatSuffixController::class.'::defineFormatPattern') + ); + $expectedRoutes->add( + self::FIXTURES_ROUTE_NAME_PREFIX.'formatsuffix_disableformatsuffix', + (new Route('/c'))->setMethods('GET')->setDefault('_controller', FormatSuffixController::class.'::disableFormatSuffix') + ); + + self::assertEquals($expectedRoutes, $routes); } public function testOperationId(): void @@ -87,22 +83,22 @@ public function testPathParameterPattern(): void $routes = $routeLoader->__invoke(); - $expectedRoutes = []; - $expectedRoutes[] = (new Route('/foo/{id}')) - ->setMethods('GET') - ->setDefault('_controller', PathParameterPatternController::class.'::noPattern'); - $expectedRoutes[] = (new Route('/baz/{id}')) - ->setMethods('GET') - ->setDefault('_controller', PathParameterPatternController::class.'::noSchema'); - $expectedRoutes[] = (new Route('/bar/{id}')) - ->setRequirement('id', '^[a-zA-Z0-9]+$') - ->setMethods('GET') - ->setDefault('_controller', PathParameterPatternController::class.'::withPattern'); - - $index = 0; - foreach ($routes as $route) { - $this->assertEquals($route, $expectedRoutes[$index++]); - } + $expectedRoutes = new RouteCollection(); + $expectedRoutes->add( + self::FIXTURES_ROUTE_NAME_PREFIX.'pathparameterpattern_nopattern', + (new Route('/foo/{id}'))->setMethods('GET')->setDefault('_controller', PathParameterPatternController::class.'::noPattern') + ); + $expectedRoutes->add( + self::FIXTURES_ROUTE_NAME_PREFIX.'pathparameterpattern_noschema', + (new Route('/baz/{id}'))->setMethods('GET')->setDefault('_controller', PathParameterPatternController::class.'::noSchema') + ); + // OpenAPI needs the param pattern to be anchored (^$) to have the desired effect. Symfony automatically trims those to get a valid full path regex. + $expectedRoutes->add( + self::FIXTURES_ROUTE_NAME_PREFIX.'pathparameterpattern_withpattern', + (new Route('/bar/{id}'))->setRequirement('id', '^[a-zA-Z0-9]+$')->setMethods('GET')->setDefault('_controller', PathParameterPatternController::class.'::withPattern') + ); + + self::assertEquals($expectedRoutes, $routes); } public function testPriority(): void @@ -111,21 +107,23 @@ public function testPriority(): void $routes = $routeLoader->__invoke(); - $expectedRoutes = []; - $expectedRoutes['/bar'] = (new Route('/bar')) - ->setMethods('GET') - ->setDefault('_controller', PriorityController::class.'::bar'); - $expectedRoutes['/foo'] = (new Route('/foo')) - ->setMethods('GET') - ->setDefault('_controller', PriorityController::class.'::foo'); - $expectedRoutes['/{catchall}'] = (new Route('/{catchall}')) - ->setMethods('GET') - ->setDefault('_controller', PriorityController::class.'::catchall'); - - foreach ($routes as $route) { - $this->assertArrayHasKey($route->getPath(), $expectedRoutes); - $this->assertEquals($route, $expectedRoutes[$route->getPath()]); - } + $expectedRoutes = new RouteCollection(); + $expectedRoutes->add( + self::FIXTURES_ROUTE_NAME_PREFIX.'priority_foo', + (new Route('/foo'))->setMethods('GET')->setDefault('_controller', PriorityController::class.'::foo') + ); + $expectedRoutes->add( + self::FIXTURES_ROUTE_NAME_PREFIX.'priority_catchall', + (new Route('/{catchall}'))->setMethods('GET')->setDefault('_controller', PriorityController::class.'::catchall'), + -100 + ); + $expectedRoutes->add( + self::FIXTURES_ROUTE_NAME_PREFIX.'priority_bar', + (new Route('/bar'))->setMethods('GET')->setDefault('_controller', PriorityController::class.'::bar'), + 10 + ); + + self::assertEquals($expectedRoutes, $routes); } public function testSeveralClasses(): void @@ -134,21 +132,21 @@ public function testSeveralClasses(): void $routes = $routeLoader->__invoke(); - $expectedRoutes = []; - $expectedRoutes[] = (new Route('/bar')) - ->setMethods('GET') - ->setDefault('_controller', BarController::class.'::__invoke'); - $expectedRoutes[] = (new Route('/foo')) - ->setMethods('GET') - ->setDefault('_controller', FooController::class.'::__invoke'); - $expectedRoutes[] = (new Route('/sub')) - ->setMethods('GET') - ->setDefault('_controller', SubController::class.'::__invoke'); - - $index = 0; - foreach ($routes as $route) { - $this->assertEquals($route, $expectedRoutes[$index++]); - } + $expectedRoutes = new RouteCollection(); + $expectedRoutes->add( + self::FIXTURES_ROUTE_NAME_PREFIX.'severalclasses_bar__invoke', + (new Route('/bar'))->setMethods('GET')->setDefault('_controller', BarController::class.'::__invoke') + ); + $expectedRoutes->add( + self::FIXTURES_ROUTE_NAME_PREFIX.'severalclasses_foo__invoke', + (new Route('/foo'))->setMethods('GET')->setDefault('_controller', FooController::class.'::__invoke') + ); + $expectedRoutes->add( + self::FIXTURES_ROUTE_NAME_PREFIX.'severalclasses_subnamespace_sub__invoke', + (new Route('/sub'))->setMethods('GET')->setDefault('_controller', SubController::class.'::__invoke') + ); + + self::assertEquals($expectedRoutes, $routes); } public function testSeveralHttpMethods(): void @@ -157,24 +155,25 @@ public function testSeveralHttpMethods(): void $routes = $routeLoader->__invoke(); - $expectedRoutes = []; - $expectedRoutes[] = (new Route('/foobar')) - ->setMethods('GET') - ->setDefault('_controller', SeveralHttpMethodsController::class.'::get'); - $expectedRoutes[] = (new Route('/foobar')) - ->setMethods('PUT') - ->setDefault('_controller', SeveralHttpMethodsController::class.'::put'); - $expectedRoutes[] = (new Route('/foobar')) - ->setMethods('POST') - ->setDefault('_controller', SeveralHttpMethodsController::class.'::post'); - $expectedRoutes[] = (new Route('/foobar')) - ->setMethods('DELETE') - ->setDefault('_controller', SeveralHttpMethodsController::class.'::delete'); - - $index = 0; - foreach ($routes as $route) { - $this->assertEquals($route, $expectedRoutes[$index++]); - } + $expectedRoutes = new RouteCollection(); + $expectedRoutes->add( + self::FIXTURES_ROUTE_NAME_PREFIX.'severalhttpmethods_get', + (new Route('/foobar'))->setMethods('GET')->setDefault('_controller', SeveralHttpMethodsController::class.'::get') + ); + $expectedRoutes->add( + self::FIXTURES_ROUTE_NAME_PREFIX.'severalhttpmethods_put', + (new Route('/foobar'))->setMethods('PUT')->setDefault('_controller', SeveralHttpMethodsController::class.'::put') + ); + $expectedRoutes->add( + self::FIXTURES_ROUTE_NAME_PREFIX.'severalhttpmethods_post', + (new Route('/foobar'))->setMethods('POST')->setDefault('_controller', SeveralHttpMethodsController::class.'::post') + ); + $expectedRoutes->add( + self::FIXTURES_ROUTE_NAME_PREFIX.'severalhttpmethods_delete', + (new Route('/foobar'))->setMethods('DELETE')->setDefault('_controller', SeveralHttpMethodsController::class.'::delete') + ); + + self::assertEquals($expectedRoutes, $routes); } public function testSeveralRoutesOnOneAction(): void @@ -183,44 +182,40 @@ public function testSeveralRoutesOnOneAction(): void $routes = $routeLoader->__invoke(); - $expectedRoutes = []; - $expectedRoutes[] = (new Route('/foobar')) - ->setMethods('GET') - ->setDefault('_controller', SeveralRoutesOnOneActionController::class.'::__invoke'); - $expectedRoutes[] = (new Route('/foobar')) - ->setMethods('POST') - ->setDefault('_controller', SeveralRoutesOnOneActionController::class.'::__invoke'); - $expectedRoutes[] = (new Route('/foo-bar')) - ->setMethods('GET') - ->setDefault('_controller', SeveralRoutesOnOneActionController::class.'::__invoke'); - - $index = 0; - foreach ($routes as $route) { - $this->assertEquals($route, $expectedRoutes[$index++]); - } + $expectedRoutes = new RouteCollection(); + $expectedRoutes->add( + self::FIXTURES_ROUTE_NAME_PREFIX.'severalroutesononeaction__invoke', + (new Route('/foobar'))->setMethods('GET')->setDefault('_controller', SeveralRoutesOnOneActionController::class.'::__invoke') + ); + $expectedRoutes->add( + self::FIXTURES_ROUTE_NAME_PREFIX.'severalroutesononeaction__invoke_1', + (new Route('/foobar'))->setMethods('POST')->setDefault('_controller', SeveralRoutesOnOneActionController::class.'::__invoke') + ); + $expectedRoutes->add( + 'my-name', + (new Route('/foo-bar'))->setMethods('GET')->setDefault('_controller', SeveralRoutesOnOneActionController::class.'::__invoke') + ); + + self::assertEquals($expectedRoutes, $routes); } public function testSeveralDirectories(): void { - $routeLoader = OpenApiRouteLoader::fromDirectories( - __DIR__.'/Fixtures/Basic', - __DIR__.'/Fixtures/SeveralClasses/SubNamespace' - ); + $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures/Basic', __DIR__.'/Fixtures/SeveralClasses/SubNamespace'); $routes = $routeLoader->__invoke(); - $expectedRoutes = []; - $expectedRoutes[] = (new Route('/foobar')) - ->setMethods('GET') - ->setDefault('_controller', BasicController::class.'::__invoke'); - $expectedRoutes[] = (new Route('/sub')) - ->setMethods('GET') - ->setDefault('_controller', SubController::class.'::__invoke'); - - $index = 0; - foreach ($routes as $route) { - $this->assertEquals($route, $expectedRoutes[$index++]); - } + $expectedRoutes = new RouteCollection(); + $expectedRoutes->add( + self::FIXTURES_ROUTE_NAME_PREFIX.'basic__invoke', + (new Route('/foobar'))->setMethods('GET')->setDefault('_controller', BasicController::class.'::__invoke') + ); + $expectedRoutes->add( + self::FIXTURES_ROUTE_NAME_PREFIX.'severalclasses_subnamespace_sub__invoke', + (new Route('/sub'))->setMethods('GET')->setDefault('_controller', SubController::class.'::__invoke') + ); + + self::assertEquals($expectedRoutes, $routes); } public function testSrcDirectoryDoesNotExist(): void diff --git a/tests/Attributes/Fixtures/Basic/Controller.php b/tests/Attributes/Fixtures/Basic/Controller.php index d59c712..c72d368 100644 --- a/tests/Attributes/Fixtures/Basic/Controller.php +++ b/tests/Attributes/Fixtures/Basic/Controller.php @@ -4,16 +4,13 @@ namespace Tobion\OpenApiSymfonyRouting\Tests\Attributes\Fixtures\Basic; -use OpenApi\Attributes as OAT; - -#[OAT\Info(version: "1.0", title: "My API")] -class OpenApiSpec -{} +use OpenApi\Attributes as OA; +#[OA\Info(version: "1.0", title: "My API")] class Controller { - #[OAT\Get(path: "/foobar")] - #[OAT\Response(response: 200, description: "OK")] + #[OA\Get(path: "/foobar")] + #[OA\Response(response: 200, description: "OK")] public function __invoke(): void { } diff --git a/tests/Attributes/Fixtures/FormatSuffix/Controller.php b/tests/Attributes/Fixtures/FormatSuffix/Controller.php index 9a10298..4cd547d 100644 --- a/tests/Attributes/Fixtures/FormatSuffix/Controller.php +++ b/tests/Attributes/Fixtures/FormatSuffix/Controller.php @@ -4,10 +4,10 @@ namespace Tobion\OpenApiSymfonyRouting\Tests\Attributes\Fixtures\FormatSuffix; -use OpenApi\Attributes as OAT; +use OpenApi\Attributes as OA; -#[OAT\OpenApi( - info: new OAT\Info( +#[OA\OpenApi( + info: new OA\Info( title: "My API", version: "1.0" ), @@ -19,20 +19,20 @@ )] class Controller { - #[OAT\Get(path: "/a",)] - #[OAT\Response(response: "200", description: "Success")] + #[OA\Get(path: "/a",)] + #[OA\Response(response: "200", description: "Success")] public function inheritEnabledFormatSuffix(): void { } - #[OAT\Get(path: "/b", x: ["format-suffix" => ["pattern" => "json|xml"]])] - #[OAT\Response(response: "200", description: "Success")] + #[OA\Get(path: "/b", x: ["format-suffix" => ["pattern" => "json|xml"]])] + #[OA\Response(response: "200", description: "Success")] public function defineFormatPattern(): void { } - #[OAT\Get(path: "/c", x: ["format-suffix" => false])] - #[OAT\Response(response: "200", description: "Success")] + #[OA\Get(path: "/c", x: ["format-suffix" => false])] + #[OA\Response(response: "200", description: "Success")] public function disableFormatSuffix(): void { } diff --git a/tests/Attributes/Fixtures/OperationId/Controller.php b/tests/Attributes/Fixtures/OperationId/Controller.php index 223b55a..8fc22ea 100644 --- a/tests/Attributes/Fixtures/OperationId/Controller.php +++ b/tests/Attributes/Fixtures/OperationId/Controller.php @@ -4,13 +4,13 @@ namespace Tobion\OpenApiSymfonyRouting\Tests\Attributes\Fixtures\OperationId; -use OpenApi\Attributes as OAT; +use OpenApi\Attributes as OA; -#[OAT\Info(title: "My API", version: "1.0")] +#[OA\Info(title: "My API", version: "1.0")] class Controller { - #[OAT\Get(path: "/foobar", operationId: "my-name")] - #[OAT\Response(response: "200", description: "Success")] + #[OA\Get(path: "/foobar", operationId: "my-name")] + #[OA\Response(response: "200", description: "Success")] public function __invoke(): void { } diff --git a/tests/Attributes/Fixtures/PathParameterPattern/Controller.php b/tests/Attributes/Fixtures/PathParameterPattern/Controller.php index f62855c..8d74212 100644 --- a/tests/Attributes/Fixtures/PathParameterPattern/Controller.php +++ b/tests/Attributes/Fixtures/PathParameterPattern/Controller.php @@ -4,34 +4,36 @@ namespace Tobion\OpenApiSymfonyRouting\Tests\Attributes\Fixtures\PathParameterPattern; -use OpenApi\Attributes as OAT; +use mysql_xdevapi\Schema; +use OpenApi\Attributes as OA; -#[OAT\Info(title: "My API", version: "1.0")] +#[OA\Info(title: "My API", version: "1.0")] class Controller { - #[OAT\Get(path: "/foo/{id}")] - #[OAT\Parameter(name:"id", in:"path", required:true, schema: new OAT\Schema(type:"string"))] - #[OAT\Response(response:"200", description:"Success")] - public function noPattern(): void + #[OA\Get(path: "/foo/{id}")] + #[OA\Response(response:"200", description:"Success")] + public function noPattern( + #[OA\Parameter]string $id + ): void { } - #[OAT\Get(path: "/baz/{id}")] - #[OAT\Parameter(name:"id", in:"path", required:true)] - #[OAT\Response(response:"200", description:"Success")] - public function noSchema(): void + #[OA\Get(path: "/baz/{id}")] + #[OA\Response(response:"200", description:"Success")] + public function noSchema( + #[OA\Parameter]string $id + ): void { } - #[OAT\Get(path: "/bar/{id}")] - #[OAT\Parameter( - name:"id", - in:"path", - required:true, - schema: new OAT\Schema(type:"string", pattern:"^[a-zA-Z0-9]+$") - )] - #[OAT\Response(response:"200", description:"Success")] - public function withPattern(): void + #[OA\Get(path: "/bar/{id}/{type}")] + #[OA\Response(response:"200", description:"Success")] + public function withPattern( + #[OA\PathParameter(required: true, schema: new OA\Schema(pattern:"^[a-zA-Z0-9]+$"))] + string $id, + #[OA\PathParameter(required: true, schema: new OA\Schema(enum: ["internal", "external"]))] + string $type + ): void { } } diff --git a/tests/Attributes/Fixtures/Priority/Controller.php b/tests/Attributes/Fixtures/Priority/Controller.php index 36f8f95..8e7d0b6 100644 --- a/tests/Attributes/Fixtures/Priority/Controller.php +++ b/tests/Attributes/Fixtures/Priority/Controller.php @@ -4,25 +4,25 @@ namespace Tobion\OpenApiSymfonyRouting\Tests\Attributes\Fixtures\Priority; -use OpenApi\Attributes as OAT; +use OpenApi\Attributes as OA; -#[OAT\Info(title:"My API", version:"1.0")] +#[OA\Info(title:"My API", version:"1.0")] class Controller { - #[OAT\Get(path:"/foo")] - #[OAT\Response(response:"200", description:"Success")] + #[OA\Get(path:"/foo")] + #[OA\Response(response:"200", description:"Success")] public function foo(): void { } - #[OAT\Get(path:"/{catchall}", x: ["priority" => -100])] - #[OAT\Response(response:"200", description:"Success")] + #[OA\Get(path:"/{catchall}", x: ["priority" => -100])] + #[OA\Response(response:"200", description:"Success")] public function catchall(): void { } - #[OAT\Get(path:"/bar", x: ["priority" => 10])] - #[OAT\Response(response:"200", description:"Success")] + #[OA\Get(path:"/bar", x: ["priority" => 10])] + #[OA\Response(response:"200", description:"Success")] public function bar(): void { } diff --git a/tests/Attributes/Fixtures/SeveralClasses/BarController.php b/tests/Attributes/Fixtures/SeveralClasses/BarController.php index 81a6c98..b4f81bd 100644 --- a/tests/Attributes/Fixtures/SeveralClasses/BarController.php +++ b/tests/Attributes/Fixtures/SeveralClasses/BarController.php @@ -4,13 +4,13 @@ namespace Tobion\OpenApiSymfonyRouting\Tests\Attributes\Fixtures\SeveralClasses; -use OpenApi\Attributes as OAT; +use OpenApi\Attributes as OA; -#[OAT\Info(title:"My API", version:"1.0")] +#[OA\Info(title:"My API", version:"1.0")] class BarController { - #[OAT\Get(path:"/bar")] - #[OAT\Response(response:"200", description:"Success")] + #[OA\Get(path:"/bar")] + #[OA\Response(response:"200", description:"Success")] public function __invoke(): void { } diff --git a/tests/Attributes/Fixtures/SeveralClasses/FooController.php b/tests/Attributes/Fixtures/SeveralClasses/FooController.php index 49ab08f..071433a 100644 --- a/tests/Attributes/Fixtures/SeveralClasses/FooController.php +++ b/tests/Attributes/Fixtures/SeveralClasses/FooController.php @@ -4,12 +4,12 @@ namespace Tobion\OpenApiSymfonyRouting\Tests\Attributes\Fixtures\SeveralClasses; -use OpenApi\Attributes as OAT; +use OpenApi\Attributes as OA; class FooController { - #[OAT\Get(path:"/foo")] - #[OAT\Response(response:"200", description:"Success")] + #[OA\Get(path:"/foo")] + #[OA\Response(response:"200", description:"Success")] public function __invoke(): void { } diff --git a/tests/Attributes/Fixtures/SeveralClasses/SubNamespace/SubController.php b/tests/Attributes/Fixtures/SeveralClasses/SubNamespace/SubController.php index b03a4c8..2f59c32 100644 --- a/tests/Attributes/Fixtures/SeveralClasses/SubNamespace/SubController.php +++ b/tests/Attributes/Fixtures/SeveralClasses/SubNamespace/SubController.php @@ -4,12 +4,12 @@ namespace Tobion\OpenApiSymfonyRouting\Tests\Attributes\Fixtures\SeveralClasses\SubNamespace; -use OpenApi\Attributes as OAT; +use OpenApi\Attributes as OA; class SubController { - #[OAT\Get(path:"/sub")] - #[OAT\Response(response:"200", description:"Success")] + #[OA\Get(path:"/sub")] + #[OA\Response(response:"200", description:"Success")] public function __invoke(): void { } diff --git a/tests/Attributes/Fixtures/SeveralHttpMethods/Controller.php b/tests/Attributes/Fixtures/SeveralHttpMethods/Controller.php index 8ba355d..4db068d 100644 --- a/tests/Attributes/Fixtures/SeveralHttpMethods/Controller.php +++ b/tests/Attributes/Fixtures/SeveralHttpMethods/Controller.php @@ -4,31 +4,31 @@ namespace Tobion\OpenApiSymfonyRouting\Tests\Attributes\Fixtures\SeveralHttpMethods; -use OpenApi\Attributes as OAT; +use OpenApi\Attributes as OA; -#[OAT\Info(title:"My API", version:"1.0")] +#[OA\Info(title:"My API", version:"1.0")] class Controller { - #[OAT\Get(path:"/foobar")] - #[OAT\Response(response:"200", description:"Success")] + #[OA\Get(path:"/foobar")] + #[OA\Response(response:"200", description:"Success")] public function get(): void { } - #[OAT\Put(path:"/foobar")] - #[OAT\Response(response:"200", description:"Success")] + #[OA\Put(path:"/foobar")] + #[OA\Response(response:"200", description:"Success")] public function put(): void { } - #[OAT\Post(path:"/foobar")] - #[OAT\Response(response:"200", description:"Success")] + #[OA\Post(path:"/foobar")] + #[OA\Response(response:"200", description:"Success")] public function post(): void { } - #[OAT\Delete(path:"/foobar")] - #[OAT\Response(response:"200", description:"Success")] + #[OA\Delete(path:"/foobar")] + #[OA\Response(response:"200", description:"Success")] public function delete(): void { } diff --git a/tests/Attributes/Fixtures/SeveralRoutesOnOneAction/Controller.php b/tests/Attributes/Fixtures/SeveralRoutesOnOneAction/Controller.php index 776c983..e098dae 100644 --- a/tests/Attributes/Fixtures/SeveralRoutesOnOneAction/Controller.php +++ b/tests/Attributes/Fixtures/SeveralRoutesOnOneAction/Controller.php @@ -4,14 +4,14 @@ namespace Tobion\OpenApiSymfonyRouting\Tests\Attributes\Fixtures\SeveralRoutesOnOneAction; -use OpenApi\Attributes as OAT; +use OpenApi\Attributes as OA; -#[OAT\Info(title:"My API", version:"1.0")] +#[OA\Info(title:"My API", version:"1.0")] class Controller { - #[OAT\Get(path:"/foobar", responses: [new OAT\Response(response:"200", description:"Success")])] - #[OAT\Post(path:"/foobar", responses: [new OAT\Response(response:"200", description:"Success")])] - #[OAT\Get(path:"/foo-bar", operationId: "my-name", responses: [new OAT\Response(response:"200", description:"Success")])] + #[OA\Get(path:"/foobar", responses: [new OA\Response(response:"200", description:"Success")])] + #[OA\Post(path:"/foobar", responses: [new OA\Response(response:"200", description:"Success")])] + #[OA\Get(path:"/foo-bar", operationId: "my-name", responses: [new OA\Response(response:"200", description:"Success")])] public function __invoke(): void { } diff --git a/tests/Attributes/OpenApiRouteLoaderAttributesTest.php b/tests/Attributes/OpenApiRouteLoaderAttributesTest.php index 9e55d1e..d79ab2e 100644 --- a/tests/Attributes/OpenApiRouteLoaderAttributesTest.php +++ b/tests/Attributes/OpenApiRouteLoaderAttributesTest.php @@ -20,22 +20,26 @@ use Tobion\OpenApiSymfonyRouting\Tests\Attributes\Fixtures\SeveralHttpMethods\Controller as SeveralHttpMethodsController; use Tobion\OpenApiSymfonyRouting\Tests\Attributes\Fixtures\SeveralRoutesOnOneAction\Controller as SeveralRoutesOnOneActionController; -class OpenApiRouteLoaderAttributesTest extends TestCase +/** + * @requires PHP >= 8.1 + */ +final class OpenApiRouteLoaderAttributesTest extends TestCase { + private const FIXTURES_ROUTE_NAME_PREFIX = 'tobion_openapisymfonyrouting_tests_attributes_fixtures_'; + public function testBasic(): void { $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures/Basic'); $routes = $routeLoader->__invoke(); - foreach ($routes as $route) { - $this->assertEquals( - $route, - (new Route('/foobar')) - ->setMethods('GET') - ->setDefault('_controller', BasicController::class.'::__invoke') - ); - } + $expectedRoutes = new RouteCollection(); + $expectedRoutes->add( + self::FIXTURES_ROUTE_NAME_PREFIX.'basic__invoke', + (new Route('/foobar'))->setMethods('GET')->setDefault('_controller', BasicController::class.'::__invoke') + ); + + self::assertEquals($expectedRoutes, $routes); } public function testFormatSuffix(): void @@ -44,24 +48,21 @@ public function testFormatSuffix(): void $routes = $routeLoader->__invoke(); - $expectedRoutes = []; - $expectedRoutes[] = (new Route('/a.{_format}')) - ->setDefault('_format', null) - ->setMethods('GET') - ->setDefault('_controller', FormatSuffixController::class.'::inheritEnabledFormatSuffix'); - $expectedRoutes[] = (new Route('/b.{_format}')) - ->setDefault('_format', null) - ->setRequirement('_format', 'json|xml') - ->setMethods('GET') - ->setDefault('_controller', FormatSuffixController::class.'::defineFormatPattern'); - $expectedRoutes[] = (new Route('/c')) - ->setMethods('GET') - ->setDefault('_controller', FormatSuffixController::class.'::disableFormatSuffix'); - - $index = 0; - foreach ($routes as $route) { - $this->assertEquals($route, $expectedRoutes[$index++]); - } + $expectedRoutes = new RouteCollection(); + $expectedRoutes->add( + self::FIXTURES_ROUTE_NAME_PREFIX.'formatsuffix_inheritenabledformatsuffix', + (new Route('/a.{_format}'))->setDefault('_format', null)->setMethods('GET')->setDefault('_controller', FormatSuffixController::class.'::inheritEnabledFormatSuffix') + ); + $expectedRoutes->add( + self::FIXTURES_ROUTE_NAME_PREFIX.'formatsuffix_defineformatpattern', + (new Route('/b.{_format}'))->setDefault('_format', null)->setRequirement('_format', 'json|xml')->setMethods('GET')->setDefault('_controller', FormatSuffixController::class.'::defineFormatPattern') + ); + $expectedRoutes->add( + self::FIXTURES_ROUTE_NAME_PREFIX.'formatsuffix_disableformatsuffix', + (new Route('/c'))->setMethods('GET')->setDefault('_controller', FormatSuffixController::class.'::disableFormatSuffix') + ); + + self::assertEquals($expectedRoutes, $routes); } public function testOperationId(): void @@ -85,22 +86,26 @@ public function testPathParameterPattern(): void $routes = $routeLoader->__invoke(); - $expectedRoutes = []; - $expectedRoutes[] = (new Route('/foo/{id}')) - ->setMethods('GET') - ->setDefault('_controller', PathParameterPatternController::class.'::noPattern'); - $expectedRoutes[] = (new Route('/baz/{id}')) - ->setMethods('GET') - ->setDefault('_controller', PathParameterPatternController::class.'::noSchema'); - $expectedRoutes[] = (new Route('/bar/{id}')) - ->setRequirement('id', '^[a-zA-Z0-9]+$') - ->setMethods('GET') - ->setDefault('_controller', PathParameterPatternController::class.'::withPattern'); - - $index = 0; - foreach ($routes as $route) { - $this->assertEquals($route, $expectedRoutes[$index++]); - } + $expectedRoutes = new RouteCollection(); + $expectedRoutes->add( + self::FIXTURES_ROUTE_NAME_PREFIX.'pathparameterpattern_nopattern', + (new Route('/foo/{id}'))->setMethods('GET')->setDefault('_controller', PathParameterPatternController::class.'::noPattern') + ); + $expectedRoutes->add( + self::FIXTURES_ROUTE_NAME_PREFIX.'pathparameterpattern_noschema', + (new Route('/baz/{id}'))->setMethods('GET')->setDefault('_controller', PathParameterPatternController::class.'::noSchema') + ); + + // OpenAPI needs the param pattern to be anchored (^$) to have the desired effect. Symfony automatically trims those to get a valid full path regex. + $expectedRoutes->add( + self::FIXTURES_ROUTE_NAME_PREFIX.'pathparameterpattern_withpattern', + (new Route('/bar/{id}/{type}')) + ->setRequirement('id', '^[a-zA-Z0-9]+$') + ->setRequirement('type', 'internal|external') + ->setMethods('GET')->setDefault('_controller', PathParameterPatternController::class.'::withPattern') + ); + + self::assertEquals($expectedRoutes, $routes); } public function testPriority(): void @@ -109,21 +114,23 @@ public function testPriority(): void $routes = $routeLoader->__invoke(); - $expectedRoutes = []; - $expectedRoutes[] = (new Route('/bar')) - ->setMethods('GET') - ->setDefault('_controller', PriorityController::class.'::bar'); - $expectedRoutes[] = (new Route('/foo')) - ->setMethods('GET') - ->setDefault('_controller', PriorityController::class.'::foo'); - $expectedRoutes[] = (new Route('/{catchall}')) - ->setMethods('GET') - ->setDefault('_controller', PriorityController::class.'::catchall'); - - $index = 0; - foreach ($routes as $route) { - $this->assertEquals($route, $expectedRoutes[$index++]); - } + $expectedRoutes = new RouteCollection(); + $expectedRoutes->add( + self::FIXTURES_ROUTE_NAME_PREFIX.'priority_foo', + (new Route('/foo'))->setMethods('GET')->setDefault('_controller', PriorityController::class.'::foo') + ); + $expectedRoutes->add( + self::FIXTURES_ROUTE_NAME_PREFIX.'priority_catchall', + (new Route('/{catchall}'))->setMethods('GET')->setDefault('_controller', PriorityController::class.'::catchall'), + -100 + ); + $expectedRoutes->add( + self::FIXTURES_ROUTE_NAME_PREFIX.'priority_bar', + (new Route('/bar'))->setMethods('GET')->setDefault('_controller', PriorityController::class.'::bar'), + 10 + ); + + self::assertEquals($expectedRoutes, $routes); } public function testSeveralClasses(): void @@ -132,21 +139,21 @@ public function testSeveralClasses(): void $routes = $routeLoader->__invoke(); - $expectedRoutes = []; - $expectedRoutes[] = (new Route('/bar')) - ->setMethods('GET') - ->setDefault('_controller', BarController::class.'::__invoke'); - $expectedRoutes[] = (new Route('/foo')) - ->setMethods('GET') - ->setDefault('_controller', FooController::class.'::__invoke'); - $expectedRoutes[] = (new Route('/sub')) - ->setMethods('GET') - ->setDefault('_controller', SubController::class.'::__invoke'); - - $index = 0; - foreach ($routes as $route) { - $this->assertEquals($route, $expectedRoutes[$index++]); - } + $expectedRoutes = new RouteCollection(); + $expectedRoutes->add( + self::FIXTURES_ROUTE_NAME_PREFIX.'severalclasses_bar__invoke', + (new Route('/bar'))->setMethods('GET')->setDefault('_controller', BarController::class.'::__invoke') + ); + $expectedRoutes->add( + self::FIXTURES_ROUTE_NAME_PREFIX.'severalclasses_foo__invoke', + (new Route('/foo'))->setMethods('GET')->setDefault('_controller', FooController::class.'::__invoke') + ); + $expectedRoutes->add( + self::FIXTURES_ROUTE_NAME_PREFIX.'severalclasses_subnamespace_sub__invoke', + (new Route('/sub'))->setMethods('GET')->setDefault('_controller', SubController::class.'::__invoke') + ); + + self::assertEquals($expectedRoutes, $routes); } public function testSeveralHttpMethods(): void @@ -155,24 +162,25 @@ public function testSeveralHttpMethods(): void $routes = $routeLoader->__invoke(); - $expectedRoutes = []; - $expectedRoutes[] = (new Route('/foobar')) - ->setMethods('GET') - ->setDefault('_controller', SeveralHttpMethodsController::class.'::get'); - $expectedRoutes[] = (new Route('/foobar')) - ->setMethods('PUT') - ->setDefault('_controller', SeveralHttpMethodsController::class.'::put'); - $expectedRoutes[] = (new Route('/foobar')) - ->setMethods('POST') - ->setDefault('_controller', SeveralHttpMethodsController::class.'::post'); - $expectedRoutes[] = (new Route('/foobar')) - ->setMethods('DELETE') - ->setDefault('_controller', SeveralHttpMethodsController::class.'::delete'); - - $index = 0; - foreach ($routes as $route) { - $this->assertEquals($route, $expectedRoutes[$index++]); - } + $expectedRoutes = new RouteCollection(); + $expectedRoutes->add( + self::FIXTURES_ROUTE_NAME_PREFIX.'severalhttpmethods_get', + (new Route('/foobar'))->setMethods('GET')->setDefault('_controller', SeveralHttpMethodsController::class.'::get') + ); + $expectedRoutes->add( + self::FIXTURES_ROUTE_NAME_PREFIX.'severalhttpmethods_put', + (new Route('/foobar'))->setMethods('PUT')->setDefault('_controller', SeveralHttpMethodsController::class.'::put') + ); + $expectedRoutes->add( + self::FIXTURES_ROUTE_NAME_PREFIX.'severalhttpmethods_post', + (new Route('/foobar'))->setMethods('POST')->setDefault('_controller', SeveralHttpMethodsController::class.'::post') + ); + $expectedRoutes->add( + self::FIXTURES_ROUTE_NAME_PREFIX.'severalhttpmethods_delete', + (new Route('/foobar'))->setMethods('DELETE')->setDefault('_controller', SeveralHttpMethodsController::class.'::delete') + ); + + self::assertEquals($expectedRoutes, $routes); } public function testSeveralRoutesOnOneAction(): void @@ -181,44 +189,40 @@ public function testSeveralRoutesOnOneAction(): void $routes = $routeLoader->__invoke(); - $expectedRoutes = []; - $expectedRoutes[] = (new Route('/foobar')) - ->setMethods('GET') - ->setDefault('_controller', SeveralRoutesOnOneActionController::class.'::__invoke'); - $expectedRoutes[] = (new Route('/foobar')) - ->setMethods('POST') - ->setDefault('_controller', SeveralRoutesOnOneActionController::class.'::__invoke'); - $expectedRoutes[] = (new Route('/foo-bar')) - ->setMethods('GET') - ->setDefault('_controller', SeveralRoutesOnOneActionController::class.'::__invoke'); - - $index = 0; - foreach ($routes as $route) { - $this->assertEquals($route, $expectedRoutes[$index++]); - } + $expectedRoutes = new RouteCollection(); + $expectedRoutes->add( + self::FIXTURES_ROUTE_NAME_PREFIX.'severalroutesononeaction__invoke', + (new Route('/foobar'))->setMethods('GET')->setDefault('_controller', SeveralRoutesOnOneActionController::class.'::__invoke') + ); + $expectedRoutes->add( + self::FIXTURES_ROUTE_NAME_PREFIX.'severalroutesononeaction__invoke_1', + (new Route('/foobar'))->setMethods('POST')->setDefault('_controller', SeveralRoutesOnOneActionController::class.'::__invoke') + ); + $expectedRoutes->add( + 'my-name', + (new Route('/foo-bar'))->setMethods('GET')->setDefault('_controller', SeveralRoutesOnOneActionController::class.'::__invoke') + ); + + self::assertEquals($expectedRoutes, $routes); } public function testSeveralDirectories(): void { - $routeLoader = OpenApiRouteLoader::fromDirectories( - __DIR__.'/Fixtures/Basic', - __DIR__.'/Fixtures/SeveralClasses/SubNamespace' - ); + $routeLoader = OpenApiRouteLoader::fromDirectories(__DIR__.'/Fixtures/Basic', __DIR__.'/Fixtures/SeveralClasses/SubNamespace'); $routes = $routeLoader->__invoke(); - $expectedRoutes = []; - $expectedRoutes[] = (new Route('/foobar')) - ->setMethods('GET') - ->setDefault('_controller', BasicController::class.'::__invoke'); - $expectedRoutes[] = (new Route('/sub')) - ->setMethods('GET') - ->setDefault('_controller', SubController::class.'::__invoke'); - - $index = 0; - foreach ($routes as $route) { - $this->assertEquals($route, $expectedRoutes[$index++]); - } + $expectedRoutes = new RouteCollection(); + $expectedRoutes->add( + self::FIXTURES_ROUTE_NAME_PREFIX.'basic__invoke', + (new Route('/foobar'))->setMethods('GET')->setDefault('_controller', BasicController::class.'::__invoke') + ); + $expectedRoutes->add( + self::FIXTURES_ROUTE_NAME_PREFIX.'severalclasses_subnamespace_sub__invoke', + (new Route('/sub'))->setMethods('GET')->setDefault('_controller', SubController::class.'::__invoke') + ); + + self::assertEquals($expectedRoutes, $routes); } public function testSrcDirectoryDoesNotExist(): void