From d8535c145f83d57cb48f5375365a81fc71e73313 Mon Sep 17 00:00:00 2001 From: Patrik Foldes Date: Thu, 19 Feb 2026 13:17:42 +0300 Subject: [PATCH 1/4] support for symfony 8 --- .github/workflows/ci.yml | 18 +-- README.md | 16 +-- composer.json | 58 ++++----- infection.json | 1 - psalm.xml | 5 - .../PhpParserGenerators/CodeGenerator.php | 6 +- .../PhpParserGenerators/DtoCodeGenerator.php | 2 +- .../ServiceSubscriberCodeGenerator.php | 2 +- src/Command/DeleteGeneratedCodeCommand.php | 7 -- src/Command/GenerateApiCodeCommand.php | 7 -- src/DependencyInjection/Configuration.php | 5 +- .../OpenApiServerExtension.php | 6 +- src/Resources/config/services.php | 110 ++++++++++++++++++ src/Types/ScalarTypesResolver.php | 28 +++-- .../DependencyInjection/ConfigurationTest.php | 9 +- 15 files changed, 188 insertions(+), 92 deletions(-) create mode 100644 src/Resources/config/services.php diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 90ad77a..565f4c1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,10 +17,10 @@ jobs: - "ubuntu-latest" - "windows-latest" php-version: - - "8.1" - "8.2" - "8.3" - "8.4" + - "8.5" dependencies: - "lowest" - "highest" @@ -55,7 +55,7 @@ jobs: operating-system: - "ubuntu-latest" php-version: - - "8.4" + - "8.5" steps: - name: "Checkout" uses: "actions/checkout@v2" @@ -83,7 +83,7 @@ jobs: operating-system: - "ubuntu-latest" php-version: - - "8.4" + - "8.5" steps: - name: "Checkout" uses: "actions/checkout@v2" @@ -111,7 +111,7 @@ jobs: operating-system: - "ubuntu-latest" php-version: - - "8.4" + - "8.5" steps: - name: "Checkout" uses: "actions/checkout@v2" @@ -130,7 +130,7 @@ jobs: - name: "Install highest dependencies" run: "composer update --no-interaction --no-progress" - name: "Execute PhpCs" - run: "vendor/bin/phpcs --config-set php_version 7040 && vendor/bin/phpcs -q --report=checkstyle | cs2pr" + run: "vendor/bin/phpcs --config-set php_version 8020 && vendor/bin/phpcs -q --report=checkstyle | cs2pr" coverage: name: "Code coverage" runs-on: "ubuntu-latest" @@ -139,7 +139,7 @@ jobs: operating-system: - "ubuntu-latest" php-version: - - "8.4" + - "8.5" steps: - name: "Checkout" uses: "actions/checkout@v2" @@ -172,7 +172,7 @@ jobs: operating-system: - "ubuntu-latest" php-version: - - "8.4" + - "8.5" steps: - name: "Checkout" uses: "actions/checkout@v2" @@ -191,7 +191,7 @@ jobs: - name: "Install highest dependencies" run: "composer update --no-interaction --no-progress" - name: "Infection" - run: "vendor/bin/roave-infection-static-analysis-plugin --only-covered --test-framework-options=\"--testsuite=unit\"" + run: "vendor/bin/roave-infection-static-analysis-plugin --test-framework-options=\"--testsuite=unit\"" env: INFECTION_BADGE_API_KEY: ${{ secrets.INFECTION_BADGE_API_KEY }} STRYKER_DASHBOARD_API_KEY: ${{ secrets.STRYKER_DASHBOARD_API_KEY }} @@ -203,7 +203,7 @@ jobs: operating-system: - "ubuntu-latest" php-version: - - "8.4" + - "8.5" steps: - name: "Checkout" uses: "actions/checkout@v2" diff --git a/README.md b/README.md index e7bc21f..cc08497 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ open_api_server: specs: petstore: path: '../spec/petstore.yaml' # path to OpenApi specification - type: yaml # Specification format, either yaml or json. If omitted, the specification file extension will be used. + type: yaml # Specification format, either YAML or JSON. If omitted, the specification file extension will be used. name_space: PetStore # Namespace for generated DTOs and Interfaces media_type: 'application/json' # media type from the specification files to use for generating request and response DTOs #date_time_class: '\Carbon\CarbonImmutable' # FQCN which implements \DateTimeInterface. @@ -82,7 +82,7 @@ petstore-api: ## Requirements for your OpenAPI schemas For the bundle to work properly with your specifications, they should be written in OpenAPI 3.0 format and each -operation must have an unique `operationId`. +operation must have a unique `operationId`. Currently, there are also the following limitations: - `number` without `format` is treated as float @@ -105,7 +105,7 @@ Be careful with the generate and delete commands, they will delete the entire co in `root_path` in the `/config/packages/open_api_server.yaml` file. That directory should contain no files except the code generated by this bundle, as it will be deleted every time you generate the API server code. -For each operation described in the specification, a API call handler interface will be generated that you should implement +For each operation described in the specification, an API call handler interface will be generated that you should implement to handle the API calls. ## Implementing the API call handlers interfaces @@ -195,9 +195,9 @@ public function showPetById(ShowPetByIdRequestDto $request) : ShowPetByIdRespons ## Customizing the API server behavior -During the request handling lyfecycle the API server emits several events that can be used instead -of the built-in Symfony Kernel events as the former provide more context. Theese events allow -hooking into the API server functionality and modify it's behavior. +During the request handling lifecycle the API server emits several events that can be used instead +of the built-in Symfony Kernel events as the former provide more context. These events allow +hooking into the API server functionality and modify its behavior. The following events are available: @@ -218,8 +218,8 @@ The following events are available: The ResponseDtoEvent event occurs after the request handler class was executed returning a ResponseDto and before this ResponseDto is serialized to a Response. This event allows you to modify the ResponseDto contents before it will be serialized. This can be used as an - alternative to modyfing the Response object in a Symfony ResponseEvent, avoiding unnecessary decoding/encoding - of the Response body json. + alternative to modifying the Response object in a Symfony ResponseEvent, avoiding unnecessary decoding/encoding + of the Response body JSON. Note that the ResponseDTO is not created if the API endpoint has no response body. - `OnMoon\OpenApiServerBundle\Event\Server\ResponseEvent` diff --git a/composer.json b/composer.json index cb3dca3..eeea07b 100644 --- a/composer.json +++ b/composer.json @@ -22,42 +22,42 @@ } ], "require": { - "php": "^8.1", + "php": "^8.2", "ext-json": "*", - "devizzent/cebe-php-openapi": "^1.1.4", - "league/openapi-psr7-validator": "^0.22.0", + "devizzent/cebe-php-openapi": "^1.1.5", + "league/openapi-psr7-validator": "^0.22", "lukasoppermann/http-status": "^4.0", "nikic/php-parser": "^4.19|^v5.0", - "nyholm/psr7": "^1.5", - "phpdocumentor/reflection-docblock": "^5.3", - "sspat/reserved-words": "^3.0", - "symfony/cache": "^6.4|^7.0", - "symfony/cache-contracts": "^3.5", - "symfony/config": "^6.4|^7.0", - "symfony/console": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/event-dispatcher": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/psr-http-message-bridge": "^6.4|^7.0", - "symfony/routing": "^6.4|^7.0", - "symfony/yaml": "^6.4|^7.0", + "nyholm/psr7": "^1.8", + "phpdocumentor/reflection-docblock": "^6.0", + "sspat/reserved-words": "^3.0.2", + "symfony/cache": "^6.4|^7.4|^8.0", + "symfony/cache-contracts": "^3.6", + "symfony/config": "^6.4|^7.4|^8.0", + "symfony/console": "^6.4|^7.4|^8.0", + "symfony/dependency-injection": "^6.4|^7.4|^8.0", + "symfony/event-dispatcher": "^6.4|^7.4|^8.0", + "symfony/http-kernel": "^6.4|^7.4|^8.0", + "symfony/psr-http-message-bridge": "^6.4|^7.4|^8.0", + "symfony/routing": "^6.4|^7.4|^8.0", + "symfony/yaml": "^6.4|^7.4|^8.0", "thecodingmachine/safe": "^1.3|^2|^3.1" }, "require-dev": { - "doctrine/coding-standard": "^12.0", - "matthiasnoback/symfony-config-test": "^5.1", - "matthiasnoback/symfony-dependency-injection-test": "^5.1", + "doctrine/coding-standard": "^14.0", + "matthiasnoback/symfony-config-test": "^6.1", + "matthiasnoback/symfony-dependency-injection-test": "^6.2", "phpstan/phpstan": "^1.11|^2.1", "phpstan/phpstan-phpunit": "^1.4|^2.0", "phpstan/phpstan-strict-rules": "^1.6|^2.0", "phpunit/phpunit": "^10.5", - "roave/infection-static-analysis-plugin": "^1.35", - "squizlabs/php_codesniffer": "^3.10", - "symfony/browser-kit": "^6.4|^7.0", - "symfony/dom-crawler": "^6.4|^7.0", - "symfony/framework-bundle": "^6.4|^7.0", - "thecodingmachine/phpstan-safe-rule": "^1.2|v1.4", - "vimeo/psalm": "^5.24|^6.10" + "roave/infection-static-analysis-plugin": "^1.40", + "squizlabs/php_codesniffer": "^4.0", + "symfony/browser-kit": "^6.4|^7.4|^8.0", + "symfony/dom-crawler": "^6.4|^7.4|^8.0", + "symfony/framework-bundle": "^6.4|^7.4|^8.0", + "thecodingmachine/phpstan-safe-rule": "^1.4", + "vimeo/psalm": "^5.24|^6.15" }, "minimum-stability": "stable", "prefer-stable": true, @@ -85,12 +85,12 @@ } }, "scripts": { - "cs": "phpcs --config-set php_version 8000 && phpcs", - "csfix": "phpcs --config-set php_version 8000 && phpcbf", + "cs": "phpcs --config-set php_version 8020 && phpcs", + "csfix": "phpcs --config-set php_version 8020 && phpcbf", "psalm": "psalm", "stan": "phpstan analyse --memory-limit=-1 --xdebug", "tests": "phpunit --fail-on-warning", - "mutation": "php -d memory_limit=-1 vendor/bin/roave-infection-static-analysis-plugin --only-covered --test-framework-options=\"--testsuite=unit\"", + "mutation": "php -d memory_limit=-1 vendor/bin/roave-infection-static-analysis-plugin --test-framework-options=\"--testsuite=unit\"", "all": "composer psalm && composer stan && composer tests && composer mutation && composer cs && composer security", "get-security": "rm -f local-php-security-checker && curl -s https://api.github.com/repos/fabpot/local-php-security-checker/releases/latest | grep -E \"browser_download_url(.+)linux_amd64\" | cut -d : -f 2,3 | tr -d \\\" | xargs -I % curl % -L -o local-php-security-checker && chmod +x local-php-security-checker", "security": "./local-php-security-checker" diff --git a/infection.json b/infection.json index 54928ec..e0fba3f 100644 --- a/infection.json +++ b/infection.json @@ -10,7 +10,6 @@ }, "mutators": { "@default": true, - "IdenticalEqual": false, "NotIdenticalNotEqual": false, "MethodCallRemoval": { "ignore": [ diff --git a/psalm.xml b/psalm.xml index e9a4f81..911ef13 100644 --- a/psalm.xml +++ b/psalm.xml @@ -15,11 +15,6 @@ - - - - - diff --git a/src/CodeGenerator/PhpParserGenerators/CodeGenerator.php b/src/CodeGenerator/PhpParserGenerators/CodeGenerator.php index 87e7976..f33f3f3 100644 --- a/src/CodeGenerator/PhpParserGenerators/CodeGenerator.php +++ b/src/CodeGenerator/PhpParserGenerators/CodeGenerator.php @@ -8,9 +8,9 @@ use OnMoon\OpenApiServerBundle\CodeGenerator\Definitions\PropertyDefinition; use OnMoon\OpenApiServerBundle\Types\ScalarTypesResolver; use PhpParser\BuilderFactory; -use PhpParser\Node\Scalar\LNumber; +use PhpParser\Node\DeclareItem; +use PhpParser\Node\Scalar\Int_; use PhpParser\Node\Stmt\Declare_; -use PhpParser\Node\Stmt\DeclareDeclare; use PhpParser\PrettyPrinter\Standard; use function array_map; @@ -93,7 +93,7 @@ public function getDocComment(array $lines): string public function printFile(FileBuilder $fileBuilder): string { return (new Standard())->prettyPrintFile([ - new Declare_([new DeclareDeclare('strict_types', new LNumber(1))]), + new Declare_([new DeclareItem('strict_types', new Int_(1))]), $fileBuilder->getNamespace()->getNode(), ]); } diff --git a/src/CodeGenerator/PhpParserGenerators/DtoCodeGenerator.php b/src/CodeGenerator/PhpParserGenerators/DtoCodeGenerator.php index 6903afb..157d305 100644 --- a/src/CodeGenerator/PhpParserGenerators/DtoCodeGenerator.php +++ b/src/CodeGenerator/PhpParserGenerators/DtoCodeGenerator.php @@ -13,10 +13,10 @@ use PhpParser\Builder\Param; use PhpParser\Builder\Property; use PhpParser\Node\Arg; +use PhpParser\Node\ArrayItem; use PhpParser\Node\Expr; use PhpParser\Node\Expr\Array_; use PhpParser\Node\Expr\ArrayDimFetch; -use PhpParser\Node\Expr\ArrayItem; use PhpParser\Node\Expr\ArrowFunction; use PhpParser\Node\Expr\Assign; use PhpParser\Node\Expr\BinaryOp\Identical; diff --git a/src/CodeGenerator/PhpParserGenerators/ServiceSubscriberCodeGenerator.php b/src/CodeGenerator/PhpParserGenerators/ServiceSubscriberCodeGenerator.php index 4119ef5..ee2cb34 100644 --- a/src/CodeGenerator/PhpParserGenerators/ServiceSubscriberCodeGenerator.php +++ b/src/CodeGenerator/PhpParserGenerators/ServiceSubscriberCodeGenerator.php @@ -9,9 +9,9 @@ use OnMoon\OpenApiServerBundle\CodeGenerator\Definitions\GraphDefinition; use OnMoon\OpenApiServerBundle\Interfaces\RequestHandler; use PhpParser\Node\Arg; +use PhpParser\Node\ArrayItem; use PhpParser\Node\Expr\Array_; use PhpParser\Node\Expr\ArrayDimFetch; -use PhpParser\Node\Expr\ArrayItem; use PhpParser\Node\Expr\Assign; use PhpParser\Node\Expr\BinaryOp\Concat; use PhpParser\Node\Expr\BooleanNot; diff --git a/src/Command/DeleteGeneratedCodeCommand.php b/src/Command/DeleteGeneratedCodeCommand.php index 05fac36..3a2b2e1 100644 --- a/src/Command/DeleteGeneratedCodeCommand.php +++ b/src/Command/DeleteGeneratedCodeCommand.php @@ -36,13 +36,6 @@ public function __construct(string $rootPath, ?string $name = null) parent::__construct($name); } - /** - * phpcs:disable SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingNativeTypeHint - * - * @var string|null - */ - protected static $defaultName = self::COMMAND; - protected function configure(): void { $this diff --git a/src/Command/GenerateApiCodeCommand.php b/src/Command/GenerateApiCodeCommand.php index d0db4f0..0a590e8 100644 --- a/src/Command/GenerateApiCodeCommand.php +++ b/src/Command/GenerateApiCodeCommand.php @@ -58,13 +58,6 @@ protected function configure(): void ); } - /** - * phpcs:disable SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingNativeTypeHint - * - * @var string|null - */ - protected static $defaultName = self::COMMAND; - protected function execute(InputInterface $input, OutputInterface $output): int { $keep = (bool) $input->getOption('keep'); diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index 148487e..24e80fa 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -13,7 +13,10 @@ public function getConfigTreeBuilder(): TreeBuilder { $treeBuilder = new TreeBuilder('open_api_server'); - /** @psalm-suppress UndefinedMethod */ + /** + * @psalm-suppress UndefinedMethod + * @psalm-suppress UnusedMethodCall + */ $treeBuilder ->getRootNode() ->children() diff --git a/src/DependencyInjection/OpenApiServerExtension.php b/src/DependencyInjection/OpenApiServerExtension.php index 416633d..3cb4dcb 100644 --- a/src/DependencyInjection/OpenApiServerExtension.php +++ b/src/DependencyInjection/OpenApiServerExtension.php @@ -10,7 +10,7 @@ use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Extension\Extension; use Symfony\Component\DependencyInjection\Extension\ExtensionInterface; -use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; +use Symfony\Component\DependencyInjection\Loader\PhpFileLoader; use function Safe\preg_match; use function Safe\preg_replace; @@ -21,8 +21,8 @@ final class OpenApiServerExtension extends Extension implements ExtensionInterfa /** @param mixed[] $configs */ public function load(array $configs, ContainerBuilder $container): void { - $loader = new XmlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config')); - $loader->load('services.xml'); + $loader = new PhpFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config')); + $loader->load('services.php'); $configuration = new Configuration(); /** diff --git a/src/Resources/config/services.php b/src/Resources/config/services.php new file mode 100644 index 0000000..6511cfe --- /dev/null +++ b/src/Resources/config/services.php @@ -0,0 +1,110 @@ +services() + ->defaults() + ->autoconfigure() + ->autowire() + ->set(Httpstatus::class) + ->set(ReservedWords::class) + ->set(RouteLoader::class) + ->tag('routing.loader') + ->set(ValidatorBuilder::class) + ->set(Psr17Factory::class) + ->set(PsrHttpFactory::class) + ->args([ + new ReferenceConfigurator(Psr17Factory::class), + new ReferenceConfigurator(Psr17Factory::class), + new ReferenceConfigurator(Psr17Factory::class), + new ReferenceConfigurator(Psr17Factory::class), + ]) + ->set(RequestSchemaValidator::class, LeaguePSR7RequestSchemaValidator::class) + ->set(ApiController::class) + ->tag('controller.service_arguments') + ->set(ArgumentResolver::class) + ->set(ScalarTypesResolver::class) + ->set(BuilderFactory::class) + ->set(NamingStrategy::class, DefaultNamingStrategy::class) + ->args([ + '$rootNamespace' => '%openapi.generated.code.root.namespace%', + '$languageLevel' => '%openapi.generated.code.language.level%', + ]) + ->set(DtoCodeGenerator::class) + ->args([ + '$languageLevel' => '%openapi.generated.code.language.level%', + '$fullDocs' => '%openapi.generated.code.full.doc.blocks%', + ]) + ->set(InterfaceCodeGenerator::class) + ->args([ + '$languageLevel' => '%openapi.generated.code.language.level%', + '$fullDocs' => '%openapi.generated.code.full.doc.blocks%', + ]) + ->set(ServiceSubscriberCodeGenerator::class) + ->args([ + '$languageLevel' => '%openapi.generated.code.language.level%', + '$fullDocs' => '%openapi.generated.code.full.doc.blocks%', + ]) + ->set(FileWriter::class, FilePutContentsFileWriter::class) + ->args(['%openapi.generated.code.dir.permissions%']) + ->set(GenerateApiCodeCommand::class) + ->args([ + '$cache' => new ReferenceConfigurator('cache.app.taggable'), + '$rootPath' => '%openapi.generated.code.root.path%', + ]) + ->set(ApiServerCodeGenerator::class) + ->set(DeleteGeneratedCodeCommand::class) + ->args(['%openapi.generated.code.root.path%']) + ->set(DtoSerializer::class, ArrayDtoSerializer::class) + ->args(['$sendNulls' => '%openapi.send.nulls%']) + ->set(SpecificationLoader::class) + ->args([ + '$locator' => new ReferenceConfigurator('file_locator'), + '$cache' => new ReferenceConfigurator('cache.app.taggable'), + ]) + ->set(SpecificationParser::class) + ->args(['$skipHttpCodes' => '%openapi.generated.code.skip.http.codes%']) + ->set(GraphGenerator::class) + ->set(AttributeGenerator::class) + ->set(FileGenerator::class) + ->set(NameGenerator::class) + ->args([ + '$rootNamespace' => '%openapi.generated.code.root.namespace%', + '$rootPath' => '%openapi.generated.code.root.path%', + ]); +}; diff --git a/src/Types/ScalarTypesResolver.php b/src/Types/ScalarTypesResolver.php index 5b17ab5..69df08b 100644 --- a/src/Types/ScalarTypesResolver.php +++ b/src/Types/ScalarTypesResolver.php @@ -122,31 +122,29 @@ public function isDateTime(int $id): bool public function findScalarType(?string $type, ?string $format): int { - if ($type === null) { - return 0; - } + if ($type !== null) { + if ($format !== null) { + foreach ($this->scalarTypes as $id => $scalar) { + if ( + $scalar['type'] === $type && + isset($scalar['format']) && + $scalar['format'] === $format + ) { + return $id; + } + } + } - if ($format !== null) { foreach ($this->scalarTypes as $id => $scalar) { if ( $scalar['type'] === $type && - isset($scalar['format']) && - $scalar['format'] === $format + ! isset($scalar['format']) ) { return $id; } } } - foreach ($this->scalarTypes as $id => $scalar) { - if ( - $scalar['type'] === $type && - ! isset($scalar['format']) - ) { - return $id; - } - } - return 0; } } diff --git a/test/functional/DependencyInjection/ConfigurationTest.php b/test/functional/DependencyInjection/ConfigurationTest.php index f700e80..521cf62 100644 --- a/test/functional/DependencyInjection/ConfigurationTest.php +++ b/test/functional/DependencyInjection/ConfigurationTest.php @@ -90,12 +90,17 @@ public function testParametersCannotBeEmpty(array $configuration, string $parame public static function parametersEnumDataProvider(): array { return [ - [['specs' => [['path' => 'test', 'type' => 'someRandomString']]], 'specs.0.type', 'someRandomString', '"yaml", "json"'], + [ + ['specs' => [['path' => 'test', 'type' => 'someRandomString']]], + 'specs.0.type', + 'someRandomString', + '"yaml", "json"', + ], [ ['specs' => [['path' => 'test', 'name_space' => 'test', 'media_type' => 'someRandomString']]], 'specs.0.media_type', 'someRandomString', - '"application\/json"', + '"application/json"', ], ]; } From d7a63b4bd9b94afc058d0662e0dfde907de5e344 Mon Sep 17 00:00:00 2001 From: Patrik Foldes Date: Thu, 19 Feb 2026 13:31:04 +0300 Subject: [PATCH 2/4] fix test --- .../DependencyInjection/ConfigurationTest.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/functional/DependencyInjection/ConfigurationTest.php b/test/functional/DependencyInjection/ConfigurationTest.php index 521cf62..616d8ad 100644 --- a/test/functional/DependencyInjection/ConfigurationTest.php +++ b/test/functional/DependencyInjection/ConfigurationTest.php @@ -92,15 +92,15 @@ public static function parametersEnumDataProvider(): array return [ [ ['specs' => [['path' => 'test', 'type' => 'someRandomString']]], - 'specs.0.type', + 'specs\.0\.type', 'someRandomString', '"yaml", "json"', ], [ ['specs' => [['path' => 'test', 'name_space' => 'test', 'media_type' => 'someRandomString']]], - 'specs.0.media_type', + 'specs\.0\.media_type', 'someRandomString', - '"application/json"', + '"application\\\?\/json"', ], ]; } @@ -118,11 +118,11 @@ public function testParametersEnumDataProvider( string $permissibleValues ): void { $this->assertConfigurationIsInvalid([$configuration], sprintf( - 'The value "%s" is not allowed for path "open_api_server.%s". Permissible values: %s', + '/The value "%s" is not allowed for path "open_api_server\.%s"\. Permissible values: %s/', $notAllowedValue, $parameterName, $permissibleValues - )); + ), true); } public function testParametersDefaultValues(): void From f7ddd862bafc385e410845c5f912eb181bedf23b Mon Sep 17 00:00:00 2001 From: Patrik Foldes Date: Thu, 19 Feb 2026 14:06:40 +0300 Subject: [PATCH 3/4] improve coverage --- phpunit.xml.dist | 7 ++- .../DeleteGeneratedCodeCommandTest.php | 3 ++ .../Command/GenerateApiCodeCommandTest.php | 45 +++++++++++++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 7b61c73..3ab2db2 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,5 +1,10 @@ - + ./test/unit diff --git a/test/functional/Command/DeleteGeneratedCodeCommandTest.php b/test/functional/Command/DeleteGeneratedCodeCommandTest.php index db5ad3a..96db3b8 100644 --- a/test/functional/Command/DeleteGeneratedCodeCommandTest.php +++ b/test/functional/Command/DeleteGeneratedCodeCommandTest.php @@ -29,6 +29,7 @@ public function setUp(): void mkdir(TestKernel::$bundleRootPath); } + mkdir(TestKernel::$bundleRootPath . '/Test'); file_put_contents(TestKernel::$bundleRootPath . '/test.txt', ''); } @@ -44,6 +45,7 @@ public function testDeletion(): void Assert::assertEquals(sprintf('Delete all contents of the directory %1$s? (y/n): All contents of directory were deleted: %1$s', TestKernel::$bundleRootPath), rtrim($output)); Assert::assertSame(0, $this->commandTester->getStatusCode()); Assert::assertFileDoesNotExist(TestKernel::$bundleRootPath . '/test.txt'); + Assert::assertDirectoryDoesNotExist(TestKernel::$bundleRootPath . '/Test'); } public function testDeletionCancel(): void @@ -59,5 +61,6 @@ public function testDeletionCancel(): void Assert::assertSame(0, $this->commandTester->getStatusCode()); Assert::assertDirectoryExists(TestKernel::$bundleRootPath); Assert::assertFileExists(TestKernel::$bundleRootPath . '/test.txt'); + Assert::assertDirectoryExists(TestKernel::$bundleRootPath . '/Test'); } } diff --git a/test/functional/Command/GenerateApiCodeCommandTest.php b/test/functional/Command/GenerateApiCodeCommandTest.php index 4c14b39..2e413c8 100644 --- a/test/functional/Command/GenerateApiCodeCommandTest.php +++ b/test/functional/Command/GenerateApiCodeCommandTest.php @@ -9,7 +9,11 @@ use PHPUnit\Framework\Assert; use Symfony\Component\Console\Tester\CommandTester; +use function file_put_contents; +use function mkdir; +use function rmdir; use function rtrim; +use function Safe\unlink; use function sprintf; use function ucfirst; @@ -28,6 +32,13 @@ public function setUp(): void public function testGeneration(): void { + $orphanFilePath = TestKernel::$bundleRootPath . DIRECTORY_SEPARATOR . 'should_be_deleted.php'; + $orphanDirectoryPath = TestKernel::$bundleRootPath . DIRECTORY_SEPARATOR . 'ShouldBeDeleted'; + + mkdir(TestKernel::$bundleRootPath); + mkdir($orphanDirectoryPath); + file_put_contents($orphanFilePath, 'commandTester->execute([ 'command' => GenerateApiCodeCommand::COMMAND, ]); @@ -43,5 +54,39 @@ public function testGeneration(): void Assert::assertFileExists(TestKernel::$bundleRootPath . DIRECTORY_SEPARATOR . 'Apis' . DIRECTORY_SEPARATOR . $this->openapiNamespace . DIRECTORY_SEPARATOR . ucfirst($this->openapiOperationId) . DIRECTORY_SEPARATOR . 'Dto' . DIRECTORY_SEPARATOR . 'Request' . DIRECTORY_SEPARATOR . ucfirst($this->openapiOperationId) . 'RequestDto.php'); Assert::assertFileExists(TestKernel::$bundleRootPath . DIRECTORY_SEPARATOR . 'Apis' . DIRECTORY_SEPARATOR . $this->openapiNamespace . DIRECTORY_SEPARATOR . ucfirst($this->openapiOperationId) . DIRECTORY_SEPARATOR . 'Dto' . DIRECTORY_SEPARATOR . 'Request' . DIRECTORY_SEPARATOR . 'PathParameters' . DIRECTORY_SEPARATOR . 'PathParametersDto.php'); Assert::assertFileExists(TestKernel::$bundleRootPath . DIRECTORY_SEPARATOR . 'Components' . DIRECTORY_SEPARATOR . $this->openapiNamespace . DIRECTORY_SEPARATOR . 'GoodResponseSchema' . DIRECTORY_SEPARATOR . 'GoodResponseSchema.php'); + Assert::assertFileDoesNotExist($orphanFilePath); + Assert::assertDirectoryDoesNotExist($orphanDirectoryPath); + } + + public function testGenerationNoKeep(): void + { + $orphanFilePath = TestKernel::$bundleRootPath . DIRECTORY_SEPARATOR . 'should_be_deleted.php'; + $orphanDirectoryPath = TestKernel::$bundleRootPath . DIRECTORY_SEPARATOR . 'ShouldBeDeleted'; + + mkdir(TestKernel::$bundleRootPath); + mkdir($orphanDirectoryPath); + file_put_contents($orphanFilePath, 'commandTester->execute([ + 'command' => GenerateApiCodeCommand::COMMAND . '-k -z --aaaa=xx', + '--keep' => true, + ]); + + $output = $this->commandTester->getDisplay(); + + Assert::assertEquals(sprintf('API server code generated in: %s', TestKernel::$bundleRootPath), rtrim($output)); + Assert::assertSame(0, $this->commandTester->getStatusCode()); + Assert::assertDirectoryExists(TestKernel::$bundleRootPath); + Assert::assertDirectoryIsReadable(TestKernel::$bundleRootPath); + Assert::assertFileExists(TestKernel::$bundleRootPath . DIRECTORY_SEPARATOR . 'ServiceSubscriber' . DIRECTORY_SEPARATOR . 'ApiServiceLoaderServiceSubscriber.php'); + Assert::assertFileExists(TestKernel::$bundleRootPath . DIRECTORY_SEPARATOR . 'Apis' . DIRECTORY_SEPARATOR . $this->openapiNamespace . DIRECTORY_SEPARATOR . ucfirst($this->openapiOperationId) . DIRECTORY_SEPARATOR . ucfirst($this->openapiOperationId) . '.php'); + Assert::assertFileExists(TestKernel::$bundleRootPath . DIRECTORY_SEPARATOR . 'Apis' . DIRECTORY_SEPARATOR . $this->openapiNamespace . DIRECTORY_SEPARATOR . ucfirst($this->openapiOperationId) . DIRECTORY_SEPARATOR . 'Dto' . DIRECTORY_SEPARATOR . 'Request' . DIRECTORY_SEPARATOR . ucfirst($this->openapiOperationId) . 'RequestDto.php'); + Assert::assertFileExists(TestKernel::$bundleRootPath . DIRECTORY_SEPARATOR . 'Apis' . DIRECTORY_SEPARATOR . $this->openapiNamespace . DIRECTORY_SEPARATOR . ucfirst($this->openapiOperationId) . DIRECTORY_SEPARATOR . 'Dto' . DIRECTORY_SEPARATOR . 'Request' . DIRECTORY_SEPARATOR . 'PathParameters' . DIRECTORY_SEPARATOR . 'PathParametersDto.php'); + Assert::assertFileExists(TestKernel::$bundleRootPath . DIRECTORY_SEPARATOR . 'Components' . DIRECTORY_SEPARATOR . $this->openapiNamespace . DIRECTORY_SEPARATOR . 'GoodResponseSchema' . DIRECTORY_SEPARATOR . 'GoodResponseSchema.php'); + Assert::assertFileExists($orphanFilePath); + Assert::assertDirectoryExists($orphanDirectoryPath); + + rmdir($orphanDirectoryPath); + unlink($orphanFilePath); } } From aa34ef53e59bb4284b04183d296670fe3c228adc Mon Sep 17 00:00:00 2001 From: Patrik Foldes Date: Thu, 19 Feb 2026 14:13:26 +0300 Subject: [PATCH 4/4] fix coverage --- phpunit.xml.dist | 3 ++ src/Resources/config/services.xml | 73 ------------------------------- 2 files changed, 3 insertions(+), 73 deletions(-) delete mode 100644 src/Resources/config/services.xml diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 3ab2db2..66cddfb 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -25,5 +25,8 @@ ./src + + ./src/Resources/config + diff --git a/src/Resources/config/services.xml b/src/Resources/config/services.xml deleted file mode 100644 index e087842..0000000 --- a/src/Resources/config/services.xml +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - %openapi.generated.code.root.namespace% - %openapi.generated.code.language.level% - - - %openapi.generated.code.language.level% - %openapi.generated.code.full.doc.blocks% - - - %openapi.generated.code.language.level% - %openapi.generated.code.full.doc.blocks% - - - %openapi.generated.code.language.level% - %openapi.generated.code.full.doc.blocks% - - - %openapi.generated.code.dir.permissions% - - - %openapi.generated.code.root.path% - - - - - %openapi.generated.code.root.path% - - - %openapi.send.nulls% - - - - - - - %openapi.generated.code.skip.http.codes% - - - - - - %openapi.generated.code.root.namespace% - %openapi.generated.code.root.path% - - -