From fc5d60d74b63806f7d6bb80b8393db1a12ae2dbc Mon Sep 17 00:00:00 2001 From: Djordy Koert Date: Sat, 6 Apr 2024 14:08:11 +0200 Subject: [PATCH] phpstan installation (#2249) * phpstan installation * remove old symfony 4.2 code * deprecate unused property * remove symfony 5.3 BC layer * remove bleedingEdge * remove phpstan/extension-installer * add phpstan-strict-rules * rename to phpstan.dist.neon * add phpstan job * add phpstan-symfony application loader * remove phpVersion * source code fixes PHPStan level 1 * test code fixes PHPStan level 1 * fix strings used for int Asserts * revert util change for PHP < 8.1 * remove mixed type usage * remove __callStatic * add baseline command * PHPStan level 2 * cleanup ControllerReflector class * remove bitwise operator usage * PHPStan level 3 * PHPStan level 4 * PHPStan level 5 * bump deprecation version Co-authored-by: Dominic Luidold * Create dependabot.yml * Bump actions/cache from 3 to 4 Bumps [actions/cache](https://github.com/actions/cache) from 3 to 4. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * drop sensio/framework-extra-bundle (#2256) * add phpstan-baseline description * remove config section * move PropertyDescriberInterface errors to baseline * add phpstan.neon to gitignore --------- Signed-off-by: dependabot[bot] Co-authored-by: Dominic Luidold Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/continuous-integration.yml | 26 +++ .gitignore | 1 + composer.json | 19 +- phpstan-baseline.neon | 126 +++++++++++ phpstan.dist.neon | 30 +++ src/Annotation/Areas.php | 9 +- src/ApiDocGenerator.php | 4 +- src/Command/DumpCommand.php | 2 +- src/DependencyInjection/Configuration.php | 7 +- .../NelmioApiDocExtension.php | 2 +- src/Describer/ApiPlatformDescriber.php | 4 +- src/Describer/DefaultDescriber.php | 2 +- src/Describer/ExternalDocDescriber.php | 2 +- src/Describer/OpenApiPhpDescriber.php | 17 +- src/Model/ModelRegistry.php | 17 +- .../Annotations/OpenApiAnnotationsReader.php | 14 +- .../Annotations/PropertyPhpDocReader.php | 11 +- .../SymfonyConstraintAnnotationReader.php | 23 +- .../BazingaHateoasModelDescriber.php | 9 +- src/ModelDescriber/FormModelDescriber.php | 14 +- src/ModelDescriber/JMSModelDescriber.php | 6 +- src/ModelDescriber/ObjectModelDescriber.php | 6 +- .../SelfDescribingModelDescriber.php | 2 +- src/OpenApiPhp/Util.php | 43 +++- src/Processor/MapRequestPayloadProcessor.php | 4 +- src/Processor/NullablePropertyProcessor.php | 2 +- .../ArrayPropertyDescriber.php | 4 +- .../ObjectPropertyDescriber.php | 7 +- src/PropertyDescriber/PropertyDescriber.php | 2 +- src/Render/RenderOpenApi.php | 2 +- src/RouteDescriber/RouteArgumentDescriber.php | 2 +- .../SymfonyMapQueryParameterDescriber.php | 1 - .../SymfonyMapQueryStringDescriber.php | 5 - .../SymfonyMapRequestPayloadDescriber.php | 5 - src/RouteDescriber/RouteDescriberTrait.php | 10 +- src/RouteDescriber/RouteMetadataDescriber.php | 2 +- .../FilteredRouteCollectionBuilder.php | 2 +- src/Util/ControllerReflector.php | 77 ++----- tests/ApiDocGeneratorTest.php | 4 +- tests/Command/DumpCommandTest.php | 2 +- .../DependencyInjection/ConfigurationTest.php | 6 +- .../NelmioApiDocExtensionTest.php | 26 +-- tests/Describer/ApiPlatformDescriberTest.php | 10 +- tests/Describer/RouteDescriberTest.php | 19 +- tests/Functional/BazingaFunctionalTest.php | 19 +- tests/Functional/ControllerTest.php | 2 +- .../CsrfProtectionFunctionalTest.php | 8 +- .../Entity/JMSNamingStrategyConstraints80.php | 2 +- .../Entity/JMSNamingStrategyConstraints81.php | 2 +- .../Entity/SymfonyConstraints80.php | 6 +- .../Entity/SymfonyConstraints81.php | 4 +- tests/Functional/FOSRestTest.php | 36 ++-- tests/Functional/FunctionalTest.php | 198 +++++++++--------- tests/Functional/JMSFunctionalTest.php | 36 ++-- .../SwaggerPHPApiComplianceTest.php | 5 +- tests/Functional/SwaggerUiTest.php | 38 ++-- tests/Functional/SymfonyFunctionalTest.php | 2 +- tests/Functional/TestKernel.php | 55 ++--- .../ValidationGroupsFunctionalTest.php | 4 +- tests/Functional/WebTestCase.php | 51 ++--- tests/Model/ModelRegistryTest.php | 10 +- .../Annotations/AnnotationReaderTest.php | 16 +- .../SymfonyConstraintAnnotationReaderTest.php | 126 +++++------ .../ApplyOpenApiDiscriminatorTraitTest.php | 20 +- .../ModelDescriber/FormModelDescriberTest.php | 25 ++- .../SelfDescribingModelDescriberTest.php | 8 +- tests/Render/Html/GetNelmioAssetTest.php | 5 +- tests/Render/RenderOpenApiTest.php | 4 +- tests/RouteDescriber/FosRestDescriberTest.php | 8 +- .../RouteMetadataDescriberTest.php | 28 +-- .../FilteredRouteCollectionBuilderTest.php | 20 +- tests/SwaggerPhp/UtilTest.php | 109 +++++----- tests/Util/ControllerReflectorTest.php | 8 +- tests/console-application.php | 34 +++ 74 files changed, 819 insertions(+), 658 deletions(-) create mode 100644 phpstan-baseline.neon create mode 100644 phpstan.dist.neon create mode 100644 tests/console-application.php diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 68acaad4b..c1d49b86d 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -101,3 +101,29 @@ jobs: - name: Run PHP-CS-Fixer run: vendor/bin/php-cs-fixer check -v --diff + + phpstan: + name: PHPStan + runs-on: ubuntu-22.04 + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 2 + + - name: Install PHP without coverage + uses: shivammathur/setup-php@v2 + with: + php-version: 8.3 + tools: composer, flex + coverage: pcov + + - name: Setup dependencies + uses: ./.github/workflows/common/composer-install + with: + symfony-version: "7.0.*" + install-doctrine-annotations: false + + - name: Run PHPStan + run: vendor/bin/phpstan analyse --memory-limit=2G --no-progress --no-interaction diff --git a/.gitignore b/.gitignore index 152332d20..5e6bcf55c 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ /Tests/Functional/cache /Tests/Functional/logs .idea +/phpstan.neon ###> friendsofphp/php-cs-fixer ### /.php-cs-fixer.php diff --git a/composer.json b/composer.json index 92aaa9afd..f4f22efc1 100644 --- a/composer.json +++ b/composer.json @@ -53,9 +53,16 @@ "jms/serializer": "^1.14|^3.0", "composer/package-versions-deprecated": "1.11.99.1", - "phpunit/phpunit": "^8.5|^9.6", "doctrine/annotations": "^2.0", - "friendsofphp/php-cs-fixer": "^3.52" + + "phpunit/phpunit": "^8.5|^9.6", + + "friendsofphp/php-cs-fixer": "^3.52", + + "phpstan/phpstan": "^1.10", + "phpstan/phpstan-symfony": "^1.3", + "phpstan/phpstan-phpunit": "^1.3", + "phpstan/phpstan-strict-rules": "^1.5" }, "conflict": { "zircote/swagger-php": "4.8.7" @@ -93,11 +100,15 @@ "scripts-descriptions": { "phpcs-check": "Run PHP-CS-Fixer in dry-run mode", "phpcs-fix": "Run PHP-CS-Fixer", - "phpunit": "Run phpunit" + "phpunit": "Run phpunit", + "phpstan": "Run phpstan", + "phpstan-baseline": "Generate a baseline for phpstan" }, "scripts": { "phpcs-check": "vendor/bin/php-cs-fixer check -v --diff", "phpcs-fix": "vendor/bin/php-cs-fixer fix -v", - "phpunit": "phpunit" + "phpunit": "phpunit", + "phpstan": "phpstan --memory-limit=2G", + "phpstan-baseline": "phpstan --memory-limit=2G --generate-baseline" } } diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon new file mode 100644 index 000000000..3ea01054a --- /dev/null +++ b/phpstan-baseline.neon @@ -0,0 +1,126 @@ +parameters: + ignoreErrors: + - + message: "#^Method Nelmio\\\\ApiDocBundle\\\\PropertyDescriber\\\\PropertyDescriberInterface\\:\\:describe\\(\\) invoked with 5 parameters, 2\\-3 required\\.$#" + count: 1 + path: src/PropertyDescriber/ArrayPropertyDescriber.php + + - + message: "#^Method Nelmio\\\\ApiDocBundle\\\\PropertyDescriber\\\\PropertyDescriberInterface\\:\\:describe\\(\\) invoked with 5 parameters, 2\\-3 required\\.$#" + count: 1 + path: src/PropertyDescriber/CompoundPropertyDescriber.php + + - + message: "#^Method Nelmio\\\\ApiDocBundle\\\\PropertyDescriber\\\\PropertyDescriberInterface\\:\\:describe\\(\\) invoked with 5 parameters, 2\\-3 required\\.$#" + count: 1 + path: src/PropertyDescriber/DictionaryPropertyDescriber.php + + - + message: "#^Method Nelmio\\\\ApiDocBundle\\\\PropertyDescriber\\\\PropertyDescriberInterface\\:\\:describe\\(\\) invoked with 5 parameters, 2\\-3 required\\.$#" + count: 1 + path: src/PropertyDescriber/NullablePropertyDescriber.php + + - + message: "#^Method Nelmio\\\\ApiDocBundle\\\\PropertyDescriber\\\\PropertyDescriberInterface\\:\\:describe\\(\\) invoked with 5 parameters, 2\\-3 required\\.$#" + count: 1 + path: src/PropertyDescriber/PropertyDescriber.php + + - + message: "#^PHPDoc tag @param references unknown parameter\\: \\$context$#" + count: 1 + path: src/PropertyDescriber/PropertyDescriberInterface.php + + - + message: "#^PHPDoc tag @param references unknown parameter\\: \\$schema$#" + count: 1 + path: src/PropertyDescriber/PropertyDescriberInterface.php + + - + message: "#^Method Nelmio\\\\ApiDocBundle\\\\PropertyDescriber\\\\PropertyDescriberInterface\\:\\:describe\\(\\) invoked with 5 parameters, 2\\-3 required\\.$#" + count: 1 + path: src/PropertyDescriber/RequiredPropertyDescriber.php + + - + message: "#^Call to method render\\(\\) on an unknown class Twig_Environment\\.$#" + count: 2 + path: src/Render/Html/HtmlOpenApiRenderer.php + + - + message: "#^Class Twig_Environment not found\\.$#" + count: 1 + path: src/Render/Html/HtmlOpenApiRenderer.php + + - + message: "#^Property Nelmio\\\\ApiDocBundle\\\\Render\\\\Html\\\\HtmlOpenApiRenderer\\:\\:\\$twig has unknown class Twig_Environment as its type\\.$#" + count: 1 + path: src/Render/Html/HtmlOpenApiRenderer.php + + - + message: "#^Access to property \\$allowBlank on an unknown class FOS\\\\RestBundle\\\\Controller\\\\Annotations\\\\QueryParam\\.$#" + count: 1 + path: src/RouteDescriber/FosRestDescriber.php + + - + message: "#^Access to property \\$description on an unknown class FOS\\\\RestBundle\\\\Controller\\\\Annotations\\\\QueryParam\\.$#" + count: 1 + path: src/RouteDescriber/FosRestDescriber.php + + - + message: "#^Access to property \\$key on an unknown class FOS\\\\RestBundle\\\\Controller\\\\Annotations\\\\QueryParam\\.$#" + count: 1 + path: src/RouteDescriber/FosRestDescriber.php + + - + message: "#^Access to property \\$key on an unknown class FOS\\\\RestBundle\\\\Controller\\\\Annotations\\\\RequestParam\\.$#" + count: 1 + path: src/RouteDescriber/FosRestDescriber.php + + - + message: "#^Access to property \\$map on an unknown class FOS\\\\RestBundle\\\\Controller\\\\Annotations\\\\QueryParam\\.$#" + count: 2 + path: src/RouteDescriber/FosRestDescriber.php + + - + message: "#^Access to property \\$nullable on an unknown class FOS\\\\RestBundle\\\\Controller\\\\Annotations\\\\QueryParam\\.$#" + count: 2 + path: src/RouteDescriber/FosRestDescriber.php + + - + message: "#^Access to property \\$nullable on an unknown class FOS\\\\RestBundle\\\\Controller\\\\Annotations\\\\RequestParam\\.$#" + count: 1 + path: src/RouteDescriber/FosRestDescriber.php + + - + message: "#^Access to property \\$strict on an unknown class FOS\\\\RestBundle\\\\Controller\\\\Annotations\\\\QueryParam\\.$#" + count: 1 + path: src/RouteDescriber/FosRestDescriber.php + + - + message: "#^Access to property \\$strict on an unknown class FOS\\\\RestBundle\\\\Controller\\\\Annotations\\\\RequestParam\\.$#" + count: 1 + path: src/RouteDescriber/FosRestDescriber.php + + - + message: "#^Call to method getName\\(\\) on an unknown class FOS\\\\RestBundle\\\\Controller\\\\Annotations\\\\QueryParam\\.$#" + count: 1 + path: src/RouteDescriber/FosRestDescriber.php + + - + message: "#^Call to method getName\\(\\) on an unknown class FOS\\\\RestBundle\\\\Controller\\\\Annotations\\\\RequestParam\\.$#" + count: 1 + path: src/RouteDescriber/FosRestDescriber.php + + - + message: "#^Class FOS\\\\RestBundle\\\\Controller\\\\Annotations\\\\QueryParam not found\\.$#" + count: 3 + path: src/RouteDescriber/FosRestDescriber.php + + - + message: "#^Class FOS\\\\RestBundle\\\\Controller\\\\Annotations\\\\RequestParam not found\\.$#" + count: 2 + path: src/RouteDescriber/FosRestDescriber.php + + - + message: "#^Call to function method_exists\\(\\) with 'Hateoas\\\\\\\\Configuration\\\\\\\\Embedded' and 'getType' will always evaluate to true\\.$#" + count: 1 + path: tests/Functional/BazingaFunctionalTest.php diff --git a/phpstan.dist.neon b/phpstan.dist.neon new file mode 100644 index 000000000..4d4d69b79 --- /dev/null +++ b/phpstan.dist.neon @@ -0,0 +1,30 @@ +includes: + - phpstan-baseline.neon + - vendor/phpstan/phpstan-phpunit/extension.neon + - vendor/phpstan/phpstan-phpunit/rules.neon + - vendor/phpstan/phpstan-symfony/extension.neon + - vendor/phpstan/phpstan-symfony/rules.neon + - vendor/phpstan/phpstan-strict-rules/rules.neon + +parameters: + level: 5 + paths: + - src + - tests + excludePaths: + - tests/Functional/Entity/* + - tests/Functional/EntityExcluded/* + - tests/Functional/Controller/* + dynamicConstantNames: + - Symfony\Component\HttpKernel\Kernel::VERSION + - Symfony\Component\HttpKernel\Kernel::VERSION_ID + - Symfony\Component\HttpKernel\Kernel::MAJOR_VERSION + - Symfony\Component\HttpKernel\Kernel::MINOR_VERSION + - Symfony\Component\HttpKernel\Kernel::RELEASE_VERSION + symfony: + consoleApplicationLoader: tests/console-application.php + strictRules: + noVariableVariables: false # Neccessary for swagger-php integration + universalObjectCratesClasses: + - OpenApi\Context + treatPhpDocTypesAsCertain: false diff --git a/src/Annotation/Areas.php b/src/Annotation/Areas.php index ce64ab128..2ac703b4d 100644 --- a/src/Annotation/Areas.php +++ b/src/Annotation/Areas.php @@ -20,6 +20,9 @@ final class Areas /** @var string[] */ private $areas; + /** + * @param string[]|array{value: string[]} $properties + */ public function __construct(array $properties) { if (!array_key_exists('value', $properties) || !is_array($properties['value'])) { @@ -36,15 +39,11 @@ public function __construct(array $properties) throw new \InvalidArgumentException('An area must be given as a string'); } - if (!in_array($area, $areas)) { + if (!in_array($area, $areas, true)) { $areas[] = $area; } } - if (0 === count($areas)) { - throw new \LogicException('At least one area is expected'); - } - $this->areas = $areas; } diff --git a/src/ApiDocGenerator.php b/src/ApiDocGenerator.php index e5a5873f6..4a0da2075 100644 --- a/src/ApiDocGenerator.php +++ b/src/ApiDocGenerator.php @@ -90,14 +90,14 @@ public function generate(): OpenApi return $this->openApi; } - if ($this->cacheItemPool) { + if (null !== $this->cacheItemPool) { $item = $this->cacheItemPool->getItem($this->cacheItemId); if ($item->isHit()) { return $this->openApi = $item->get(); } } - if ($this->openApiVersion) { + if (null !== $this->openApiVersion) { $this->generator->setVersion($this->openApiVersion); } diff --git a/src/Command/DumpCommand.php b/src/Command/DumpCommand.php index 29c78968f..a74821576 100644 --- a/src/Command/DumpCommand.php +++ b/src/Command/DumpCommand.php @@ -77,7 +77,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int ]; } - if ($input->getOption('server-url')) { + if (null !== $input->getOption('server-url')) { $options['server_url'] = $input->getOption('server-url'); } diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index b46946fee..73b5cf56a 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -20,12 +20,7 @@ public function getConfigTreeBuilder(): TreeBuilder { $treeBuilder = new TreeBuilder('nelmio_api_doc'); - if (method_exists($treeBuilder, 'getRootNode')) { - $rootNode = $treeBuilder->getRootNode(); - } else { - // symfony < 4.2 support - $rootNode = $treeBuilder->root('nelmio_api_doc'); - } + $rootNode = $treeBuilder->getRootNode(); $rootNode ->children() diff --git a/src/DependencyInjection/NelmioApiDocExtension.php b/src/DependencyInjection/NelmioApiDocExtension.php index 1994d3982..99555b26a 100644 --- a/src/DependencyInjection/NelmioApiDocExtension.php +++ b/src/DependencyInjection/NelmioApiDocExtension.php @@ -284,7 +284,7 @@ public function load(array $configs, ContainerBuilder $container): void private function findNameAliases(array $names, string $area): array { $nameAliases = array_filter($names, function (array $aliasInfo) use ($area) { - return empty($aliasInfo['areas']) || in_array($area, $aliasInfo['areas'], true); + return [] === $aliasInfo['areas'] || in_array($area, $aliasInfo['areas'], true); }); $aliases = []; diff --git a/src/Describer/ApiPlatformDescriber.php b/src/Describer/ApiPlatformDescriber.php index 620bff449..092237ca0 100644 --- a/src/Describer/ApiPlatformDescriber.php +++ b/src/Describer/ApiPlatformDescriber.php @@ -21,11 +21,11 @@ final class ApiPlatformDescriber extends ExternalDocDescriber public function __construct(object $documentation, NormalizerInterface $normalizer) { if (!$documentation instanceof DocumentationInterface && !$documentation instanceof OpenApi) { - throw new \InvalidArgumentException(sprintf('Argument 1 passed to %s() must be an instance of %s or %s. The documentation provided is an instance of %s.', __METHOD__, Documentation::class, OpenApi::class, get_class($documentation))); + throw new \InvalidArgumentException(sprintf('Argument 1 passed to %s() must be an instance of %s or %s. The documentation provided is an instance of %s.', __METHOD__, DocumentationInterface::class, OpenApi::class, get_class($documentation))); } if (!$normalizer->supportsNormalization($documentation, 'json')) { - throw new \InvalidArgumentException(sprintf('Argument 2 passed to %s() must implement %s and support normalization of %s. The normalizer provided is an instance of %s.', __METHOD__, NormalizerInterface::class, Documentation::class, get_class($normalizer))); + throw new \InvalidArgumentException(sprintf('Argument 2 passed to %s() must implement %s and support normalization of %s. The normalizer provided is an instance of %s.', __METHOD__, NormalizerInterface::class, DocumentationInterface::class, get_class($normalizer))); } parent::__construct(function () use ($documentation, $normalizer) { diff --git a/src/Describer/DefaultDescriber.php b/src/Describer/DefaultDescriber.php index 3812e3a03..57a31df04 100644 --- a/src/Describer/DefaultDescriber.php +++ b/src/Describer/DefaultDescriber.php @@ -42,7 +42,7 @@ public function describe(OA\OpenApi $api) foreach (Util::OPERATIONS as $method) { /** @var OA\Operation $operation */ $operation = $path->{$method}; - if (Generator::UNDEFINED !== $operation && null !== $operation && (Generator::UNDEFINED === $operation->responses || empty($operation->responses))) { + if (Generator::UNDEFINED !== $operation && null !== $operation && (Generator::UNDEFINED === $operation->responses || [] === $operation->responses)) { /** @var OA\Response $response */ $response = Util::getIndexedCollectionItem($operation, OA\Response::class, 'default'); $response->description = ''; diff --git a/src/Describer/ExternalDocDescriber.php b/src/Describer/ExternalDocDescriber.php index e023a3349..2bfa4f94b 100644 --- a/src/Describer/ExternalDocDescriber.php +++ b/src/Describer/ExternalDocDescriber.php @@ -33,7 +33,7 @@ public function describe(OA\OpenApi $api) { $externalDoc = $this->getExternalDoc(); - if (!empty($externalDoc)) { + if ($externalDoc) { Util::merge($api, $externalDoc, $this->overwrite); } } diff --git a/src/Describer/OpenApiPhpDescriber.php b/src/Describer/OpenApiPhpDescriber.php index b631787ee..66399fa5d 100644 --- a/src/Describer/OpenApiPhpDescriber.php +++ b/src/Describer/OpenApiPhpDescriber.php @@ -39,15 +39,17 @@ final class OpenApiPhpDescriber */ private $annotationReader; private $logger; - private $overwrite; public function __construct(RouteCollection $routeCollection, ControllerReflector $controllerReflector, ?Reader $annotationReader, LoggerInterface $logger, bool $overwrite = false) { + if ($overwrite || func_num_args() > 4) { + trigger_deprecation('nelmio/api-doc-bundle', '4.25.2', 'The "$overwrite" argument of "%s" is unused and therefore deprecated.', __METHOD__); + } + $this->routeCollection = $routeCollection; $this->controllerReflector = $controllerReflector; $this->annotationReader = $annotationReader; $this->logger = $logger; - $this->overwrite = $overwrite; } public function describe(OA\OpenApi $api) @@ -155,7 +157,7 @@ public function describe(OA\OpenApi $api) $implicitAnnotations[] = $annotation; } - if (empty($implicitAnnotations) && empty(get_object_vars($mergeProperties))) { + if ([] === $implicitAnnotations && [] === get_object_vars($mergeProperties)) { continue; } @@ -187,7 +189,7 @@ private function getMethodsToParse(): \Generator } $path = $this->normalizePath($route->getPath()); $supportedHttpMethods = $this->getSupportedHttpMethods($route); - if (empty($supportedHttpMethods)) { + if ([] === $supportedHttpMethods) { $this->logger->warning('None of the HTTP methods specified for path {path} are supported by swagger-ui, skipping this path', [ 'path' => $path, ]); @@ -203,7 +205,12 @@ private function getSupportedHttpMethods(Route $route): array $allMethods = Util::OPERATIONS; $methods = array_map('strtolower', $route->getMethods()); - return array_intersect($methods ?: $allMethods, $allMethods); + // an empty array means that any method is allowed + if ([] === $methods) { + return $allMethods; + } + + return array_intersect($methods, $allMethods); } private function normalizePath(string $path): string diff --git a/src/Model/ModelRegistry.php b/src/Model/ModelRegistry.php index c25ce753e..1fadbcaba 100644 --- a/src/Model/ModelRegistry.php +++ b/src/Model/ModelRegistry.php @@ -109,7 +109,7 @@ public function registerSchemas(): void } } - if (empty($this->unregistered) && !empty($this->alternativeNames)) { + if (!$this->unregistered && $this->alternativeNames) { foreach ($this->alternativeNames as $model) { $this->register($model); } @@ -193,31 +193,16 @@ private function typeToString(Type $type): string private function getCollectionKeyTypes(Type $type): array { - // BC layer, this condition should be removed after removing support for symfony < 5.3 - if (!method_exists($type, 'getCollectionKeyTypes')) { - return null !== $type->getCollectionKeyType() ? [$type->getCollectionKeyType()] : []; - } - return $type->getCollectionKeyTypes(); } private function getCollectionValueTypes(Type $type): array { - // BC layer, this condition should be removed after removing support for symfony < 5.3 - if (!method_exists($type, 'getCollectionValueTypes')) { - return null !== $type->getCollectionValueType() ? [$type->getCollectionValueType()] : []; - } - return $type->getCollectionValueTypes(); } private function getCollectionValueType(Type $type): ?Type { - // BC layer, this condition should be removed after removing support for symfony < 5.3 - if (!method_exists($type, 'getCollectionValueTypes')) { - return $type->getCollectionValueType(); - } - return $type->getCollectionValueTypes()[0] ?? null; } } diff --git a/src/ModelDescriber/Annotations/OpenApiAnnotationsReader.php b/src/ModelDescriber/Annotations/OpenApiAnnotationsReader.php index fa11d1f46..a8153263c 100644 --- a/src/ModelDescriber/Annotations/OpenApiAnnotationsReader.php +++ b/src/ModelDescriber/Annotations/OpenApiAnnotationsReader.php @@ -42,8 +42,7 @@ public function __construct(?Reader $annotationsReader, ModelRegistry $modelRegi public function updateSchema(\ReflectionClass $reflectionClass, OA\Schema $schema): void { - /** @var OA\Schema|null $oaSchema */ - if (!$oaSchema = $this->getAnnotation($schema->_context, $reflectionClass, OA\Schema::class)) { + if (null === $oaSchema = $this->getAnnotation($schema->_context, $reflectionClass, OA\Schema::class)) { return; } @@ -59,8 +58,7 @@ public function updateSchema(\ReflectionClass $reflectionClass, OA\Schema $schem public function getPropertyName($reflection, string $default): string { - /** @var OA\Property|null $oaProperty */ - if (!$oaProperty = $this->getAnnotation(new Context(), $reflection, OA\Property::class)) { + if (null === $oaProperty = $this->getAnnotation(new Context(), $reflection, OA\Property::class)) { return $default; } @@ -69,8 +67,7 @@ public function getPropertyName($reflection, string $default): string public function updateProperty($reflection, OA\Property $property, ?array $serializationGroups = null): void { - /** @var OA\Property|null $oaProperty */ - if (!$oaProperty = $this->getAnnotation($property->_context, $reflection, OA\Property::class)) { + if (null === $oaProperty = $this->getAnnotation($property->_context, $reflection, OA\Property::class)) { return; } @@ -85,7 +82,12 @@ public function updateProperty($reflection, OA\Property $property, ?array $seria } /** + * @template T of object + * * @param \ReflectionClass|\ReflectionProperty|\ReflectionMethod $reflection + * @param class-string $className + * + * @return T|null */ private function getAnnotation(Context $parentContext, $reflection, string $className) { diff --git a/src/ModelDescriber/Annotations/PropertyPhpDocReader.php b/src/ModelDescriber/Annotations/PropertyPhpDocReader.php index 5faf75a4b..d3b347f7f 100644 --- a/src/ModelDescriber/Annotations/PropertyPhpDocReader.php +++ b/src/ModelDescriber/Annotations/PropertyPhpDocReader.php @@ -50,15 +50,18 @@ public function updateProperty($reflection, OA\Property $property): void /** @var Var_ $var */ foreach ($docBlock->getTagsByName('var') as $var) { - if (!$title && method_exists($var, 'getDescription') && $description = $var->getDescription()) { + if (!$title && method_exists($var, 'getDescription') && null !== $description = $var->getDescription()) { $title = $description->render(); } if ( - (!isset($min) || null !== $min) && (!isset($max) || null !== $max) - && method_exists($var, 'getType') && $type = $var->getType() + !isset($min) + && !isset($max) + && method_exists($var, 'getType') && null !== $varType = $var->getType() ) { - $types = $type instanceof Compound ? $type->getIterator() : [$type]; + $types = $varType instanceof Compound + ? $varType->getIterator() + : [$varType]; foreach ($types as $type) { if ($type instanceof IntegerRange) { diff --git a/src/ModelDescriber/Annotations/SymfonyConstraintAnnotationReader.php b/src/ModelDescriber/Annotations/SymfonyConstraintAnnotationReader.php index 2f808a0e8..78c09f4ed 100644 --- a/src/ModelDescriber/Annotations/SymfonyConstraintAnnotationReader.php +++ b/src/ModelDescriber/Annotations/SymfonyConstraintAnnotationReader.php @@ -68,8 +68,7 @@ private function processPropertyAnnotations($reflection, OA\Property $property, { foreach ($annotations as $annotation) { if ($annotation instanceof Assert\NotBlank || $annotation instanceof Assert\NotNull) { - // To support symfony/validator < 4.3 - if ($annotation instanceof Assert\NotBlank && \property_exists($annotation, 'allowNull') && $annotation->allowNull) { + if ($annotation instanceof Assert\NotBlank && $annotation->allowNull) { // The field is optional return; } @@ -94,19 +93,19 @@ private function processPropertyAnnotations($reflection, OA\Property $property, $this->schema->required = array_values(array_unique($existingRequiredFields)); } elseif ($annotation instanceof Assert\Length) { if (isset($annotation->min)) { - $property->minLength = (int) $annotation->min; + $property->minLength = $annotation->min; } if (isset($annotation->max)) { - $property->maxLength = (int) $annotation->max; + $property->maxLength = $annotation->max; } } elseif ($annotation instanceof Assert\Regex) { $this->appendPattern($property, $annotation->getHtmlPattern()); } elseif ($annotation instanceof Assert\Count) { if (isset($annotation->min)) { - $property->minItems = (int) $annotation->min; + $property->minItems = $annotation->min; } if (isset($annotation->max)) { - $property->maxItems = (int) $annotation->max; + $property->maxItems = $annotation->max; } } elseif ($annotation instanceof Assert\Choice) { $this->applyEnumFromChoiceConstraint($property, $annotation, $reflection); @@ -164,7 +163,7 @@ private function appendPattern(OA\Schema $property, $newPattern): void */ private function applyEnumFromChoiceConstraint(OA\Schema $property, Assert\Choice $choice, $reflection): void { - if ($choice->callback) { + if (null !== $choice->callback) { $enumValues = call_user_func(is_array($choice->callback) ? $choice->callback : [$reflection->class, $choice->callback]); } else { $enumValues = $choice->choices; @@ -229,9 +228,13 @@ private function locateAnnotations($reflection): \Traversable */ private function isConstraintInGroup(Constraint $annotation, ?array $validationGroups): bool { - return count(array_intersect( - $validationGroups ?: [Constraint::DEFAULT_GROUP], + if (null === $validationGroups) { + $validationGroups = [Constraint::DEFAULT_GROUP]; + } + + return [] !== array_intersect( + $validationGroups, (array) $annotation->groups - )) > 0; + ); } } diff --git a/src/ModelDescriber/BazingaHateoasModelDescriber.php b/src/ModelDescriber/BazingaHateoasModelDescriber.php index 8fe05a9f7..c1cfa0b3c 100644 --- a/src/ModelDescriber/BazingaHateoasModelDescriber.php +++ b/src/ModelDescriber/BazingaHateoasModelDescriber.php @@ -58,7 +58,7 @@ public function describe(Model $model, OA\Schema $schema): void /** @var Relation $relation */ foreach ($metadata->getRelations() as $relation) { - if (!$relation->getEmbedded() && !$relation->getHref()) { + if (null === $relation->getEmbedded() && null === $relation->getHref()) { continue; } $item = new RelationPropertyMetadata($relation->getExclusion(), $relation); @@ -70,16 +70,16 @@ public function describe(Model $model, OA\Schema $schema): void $context->pushPropertyMetadata($item); $embedded = $relation->getEmbedded(); - $relationSchema = Util::getProperty($schema, $relation->getEmbedded() ? '_embedded' : '_links'); + $relationSchema = Util::getProperty($schema, null !== $relation->getEmbedded() ? '_embedded' : '_links'); $relationSchema->readOnly = true; $property = Util::getProperty($relationSchema, $relation->getName()); - if ($embedded && method_exists($embedded, 'getType') && $embedded->getType()) { + if (null !== $embedded && method_exists($embedded, 'getType') && null !== $embedded->getType()) { $this->JMSModelDescriber->describeItem($embedded->getType(), $property, $context); } else { $property->type = 'object'; } - if ($relation->getHref()) { + if (null !== $relation->getHref()) { $hrefProp = Util::getProperty($property, 'href'); $hrefProp->type = 'string'; $this->setAttributeProperties($relation, $property); @@ -119,7 +119,6 @@ private function setAttributeProperties(Relation $relation, OA\Property $subProp break; case 'double': - case 'float': $subSubProp->type = 'number'; $subSubProp->default = $value; diff --git a/src/ModelDescriber/FormModelDescriber.php b/src/ModelDescriber/FormModelDescriber.php index 060b3ea6b..998ab3eb5 100644 --- a/src/ModelDescriber/FormModelDescriber.php +++ b/src/ModelDescriber/FormModelDescriber.php @@ -140,7 +140,7 @@ private function parseForm(OA\Schema $schema, FormInterface $form) $this->findFormType($config, $property); } - if ($this->isFormCsrfExtensionEnabled && $form->getConfig()->getOption('csrf_protection', false)) { + if ($this->isFormCsrfExtensionEnabled && true === $form->getConfig()->getOption('csrf_protection')) { $tokenFieldName = $form->getConfig()->getOption('csrf_field_name'); $property = Util::getProperty($schema, $tokenFieldName); @@ -164,7 +164,7 @@ private function findFormType(FormConfigInterface $config, OA\Schema $property) { $type = $config->getType(); - if (!$builtinFormType = $this->getBuiltinFormType($type)) { + if (null === $builtinFormType = $this->getBuiltinFormType($type)) { // if form type is not builtin in Form component. $model = new Model( new Type(Type::BUILTIN_TYPE_OBJECT, false, get_class($type->getInnerType())), @@ -174,7 +174,7 @@ private function findFormType(FormConfigInterface $config, OA\Schema $property) $ref = $this->modelRegistry->register($model); // We need to use allOf for description and title to be displayed - if ($config->hasOption('documentation') && !empty($config->getOption('documentation'))) { + if ($config->hasOption('documentation') && [] !== $config->getOption('documentation')) { $property->oneOf = [new OA\Schema(['ref' => $ref])]; } else { $property->ref = $ref; @@ -219,12 +219,12 @@ private function findFormType(FormConfigInterface $config, OA\Schema $property) } if ('choice' === $blockPrefix) { - if ($config->getOption('multiple')) { + if (true === $config->getOption('multiple')) { $property->type = 'array'; } else { $property->type = 'string'; } - if (($choices = $config->getOption('choices')) && is_array($choices) && count($choices)) { + if ([] !== $choices = $config->getOption('choices')) { $enums = array_values($choices); if ($this->isNumbersArray($enums)) { $type = 'number'; @@ -234,7 +234,7 @@ private function findFormType(FormConfigInterface $config, OA\Schema $property) $type = 'string'; } - if ($config->getOption('multiple')) { + if (true === $config->getOption('multiple')) { $property->items = Util::createChild($property, OA\Items::class, ['type' => $type, 'enum' => $enums]); } else { $property->type = $type; @@ -290,7 +290,7 @@ private function findFormType(FormConfigInterface $config, OA\Schema $property) if ('entity' === $blockPrefix || 'document' === $blockPrefix) { $entityClass = $config->getOption('class'); - if ($config->getOption('multiple')) { + if (true === $config->getOption('multiple')) { $property->format = sprintf('[%s id]', $entityClass); $property->type = 'array'; $property->items = Util::createChild($property, OA\Items::class, ['type' => 'string']); diff --git a/src/ModelDescriber/JMSModelDescriber.php b/src/ModelDescriber/JMSModelDescriber.php index 2eed24280..3d38eebae 100644 --- a/src/ModelDescriber/JMSModelDescriber.php +++ b/src/ModelDescriber/JMSModelDescriber.php @@ -87,7 +87,7 @@ public function describe(Model $model, OA\Schema $schema) throw new \InvalidArgumentException(sprintf('No metadata found for class %s.', $className)); } - if (!empty($metadata->discriminatorFieldName) + if (null !== $metadata->discriminatorFieldName && $className === $metadata->discriminatorBaseClass && [] !== $metadata->discriminatorMap && Generator::UNDEFINED === $schema->discriminator) { @@ -267,7 +267,7 @@ public function describeItem(array $type, OA\Schema $property, Context $context) [$nestedType, $isHash] = $nestedTypeInfo; if ($isHash) { $property->type = 'object'; - $property->additionalProperties = Util::createChild($property, OA\Property::class); + $property->additionalProperties = Util::createChild($property, OA\AdditionalProperties::class); // this is a free form object (as nested array) if ('array' === $nestedType['name'] && !isset($nestedType['params'][0])) { @@ -317,7 +317,7 @@ public function describeItem(array $type, OA\Schema $property, Context $context) $customFields = (array) $property->jsonSerialize(); unset($customFields['property']); - if (empty($customFields)) { // no custom fields + if ([] === $customFields) { // no custom fields $property->ref = $modelRef; } else { $weakContext = Util::createWeakContext($property->_context); diff --git a/src/ModelDescriber/ObjectModelDescriber.php b/src/ModelDescriber/ObjectModelDescriber.php index c20b48a39..5a93158fa 100644 --- a/src/ModelDescriber/ObjectModelDescriber.php +++ b/src/ModelDescriber/ObjectModelDescriber.php @@ -23,6 +23,7 @@ use Symfony\Component\PropertyInfo\PropertyInfoExtractorInterface; use Symfony\Component\PropertyInfo\Type; use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface; +use Symfony\Component\Serializer\NameConverter\AdvancedNameConverterInterface; use Symfony\Component\Serializer\NameConverter\NameConverterInterface; class ObjectModelDescriber implements ModelDescriberInterface, ModelRegistryAwareInterface @@ -40,13 +41,14 @@ class ObjectModelDescriber implements ModelDescriberInterface, ModelRegistryAwar private $propertyDescriber; /** @var string[] */ private $mediaTypes; - /** @var NameConverterInterface|null */ + /** @var (NameConverterInterface&AdvancedNameConverterInterface)|null */ private $nameConverter; /** @var bool */ private $useValidationGroups; /** - * @param PropertyDescriberInterface|PropertyDescriberInterface[] $propertyDescribers + * @param PropertyDescriberInterface|PropertyDescriberInterface[] $propertyDescribers + * @param (NameConverterInterface&AdvancedNameConverterInterface)|null $nameConverter */ public function __construct( PropertyInfoExtractorInterface $propertyInfo, diff --git a/src/ModelDescriber/SelfDescribingModelDescriber.php b/src/ModelDescriber/SelfDescribingModelDescriber.php index a4f5f6fc8..fce60ea37 100644 --- a/src/ModelDescriber/SelfDescribingModelDescriber.php +++ b/src/ModelDescriber/SelfDescribingModelDescriber.php @@ -23,7 +23,7 @@ public function describe(Model $model, OA\Schema $schema): void public function supports(Model $model): bool { - return $model->getType()->getClassName() + return null !== $model->getType()->getClassName() && class_exists($model->getType()->getClassName()) && is_a($model->getType()->getClassName(), SelfDescribingModelInterface::class, true); } diff --git a/src/OpenApiPhp/Util.php b/src/OpenApiPhp/Util.php index 116759bbf..fa3f18e2c 100644 --- a/src/OpenApiPhp/Util.php +++ b/src/OpenApiPhp/Util.php @@ -125,6 +125,10 @@ public static function getOperation(OA\PathItem $path, $method): OA\Operation { $class = array_keys($path::$_nested, \strtolower($method), true)[0]; + if (!is_a($class, OA\Operation::class, true)) { + throw new \InvalidArgumentException('Invalid operation class provided.'); + } + return self::getChild($path, $class, ['path' => $path->path]); } @@ -154,6 +158,12 @@ public static function getOperationParameter(OA\Operation $operation, $name, $in * $property is determined from $parent::$_nested[$class] * it is expected to be a string nested property. * + * @template T of OA\AbstractAnnotation + * + * @param class-string $class + * + * @return T + * * @see OA\AbstractAnnotation::$_nested */ public static function getChild(OA\AbstractAnnotation $parent, $class, array $properties = []): OA\AbstractAnnotation @@ -178,9 +188,13 @@ public static function getChild(OA\AbstractAnnotation $parent, $class, array $pr * $collection is determined from $parent::$_nested[$class] * it is expected to be a single value array nested Annotation. * - * @see OA\AbstractAnnotation::$_nested + * @template T of OA\AbstractAnnotation * - * @param string $class + * @param class-string $class + * + * @return T + * + * @see OA\AbstractAnnotation::$_nested */ public static function getCollectionItem(OA\AbstractAnnotation $parent, $class, array $properties = []): OA\AbstractAnnotation { @@ -188,7 +202,7 @@ public static function getCollectionItem(OA\AbstractAnnotation $parent, $class, $nested = $parent::$_nested; $collection = $nested[$class][0]; - if (!empty($properties)) { + if ([] !== $properties) { $key = self::searchCollectionItem( $parent->{$collection} && Generator::UNDEFINED !== $parent->{$collection} ? $parent->{$collection} : [], $properties @@ -211,9 +225,13 @@ public static function getCollectionItem(OA\AbstractAnnotation $parent, $class, * it is expected to be a double value array nested Annotation * with the second value being the mapping index $property. * - * @see OA\AbstractAnnotation::$_nested + * @template T of OA\AbstractAnnotation * - * @param string $class + * @param class-string $class + * + * @return T + * + * @see OA\AbstractAnnotation::$_nested */ public static function getIndexedCollectionItem(OA\AbstractAnnotation $parent, $class, $value): OA\AbstractAnnotation { @@ -241,7 +259,7 @@ public static function getIndexedCollectionItem(OA\AbstractAnnotation $parent, $ */ public static function searchCollectionItem(array $collection, array $properties) { - foreach ($collection ?: [] as $i => $child) { + foreach ($collection as $i => $child) { foreach ($properties as $k => $prop) { if ($child->{$k} !== $prop) { continue 2; @@ -279,7 +297,7 @@ public static function createCollectionItem(OA\AbstractAnnotation $parent, $coll $parent->{$collection} = []; } - $key = \count($parent->{$collection} ?: []); + $key = \count($parent->{$collection} ?? []); $parent->{$collection}[$key] = self::createChild($parent, $class, $properties); return $key; @@ -288,7 +306,11 @@ public static function createCollectionItem(OA\AbstractAnnotation $parent, $coll /** * Create a new Object of $class with members $properties and set the context parent to be $parent. * - * @param string $class + * @template T of OA\AbstractAnnotation + * + * @param class-string $class + * + * @return T * * @throws \InvalidArgumentException at an attempt to pass in properties that are found in $parent::$_nested */ @@ -296,7 +318,7 @@ public static function createChild(OA\AbstractAnnotation $parent, $class, array { $nesting = self::getNestingIndexes($class); - if (!empty(array_intersect(array_keys($properties), $nesting))) { + if ([] !== array_intersect(array_keys($properties), $nesting)) { throw new \InvalidArgumentException('Nesting Annotations is not supported.'); } @@ -426,7 +448,8 @@ private static function mergeFromArray(OA\AbstractAnnotation $annotation, array $annotation->x = []; } - $annotation->x = [$propertyName => $value] + ($annotation->x ?: []); + $annotation->x = [$propertyName => $value] + $annotation->x; + continue; } diff --git a/src/Processor/MapRequestPayloadProcessor.php b/src/Processor/MapRequestPayloadProcessor.php index 396982e87..ea86e9355 100644 --- a/src/Processor/MapRequestPayloadProcessor.php +++ b/src/Processor/MapRequestPayloadProcessor.php @@ -50,10 +50,10 @@ public function __invoke(Analysis $analysis) throw new \LogicException(sprintf('Operation "%s" does not contain attribute of "%s', $operation->operationId, MapRequestPayload::class)); } - $modelRef = $operation->_context->{SymfonyMapRequestPayloadDescriber::CONTEXT_MODEL_REF}; - if (!isset($modelRef)) { + if (!isset($operation->_context->{SymfonyMapRequestPayloadDescriber::CONTEXT_MODEL_REF})) { throw new \LogicException(sprintf('MapRequestPayload Model reference not found for operation "%s"', $operation->operationId)); } + $modelRef = $operation->_context->{SymfonyMapRequestPayloadDescriber::CONTEXT_MODEL_REF}; /** @var OA\RequestBody $requestBody */ $requestBody = Util::getChild($operation, OA\RequestBody::class); diff --git a/src/Processor/NullablePropertyProcessor.php b/src/Processor/NullablePropertyProcessor.php index 038393c78..cf3db55b4 100644 --- a/src/Processor/NullablePropertyProcessor.php +++ b/src/Processor/NullablePropertyProcessor.php @@ -41,7 +41,7 @@ public function __invoke(Analysis $analysis): void if (Generator::UNDEFINED !== $property->nullable) { if (!$property->nullable) { // if already false mark it as undefined (so it does not show up as `nullable: false`) - $property->nullable = Generator::UNDEFINED; + $property->nullable = Generator::UNDEFINED; /* @phpstan-ignore-line */ } } } diff --git a/src/PropertyDescriber/ArrayPropertyDescriber.php b/src/PropertyDescriber/ArrayPropertyDescriber.php index 201726916..0b1287073 100644 --- a/src/PropertyDescriber/ArrayPropertyDescriber.php +++ b/src/PropertyDescriber/ArrayPropertyDescriber.php @@ -31,7 +31,7 @@ public function describe(array $types, OA\Schema $property, ?array $groups = nul foreach ($types[0]->getCollectionValueTypes() as $type) { // Handle list pseudo type // https://symfony.com/doc/current/components/property_info.html#type-getcollectionkeytypes-type-getcollectionvaluetypes - if ($this->supports([$type]) && empty($type->getCollectionValueTypes())) { + if ($this->supports([$type]) && [] === $type->getCollectionValueTypes()) { continue; } @@ -45,7 +45,7 @@ public function supports(array $types): bool return false; } - if (empty($types[0]->getCollectionKeyTypes())) { + if ([] === $types[0]->getCollectionKeyTypes()) { return true; } diff --git a/src/PropertyDescriber/ObjectPropertyDescriber.php b/src/PropertyDescriber/ObjectPropertyDescriber.php index d1ccb2e81..7f065b378 100644 --- a/src/PropertyDescriber/ObjectPropertyDescriber.php +++ b/src/PropertyDescriber/ObjectPropertyDescriber.php @@ -29,11 +29,8 @@ public function describe(array $types, OA\Schema $property, ?array $groups = nul false, $types[0]->getClassName(), $types[0]->isCollection(), - // BC layer for symfony < 5.3 - method_exists($types[0], 'getCollectionKeyTypes') ? $types[0]->getCollectionKeyTypes() : $types[0]->getCollectionKeyType(), - method_exists($types[0], 'getCollectionValueTypes') ? - ($types[0]->getCollectionValueTypes()[0] ?? null) : - $types[0]->getCollectionValueType() + $types[0]->getCollectionKeyTypes(), + $types[0]->getCollectionValueTypes()[0] ?? null, ); // ignore nullable field if ($types[0]->isNullable()) { diff --git a/src/PropertyDescriber/PropertyDescriber.php b/src/PropertyDescriber/PropertyDescriber.php index 76e7ca8e8..7d707c15a 100644 --- a/src/PropertyDescriber/PropertyDescriber.php +++ b/src/PropertyDescriber/PropertyDescriber.php @@ -35,7 +35,7 @@ public function __construct( public function describe(array $types, OA\Schema $property, ?array $groups = null, ?OA\Schema $schema = null, array $context = []): void { - if (!$propertyDescriber = $this->getPropertyDescriber($types)) { + if (null === $propertyDescriber = $this->getPropertyDescriber($types)) { return; } diff --git a/src/Render/RenderOpenApi.php b/src/Render/RenderOpenApi.php index 57b58b762..12a2d64c4 100644 --- a/src/Render/RenderOpenApi.php +++ b/src/Render/RenderOpenApi.php @@ -62,7 +62,7 @@ public function renderFromRequest(Request $request, string $format, $area, array } /** - * @throws InvalidArgumentException If the area to dump is not valid + * @throws \InvalidArgumentException If the area to dump is not valid */ public function render(string $format, string $area, array $options = []): string { diff --git a/src/RouteDescriber/RouteArgumentDescriber.php b/src/RouteDescriber/RouteArgumentDescriber.php index 86dbeb8c5..14bea9077 100644 --- a/src/RouteDescriber/RouteArgumentDescriber.php +++ b/src/RouteDescriber/RouteArgumentDescriber.php @@ -44,7 +44,7 @@ public function describe(OA\OpenApi $api, Route $route, \ReflectionMethod $refle return; } - if (!$argumentMetaDataList) { + if ([] === $argumentMetaDataList) { return; } diff --git a/src/RouteDescriber/RouteArgumentDescriber/SymfonyMapQueryParameterDescriber.php b/src/RouteDescriber/RouteArgumentDescriber/SymfonyMapQueryParameterDescriber.php index 5a22f7493..137bca56c 100644 --- a/src/RouteDescriber/RouteArgumentDescriber/SymfonyMapQueryParameterDescriber.php +++ b/src/RouteDescriber/RouteArgumentDescriber/SymfonyMapQueryParameterDescriber.php @@ -26,7 +26,6 @@ final class SymfonyMapQueryParameterDescriber implements RouteArgumentDescriberI public function describe(ArgumentMetadata $argumentMetadata, OA\Operation $operation): void { - /** @var MapQueryParameter $attribute */ if (!$attribute = $argumentMetadata->getAttributes(MapQueryParameter::class, ArgumentMetadata::IS_INSTANCEOF)[0] ?? null) { return; } diff --git a/src/RouteDescriber/RouteArgumentDescriber/SymfonyMapQueryStringDescriber.php b/src/RouteDescriber/RouteArgumentDescriber/SymfonyMapQueryStringDescriber.php index e6147e138..32e1956be 100644 --- a/src/RouteDescriber/RouteArgumentDescriber/SymfonyMapQueryStringDescriber.php +++ b/src/RouteDescriber/RouteArgumentDescriber/SymfonyMapQueryStringDescriber.php @@ -32,7 +32,6 @@ final class SymfonyMapQueryStringDescriber implements RouteArgumentDescriberInte public function describe(ArgumentMetadata $argumentMetadata, OA\Operation $operation): void { - /** @var MapQueryString $attribute */ if (!$attribute = $argumentMetadata->getAttributes(MapQueryString::class, ArgumentMetadata::IS_INSTANCEOF)[0] ?? null) { return; } @@ -60,10 +59,6 @@ public function describe(ArgumentMetadata $argumentMetadata, OA\Operation $opera */ private function getGroups(MapQueryString $attribute): ?array { - if (null === $attribute->validationGroups) { - return null; - } - if (is_string($attribute->validationGroups)) { return [$attribute->validationGroups]; } diff --git a/src/RouteDescriber/RouteArgumentDescriber/SymfonyMapRequestPayloadDescriber.php b/src/RouteDescriber/RouteArgumentDescriber/SymfonyMapRequestPayloadDescriber.php index 283222b14..5969960f5 100644 --- a/src/RouteDescriber/RouteArgumentDescriber/SymfonyMapRequestPayloadDescriber.php +++ b/src/RouteDescriber/RouteArgumentDescriber/SymfonyMapRequestPayloadDescriber.php @@ -31,7 +31,6 @@ final class SymfonyMapRequestPayloadDescriber implements RouteArgumentDescriberI public function describe(ArgumentMetadata $argumentMetadata, OA\Operation $operation): void { - /** @var MapRequestPayload $attribute */ if (!$attribute = $argumentMetadata->getAttributes(MapRequestPayload::class, ArgumentMetadata::IS_INSTANCEOF)[0] ?? null) { return; } @@ -51,10 +50,6 @@ public function describe(ArgumentMetadata $argumentMetadata, OA\Operation $opera */ private function getGroups(MapRequestPayload $attribute): ?array { - if (null === $attribute->validationGroups) { - return null; - } - if (is_string($attribute->validationGroups)) { return [$attribute->validationGroups]; } diff --git a/src/RouteDescriber/RouteDescriberTrait.php b/src/RouteDescriber/RouteDescriberTrait.php index 7788a5e45..66c9b35bb 100644 --- a/src/RouteDescriber/RouteDescriberTrait.php +++ b/src/RouteDescriber/RouteDescriberTrait.php @@ -27,10 +27,16 @@ private function getOperations(OpenApi $api, Route $route): array { $operations = []; $path = Util::getPath($api, $this->normalizePath($route->getPath())); - $methods = $route->getMethods() ?: Util::OPERATIONS; + $methods = $route->getMethods(); + + // an empty array means that any method is allowed + if ([] === $methods) { + $methods = Util::OPERATIONS; + } + foreach ($methods as $method) { $method = strtolower($method); - if (!in_array($method, Util::OPERATIONS)) { + if (!in_array($method, Util::OPERATIONS, true)) { continue; } diff --git a/src/RouteDescriber/RouteMetadataDescriber.php b/src/RouteDescriber/RouteMetadataDescriber.php index 632a26aa6..96bb6e278 100644 --- a/src/RouteDescriber/RouteMetadataDescriber.php +++ b/src/RouteDescriber/RouteMetadataDescriber.php @@ -62,7 +62,7 @@ public function describe(OA\OpenApi $api, Route $route, \ReflectionMethod $refle if (isset($requirements[$pathVariable])) { $req = $requirements[$pathVariable]; $enumValues = $this->getPossibleEnumValues($req); - if ($enumValues && Generator::UNDEFINED === $parameter->schema->pattern) { + if ([] !== $enumValues && Generator::UNDEFINED === $parameter->schema->pattern) { $parameter->schema->enum = $enumValues; } // add the pattern anyway diff --git a/src/Routing/FilteredRouteCollectionBuilder.php b/src/Routing/FilteredRouteCollectionBuilder.php index b7343b11f..eef2dc4a9 100644 --- a/src/Routing/FilteredRouteCollectionBuilder.php +++ b/src/Routing/FilteredRouteCollectionBuilder.php @@ -171,7 +171,7 @@ private function defaultRouteDisabled(Route $route): bool ? $this->annotationReader->getMethodAnnotations($method) : []; - if (method_exists(\ReflectionMethod::class, 'getAttributes')) { + if (\PHP_VERSION_ID >= 80100) { $annotations = array_merge($annotations, array_map(function (\ReflectionAttribute $attribute) { return $attribute->newInstance(); }, $method->getAttributes(AbstractAnnotation::class, \ReflectionAttribute::IS_INSTANCEOF))); diff --git a/src/Util/ControllerReflector.php b/src/Util/ControllerReflector.php index 8d221734b..b63ea72c1 100644 --- a/src/Util/ControllerReflector.php +++ b/src/Util/ControllerReflector.php @@ -11,9 +11,7 @@ namespace Nelmio\ApiDocBundle\Util; -use Symfony\Bundle\FrameworkBundle\Controller\ControllerNameParser; use Symfony\Component\DependencyInjection\ContainerInterface; -use Symfony\Component\HttpKernel\Kernel; /** * @internal @@ -22,25 +20,17 @@ class ControllerReflector { private $container; - private $controllerNameParser; - private $controllers = []; public function __construct(ContainerInterface $container) { $this->container = $container; - - if (1 < \func_num_args() && func_get_arg(1) instanceof ControllerNameParser) { - $this->controllerNameParser = func_get_arg(1); - } } /** * Returns the ReflectionMethod for the given controller string. - * - * @return \ReflectionMethod|null */ - public function getReflectionMethod($controller) + public function getReflectionMethod($controller): ?\ReflectionMethod { if (is_string($controller)) { $controller = $this->getClassAndMethod($controller); @@ -50,82 +40,43 @@ public function getReflectionMethod($controller) return null; } - return $this->geReflectionMethodByClassNameAndMethodName(...$controller); + return $this->getReflectionMethodByClassNameAndMethodName(...$controller); } - /** - * @return \ReflectionMethod|null - */ - public function geReflectionMethodByClassNameAndMethodName(string $class, string $method) + private function getReflectionMethodByClassNameAndMethodName(string $class, string $method): ?\ReflectionMethod { try { return new \ReflectionMethod($class, $method); } catch (\ReflectionException $e) { - // In case we can't reflect the controller, we just - // ignore the route + // In case we can't reflect the controller, we just ignore the route } return null; } - private function getClassAndMethod(string $controller) + private function getClassAndMethod(string $controller): ?array { if (isset($this->controllers[$controller])) { return $this->controllers[$controller]; } - if ($this->controllerNameParser && false === strpos($controller, '::') && 2 === substr_count($controller, ':')) { - $deprecatedNotation = $controller; - - try { - $controller = $this->controllerNameParser->parse($controller); - - trigger_deprecation('nelmio/api-doc-bundle', '3.6', 'Referencing controllers with %s is deprecated since Symfony 4.1, use "%s" instead.', $deprecatedNotation, $controller); - } catch (\InvalidArgumentException $e) { - // unable to optimize unknown notation - } - } - if (preg_match('#(.+)::([\w]+)#', $controller, $matches)) { $class = $matches[1]; $method = $matches[2]; - // Since symfony 4.1 routes are defined like service_id::method_name - if (Kernel::VERSION_ID >= 40100 && !class_exists($class)) { - if ($this->container->has($class)) { - $class = get_class($this->container->get($class)); - if (class_exists(ClassUtils::class)) { - $class = ClassUtils::getRealClass($class); - } - } - } - } elseif (class_exists($controller)) { - $class = $controller; - $method = '__invoke'; - } else { - // Has to be removed when dropping support of symfony < 4.1 - if (preg_match('#(.+):([\w]+)#', $controller, $matches)) { - $controller = $matches[1]; - $method = $matches[2]; - } - if ($this->container->has($controller)) { - $class = get_class($this->container->get($controller)); - if (class_exists(ClassUtils::class)) { - $class = ClassUtils::getRealClass($class); - } - - if (!isset($method) && method_exists($class, '__invoke')) { - $method = '__invoke'; - } + if (!class_exists($class) && $this->container->has($class)) { + $class = get_class($this->container->get($class)); } - } - if (!isset($class) || !isset($method)) { - $this->controllers[$controller] = null; + return $this->controllers[$controller] = [$class, $method]; + } - return null; + if (class_exists($controller)) { + return $this->controllers[$controller] = [$controller, '__invoke']; } - return $this->controllers[$controller] = [$class, $method]; + $this->controllers[$controller] = null; + + return null; } } diff --git a/tests/ApiDocGeneratorTest.php b/tests/ApiDocGeneratorTest.php index 36853fadb..02b0bd3fb 100644 --- a/tests/ApiDocGeneratorTest.php +++ b/tests/ApiDocGeneratorTest.php @@ -24,7 +24,7 @@ public function testCache() $adapter = new ArrayAdapter(); $generator = new ApiDocGenerator([new DefaultDescriber()], [], $adapter, null, new Generator()); - $this->assertEquals(json_encode($generator->generate()), json_encode($adapter->getItem('openapi_doc')->get())); + self::assertEquals(json_encode($generator->generate()), json_encode($adapter->getItem('openapi_doc')->get())); } public function testCacheWithCustomId() @@ -32,6 +32,6 @@ public function testCacheWithCustomId() $adapter = new ArrayAdapter(); $generator = new ApiDocGenerator([new DefaultDescriber()], [], $adapter, 'custom_id', new Generator()); - $this->assertEquals(json_encode($generator->generate()), json_encode($adapter->getItem('custom_id')->get())); + self::assertEquals(json_encode($generator->generate()), json_encode($adapter->getItem('custom_id')->get())); } } diff --git a/tests/Command/DumpCommandTest.php b/tests/Command/DumpCommandTest.php index 25be7c37f..e6a4f490e 100644 --- a/tests/Command/DumpCommandTest.php +++ b/tests/Command/DumpCommandTest.php @@ -24,7 +24,7 @@ public function testJson(array $jsonOptions, int $expectedJsonFlags) $output = $this->executeDumpCommand($jsonOptions + [ '--area' => 'test', ]); - $this->assertEquals( + self::assertEquals( json_encode($this->getOpenApiDefinition('test'), $expectedJsonFlags)."\n", $output ); diff --git a/tests/DependencyInjection/ConfigurationTest.php b/tests/DependencyInjection/ConfigurationTest.php index e5619224c..bb042df56 100644 --- a/tests/DependencyInjection/ConfigurationTest.php +++ b/tests/DependencyInjection/ConfigurationTest.php @@ -22,7 +22,7 @@ public function testDefaultArea() $processor = new Processor(); $config = $processor->processConfiguration(new Configuration(), [['areas' => ['path_patterns' => ['/foo']]]]); - $this->assertSame( + self::assertSame( [ 'default' => [ 'path_patterns' => ['/foo'], @@ -67,7 +67,7 @@ public function testAreas() ], ]]]); - $this->assertSame($areas, $config['areas']); + self::assertSame($areas, $config['areas']); } public function testAlternativeNames() @@ -109,7 +109,7 @@ public function testAlternativeNames() ], ], ]]); - $this->assertEquals([ + self::assertEquals([ [ 'alias' => 'Foo1', 'type' => 'App\Foo', diff --git a/tests/DependencyInjection/NelmioApiDocExtensionTest.php b/tests/DependencyInjection/NelmioApiDocExtensionTest.php index efea7ecb6..9b16b9afe 100644 --- a/tests/DependencyInjection/NelmioApiDocExtensionTest.php +++ b/tests/DependencyInjection/NelmioApiDocExtensionTest.php @@ -51,7 +51,7 @@ public function testNameAliasesArePassedToModelRegistry() $foundMethodCall = false; foreach ($methodCalls as $methodCall) { if ('setAlternativeNames' === $methodCall[0]) { - $this->assertEquals([ + self::assertEquals([ 'Foo1' => [ 'type' => 'App\\Foo', 'groups' => null, @@ -64,13 +64,13 @@ public function testNameAliasesArePassedToModelRegistry() $foundMethodCall = true; } } - $this->assertTrue($foundMethodCall); + self::assertTrue($foundMethodCall); $methodCalls = $container->getDefinition('nelmio_api_doc.generator.commercial')->getMethodCalls(); $foundMethodCall = false; foreach ($methodCalls as $methodCall) { if ('setAlternativeNames' === $methodCall[0]) { - $this->assertEquals([ + self::assertEquals([ 'Foo1' => [ 'type' => 'App\\Bar', 'groups' => null, @@ -83,7 +83,7 @@ public function testNameAliasesArePassedToModelRegistry() $foundMethodCall = true; } } - $this->assertTrue($foundMethodCall); + self::assertTrue($foundMethodCall); } public function testMergesRootKeysFromMultipleConfigurations() @@ -127,7 +127,7 @@ public function testMergesRootKeysFromMultipleConfigurations() ], ], $container); - $this->assertSame([ + self::assertSame([ 'info' => [ 'title' => 'API documentation', 'description' => 'This is the api documentation, use it wisely', @@ -165,25 +165,25 @@ public function testApiDocGeneratorWithCachePool(array $config, array $expectedV $reference = $container->getDefinition('nelmio_api_doc.generator.default')->getArgument(2); if (null === $expectedValues['defaultCachePool']) { - $this->assertNull($reference); + self::assertNull($reference); } else { - $this->assertInstanceOf(Reference::class, $reference); - $this->assertSame($expectedValues['defaultCachePool'], (string) $reference); + self::assertInstanceOf(Reference::class, $reference); + self::assertSame($expectedValues['defaultCachePool'], (string) $reference); } $reference = $container->getDefinition('nelmio_api_doc.generator.area1')->getArgument(2); if (null === $expectedValues['area1CachePool']) { - $this->assertNull($reference); + self::assertNull($reference); } else { - $this->assertInstanceOf(Reference::class, $reference); - $this->assertSame($expectedValues['area1CachePool'], (string) $reference); + self::assertInstanceOf(Reference::class, $reference); + self::assertSame($expectedValues['area1CachePool'], (string) $reference); } $cacheItemId = $container->getDefinition('nelmio_api_doc.generator.default')->getArgument(3); - $this->assertSame($expectedValues['defaultCacheItemId'], $cacheItemId); + self::assertSame($expectedValues['defaultCacheItemId'], $cacheItemId); $cacheItemId = $container->getDefinition('nelmio_api_doc.generator.area1')->getArgument(3); - $this->assertSame($expectedValues['area1CacheItemId'], $cacheItemId); + self::assertSame($expectedValues['area1CacheItemId'], $cacheItemId); } public static function provideCacheConfig(): iterable diff --git a/tests/Describer/ApiPlatformDescriberTest.php b/tests/Describer/ApiPlatformDescriberTest.php index 83f504ced..f18911e1e 100644 --- a/tests/Describer/ApiPlatformDescriberTest.php +++ b/tests/Describer/ApiPlatformDescriberTest.php @@ -26,24 +26,24 @@ class ApiPlatformDescriberTest extends AbstractDescriberTest public function testDescribe() { - $this->normalizer->expects($this->once()) + $this->normalizer->expects(self::once()) ->method('normalize') ->with($this->documentation) ->willReturn(['info' => ['title' => 'My Test App']]); $expectedApi = new OpenApi(['info' => ['title' => 'My Test App'], '_context' => new Context()]); - $this->assertEquals($expectedApi->toJson(), $this->getOpenApiDoc()->toJson()); + self::assertEquals($expectedApi->toJson(), $this->getOpenApiDoc()->toJson()); } public function testDescribeRemovesBasePathAfterNormalization() { - $this->normalizer->expects($this->once()) + $this->normalizer->expects(self::once()) ->method('normalize') ->with($this->documentation) ->willReturn(['info' => ['title' => 'My Test App'], 'basePath' => '/foo']); $expectedApi = new OpenApi(['info' => ['title' => 'My Test App'], '_context' => new Context()]); - $this->assertEquals($expectedApi->toJson(), $this->getOpenApiDoc()->toJson()); + self::assertEquals($expectedApi->toJson(), $this->getOpenApiDoc()->toJson()); } protected function setUp(): void @@ -51,7 +51,7 @@ protected function setUp(): void $this->documentation = new Documentation(new ResourceNameCollection(['dummy' => 'dummy'])); $this->normalizer = $this->createMock(NormalizerInterface::class); - $this->normalizer->expects($this->once()) + $this->normalizer->expects(self::once()) ->method('supportsNormalization') ->willReturn(true); diff --git a/tests/Describer/RouteDescriberTest.php b/tests/Describer/RouteDescriberTest.php index ab86536ad..60e514fdc 100644 --- a/tests/Describer/RouteDescriberTest.php +++ b/tests/Describer/RouteDescriberTest.php @@ -16,7 +16,6 @@ use Nelmio\ApiDocBundle\Util\ControllerReflector; use OpenApi\Annotations\OpenApi; use OpenApi\Context; -use Symfony\Bundle\FrameworkBundle\Controller\ControllerNameParser; use Symfony\Component\DependencyInjection\Container; use Symfony\Component\Routing\Route; use Symfony\Component\Routing\RouteCollection; @@ -30,10 +29,10 @@ class RouteDescriberTest extends AbstractDescriberTest public function testIgnoreWhenNoController() { $this->routes->add('foo', new Route('foo')); - $this->routeDescriber->expects($this->never()) + $this->routeDescriber->expects(self::never()) ->method('describe'); - $this->assertEquals((new OpenApi(['_context' => new Context()]))->toJson(), $this->getOpenApiDoc()->toJson()); + self::assertEquals((new OpenApi(['_context' => new Context()]))->toJson(), $this->getOpenApiDoc()->toJson()); } protected function setUp(): void @@ -42,20 +41,8 @@ protected function setUp(): void $this->routes = new RouteCollection(); $this->describer = new RouteDescriber( $this->routes, - $this->createControllerReflector(), + new ControllerReflector(new Container()), [$this->routeDescriber] ); } - - protected function createControllerReflector(): ControllerReflector - { - if (class_exists(ControllerNameParser::class)) { - return new ControllerReflector( - new Container(), - $this->createMock(ControllerNameParser::class) - ); - } - - return new ControllerReflector(new Container()); - } } diff --git a/tests/Functional/BazingaFunctionalTest.php b/tests/Functional/BazingaFunctionalTest.php index 0687782e8..82044457f 100644 --- a/tests/Functional/BazingaFunctionalTest.php +++ b/tests/Functional/BazingaFunctionalTest.php @@ -23,7 +23,7 @@ class BazingaFunctionalTest extends WebTestCase protected function setUp(): void { if (Kernel::MAJOR_VERSION >= 7) { - $this->markTestSkipped('Not supported in symfony 7'); + self::markTestSkipped('Not supported in symfony 7'); } parent::setUp(); @@ -33,7 +33,7 @@ protected function setUp(): void $metaDataFactory = self::getContainer()->get('hateoas.configuration.metadata_factory'); if (!$metaDataFactory instanceof MetadataFactory) { - $this->fail('The hateoas.metadata_factory service is not an instance of MetadataFactory'); + self::fail('The hateoas.metadata_factory service is not an instance of MetadataFactory'); } // Reusing the cache from previous tests causes relations metadata to be lost, so we need to clear it @@ -42,7 +42,7 @@ protected function setUp(): void public function testModelComplexDocumentationBazinga() { - $this->assertEquals([ + self::assertEquals([ 'type' => 'object', 'properties' => [ '_links' => [ @@ -96,7 +96,7 @@ public function testModelComplexDocumentationBazinga() public function testWithGroup() { - $this->assertEquals([ + self::assertEquals([ 'type' => 'object', 'properties' => [ '_embedded' => [ @@ -114,12 +114,11 @@ public function testWithGroup() public function testWithType() { - try { - new \ReflectionMethod(Embedded::class, 'getType'); - } catch (\ReflectionException $e) { - $this->markTestSkipped('Typed embedded properties require at least willdurand/hateoas 3.0'); + if (!method_exists(Embedded::class, 'getType')) { + self::markTestSkipped('Typed embedded properties require at most willdurand/hateoas 3.0'); } - $this->assertEquals([ + + self::assertEquals([ 'type' => 'object', 'properties' => [ '_embedded' => [ @@ -143,6 +142,6 @@ public function testWithType() protected static function createKernel(array $options = []): KernelInterface { - return new TestKernel(TestKernel::USE_JMS | TestKernel::USE_BAZINGA); + return new TestKernel(TestKernel::USE_BAZINGA); } } diff --git a/tests/Functional/ControllerTest.php b/tests/Functional/ControllerTest.php index 4db420de4..96861abd4 100644 --- a/tests/Functional/ControllerTest.php +++ b/tests/Functional/ControllerTest.php @@ -56,7 +56,7 @@ public function testControllers(?array $controller, ?string $fixtureName = null, $controllerName = $controller['name'] ?? null; $controllerType = $controller['type'] ?? null; - $fixtureName = $fixtureName ?? $controllerName ?? $this->fail('A fixture name must be provided.'); + $fixtureName = $fixtureName ?? $controllerName ?? self::fail('A fixture name must be provided.'); $routingConfiguration = function (RoutingConfigurator $routes) use ($controllerName, $controllerType) { if (null === $controllerName) { diff --git a/tests/Functional/CsrfProtectionFunctionalTest.php b/tests/Functional/CsrfProtectionFunctionalTest.php index 55b978b78..58375b20a 100644 --- a/tests/Functional/CsrfProtectionFunctionalTest.php +++ b/tests/Functional/CsrfProtectionFunctionalTest.php @@ -30,9 +30,9 @@ public function testTokenPropertyExistsPerDefaultIfEnabledPerFrameworkConfig(): { // Make sure that test precondition is correct. $isCsrfFormExtensionEnabled = self::getContainer()->getParameter('form.type_extension.csrf.enabled'); - $this->assertTrue($isCsrfFormExtensionEnabled, 'The test needs the csrf form extension to be enabled.'); + self::assertTrue($isCsrfFormExtensionEnabled, 'The test needs the csrf form extension to be enabled.'); - $this->assertEquals([ + self::assertEquals([ 'type' => 'object', 'properties' => [ 'quz' => [ @@ -50,7 +50,7 @@ public function testTokenPropertyExistsPerDefaultIfEnabledPerFrameworkConfig(): public function testTokenPropertyExistsIfCsrfProtectionIsEnabled(): void { - $this->assertEquals([ + self::assertEquals([ 'type' => 'object', 'properties' => [ 'name' => [ @@ -68,7 +68,7 @@ public function testTokenPropertyExistsIfCsrfProtectionIsEnabled(): void public function testTokenPropertyNotExistsIfCsrfProtectionIsDisabled(): void { - $this->assertEquals([ + self::assertEquals([ 'type' => 'object', 'properties' => [ 'name' => [ diff --git a/tests/Functional/Entity/JMSNamingStrategyConstraints80.php b/tests/Functional/Entity/JMSNamingStrategyConstraints80.php index d0d24b90f..e9eb9fe83 100644 --- a/tests/Functional/Entity/JMSNamingStrategyConstraints80.php +++ b/tests/Functional/Entity/JMSNamingStrategyConstraints80.php @@ -27,7 +27,7 @@ class JMSNamingStrategyConstraints80 * * @Assert\Regex(pattern="\w+") * - * @Assert\Length(min="3", max="10") + * @Assert\Length(min=3, max=10) */ private $some_weird_named_property = 'default'; diff --git a/tests/Functional/Entity/JMSNamingStrategyConstraints81.php b/tests/Functional/Entity/JMSNamingStrategyConstraints81.php index 5184778a0..bea65b743 100644 --- a/tests/Functional/Entity/JMSNamingStrategyConstraints81.php +++ b/tests/Functional/Entity/JMSNamingStrategyConstraints81.php @@ -23,7 +23,7 @@ class JMSNamingStrategyConstraints81 #[Serializer\SerializedName('beautifulName')] #[Assert\NotBlank()] #[Assert\Regex(pattern: '\w+')] - #[Assert\Length(min: '3', max: '10')] + #[Assert\Length(min: 3, max: 10)] private $some_weird_named_property = 'default'; public function getSomeWeirdNamedProperty(): string diff --git a/tests/Functional/Entity/SymfonyConstraints80.php b/tests/Functional/Entity/SymfonyConstraints80.php index a19184915..06170ee80 100644 --- a/tests/Functional/Entity/SymfonyConstraints80.php +++ b/tests/Functional/Entity/SymfonyConstraints80.php @@ -33,7 +33,7 @@ class SymfonyConstraints80 /** * @var int * - * @Assert\Length(min="0", max="50") + * @Assert\Length(min=0, max=50) */ private $propertyAssertLength; @@ -47,7 +47,7 @@ class SymfonyConstraints80 /** * @var int * - * @Assert\Count(min="0", max="10") + * @Assert\Count(min=0, max=10) */ private $propertyCount; @@ -172,7 +172,7 @@ public function setPropertyWithCompoundValidationRule(int $propertyWithCompoundV } /** - * @Assert\Count(min="0", max="10") + * @Assert\Count(min=0, max=10) */ public function setPropertyNotBlank(int $propertyNotBlank): void { diff --git a/tests/Functional/Entity/SymfonyConstraints81.php b/tests/Functional/Entity/SymfonyConstraints81.php index 4287b49a6..70ac95eba 100644 --- a/tests/Functional/Entity/SymfonyConstraints81.php +++ b/tests/Functional/Entity/SymfonyConstraints81.php @@ -31,7 +31,7 @@ class SymfonyConstraints81 /** * @var int */ - #[Assert\Length(min: '0', max: '50')] + #[Assert\Length(min: 0, max: 50)] private $propertyAssertLength; /** @@ -150,7 +150,7 @@ public function setPropertyWithCompoundValidationRule(int $propertyWithCompoundV $this->propertyWithCompoundValidationRule = $propertyWithCompoundValidationRule; } - #[Assert\Count(min: '0', max: '10')] + #[Assert\Count(min: 0, max: 10)] public function setPropertyNotBlank(int $propertyNotBlank): void { $this->propertyNotBlank = $propertyNotBlank; diff --git a/tests/Functional/FOSRestTest.php b/tests/Functional/FOSRestTest.php index 6ccbfa880..a2b4f6ffc 100644 --- a/tests/Functional/FOSRestTest.php +++ b/tests/Functional/FOSRestTest.php @@ -26,7 +26,7 @@ protected static function createKernel(array $options = []): KernelInterface protected function setUp(): void { if (Kernel::MAJOR_VERSION >= 7) { - $this->markTestSkipped('Not supported in symfony 7'); + self::markTestSkipped('Not supported in symfony 7'); } parent::setUp(); @@ -41,44 +41,44 @@ public function testFOSRestAction(string $route) { $operation = $this->getOperation($route, 'post'); - $this->assertHasParameter('foo', 'query', $operation); - $this->assertInstanceOf(OA\RequestBody::class, $operation->requestBody); + self::assertHasParameter('foo', 'query', $operation); + self::assertInstanceOf(OA\RequestBody::class, $operation->requestBody); $bodySchema = $operation->requestBody->content['application/json']->schema; - $this->assertHasProperty('bar', $bodySchema); - $this->assertHasProperty('baz', $bodySchema); + self::assertHasProperty('bar', $bodySchema); + self::assertHasProperty('baz', $bodySchema); $fooParameter = $this->getParameter($operation, 'foo', 'query'); - $this->assertInstanceOf(OA\Schema::class, $fooParameter->schema); - $this->assertEquals('\d+', $fooParameter->schema->pattern); - $this->assertEquals(Generator::UNDEFINED, $fooParameter->schema->format); + self::assertInstanceOf(OA\Schema::class, $fooParameter->schema); + self::assertEquals('\d+', $fooParameter->schema->pattern); + self::assertEquals(Generator::UNDEFINED, $fooParameter->schema->format); $mappedParameter = $this->getParameter($operation, 'mapped[]', 'query'); - $this->assertTrue($mappedParameter->explode); + self::assertTrue($mappedParameter->explode); $barProperty = $this->getProperty($bodySchema, 'bar'); - $this->assertEquals('\d+', $barProperty->pattern); - $this->assertEquals(Generator::UNDEFINED, $barProperty->format); + self::assertEquals('\d+', $barProperty->pattern); + self::assertEquals(Generator::UNDEFINED, $barProperty->format); $bazProperty = $this->getProperty($bodySchema, 'baz'); - $this->assertEquals(Generator::UNDEFINED, $bazProperty->pattern); - $this->assertEquals('IsTrue', $bazProperty->format); + self::assertEquals(Generator::UNDEFINED, $bazProperty->pattern); + self::assertEquals('IsTrue', $bazProperty->format); $dateTimeProperty = $this->getProperty($bodySchema, 'datetime'); - $this->assertEquals('date-time', $dateTimeProperty->format); + self::assertEquals('date-time', $dateTimeProperty->format); $dateTimeAltProperty = $this->getProperty($bodySchema, 'datetimeAlt'); - $this->assertEquals('date-time', $dateTimeAltProperty->format); + self::assertEquals('date-time', $dateTimeAltProperty->format); $dateTimeNoFormatProperty = $this->getProperty($bodySchema, 'datetimeNoFormat'); - $this->assertEquals(Generator::UNDEFINED, $dateTimeNoFormatProperty->format); + self::assertEquals(Generator::UNDEFINED, $dateTimeNoFormatProperty->format); $dateProperty = $this->getProperty($bodySchema, 'date'); - $this->assertEquals('date', $dateProperty->format); + self::assertEquals('date', $dateProperty->format); // The _format path attribute should be removed - $this->assertNotHasParameter('_format', 'path', $operation); + self::assertNotHasParameter('_format', 'path', $operation); } public function provideRoute(): iterable diff --git a/tests/Functional/FunctionalTest.php b/tests/Functional/FunctionalTest.php index c16e1e858..5fcf62777 100644 --- a/tests/Functional/FunctionalTest.php +++ b/tests/Functional/FunctionalTest.php @@ -31,9 +31,9 @@ protected function setUp(): void public function testConfiguredDocumentation() { - $this->assertEquals('My Default App', $this->getOpenApiDefinition()->info->title); - $this->assertEquals(['buildHash' => 'ab1234567890'], $this->getOpenApiDefinition()->info->x); - $this->assertEquals('My Test App', $this->getOpenApiDefinition('test')->info->title); + self::assertEquals('My Default App', $this->getOpenApiDefinition()->info->title); + self::assertEquals(['buildHash' => 'ab1234567890'], $this->getOpenApiDefinition()->info->x); + self::assertEquals('My Test App', $this->getOpenApiDefinition('test')->info->title); } public function testUndocumentedAction() @@ -53,13 +53,13 @@ public function testFetchArticleAction(string $articleRoute) $this->assertHasResponse('200', $operation); $response = $this->getOperationResponse($operation, '200'); - $this->assertEquals('#/components/schemas/Article', $response->content['application/json']->schema->ref); + self::assertEquals('#/components/schemas/Article', $response->content['application/json']->schema->ref); // Ensure that groups are supported $articleModel = $this->getModel('Article'); - $this->assertCount(1, $articleModel->properties); + self::assertCount(1, $articleModel->properties); $this->assertHasProperty('author', $articleModel); - $this->assertSame('#/components/schemas/User2', Util::getProperty($articleModel, 'author')->ref); + self::assertSame('#/components/schemas/User2', Util::getProperty($articleModel, 'author')->ref); $this->assertNotHasProperty('author', Util::getProperty($articleModel, 'author')); } @@ -92,7 +92,7 @@ public function testSwaggerAction(string $path) $this->assertHasResponse('201', $operation); $response = $this->getOperationResponse($operation, '201'); - $this->assertEquals('An example resource', $response->description); + self::assertEquals('An example resource', $response->description); } public function swaggerActionPathsProvider() @@ -103,7 +103,7 @@ public function swaggerActionPathsProvider() public function testAnnotationWithManualPath() { $path = $this->getPath('/api/swagger2'); - $this->assertSame(Generator::UNDEFINED, $path->post); + self::assertSame(Generator::UNDEFINED, $path->post); $operation = $this->getOperation('/api/swagger', 'get'); $this->assertNotHasParameter('Accept-Version', 'header', $operation); @@ -119,18 +119,18 @@ public function testImplicitSwaggerAction(string $method) { $operation = $this->getOperation('/api/swagger/implicit', $method); - $this->assertEquals(['implicit'], $operation->tags); + self::assertEquals(['implicit'], $operation->tags); $this->assertHasResponse('201', $operation); $response = $this->getOperationResponse($operation, '201'); - $this->assertEquals('Operation automatically detected', $response->description); - $this->assertEquals('#/components/schemas/User', $response->content['application/json']->schema->ref); + self::assertEquals('Operation automatically detected', $response->description); + self::assertEquals('#/components/schemas/User', $response->content['application/json']->schema->ref); - $this->assertInstanceOf(OAAnnotations\RequestBody::class, $operation->requestBody); + self::assertInstanceOf(OAAnnotations\RequestBody::class, $operation->requestBody); $requestBody = $operation->requestBody; - $this->assertEquals('This is a request body', $requestBody->description); - $this->assertEquals('array', $requestBody->content['application/json']->schema->type); - $this->assertEquals('#/components/schemas/User', $requestBody->content['application/json']->schema->items->ref); + self::assertEquals('This is a request body', $requestBody->description); + self::assertEquals('array', $requestBody->content['application/json']->schema->type); + self::assertEquals('#/components/schemas/User', $requestBody->content['application/json']->schema->items->ref); } public function implicitSwaggerActionMethodsProvider() @@ -142,27 +142,27 @@ public function testUserAction() { $operation = $this->getOperation('/api/test/{user}', 'get'); - $this->assertEquals(Generator::UNDEFINED, $operation->security); - $this->assertEquals(Generator::UNDEFINED, $operation->summary); - $this->assertEquals(Generator::UNDEFINED, $operation->description); - $this->assertEquals(Generator::UNDEFINED, $operation->deprecated); + self::assertEquals(Generator::UNDEFINED, $operation->security); + self::assertEquals(Generator::UNDEFINED, $operation->summary); + self::assertEquals(Generator::UNDEFINED, $operation->description); + self::assertEquals(Generator::UNDEFINED, $operation->deprecated); $this->assertHasResponse(200, $operation); $this->assertHasParameter('user', 'path', $operation); $parameter = Util::getOperationParameter($operation, 'user', 'path'); - $this->assertTrue($parameter->required); - $this->assertEquals('string', $parameter->schema->type); - $this->assertEquals('/foo/', $parameter->schema->pattern); - $this->assertEquals(Generator::UNDEFINED, $parameter->schema->format); + self::assertTrue($parameter->required); + self::assertEquals('string', $parameter->schema->type); + self::assertEquals('/foo/', $parameter->schema->pattern); + self::assertEquals(Generator::UNDEFINED, $parameter->schema->format); } public function testDeprecatedAction() { $operation = $this->getOperation('/api/deprecated', 'get'); - $this->assertEquals('This action is deprecated.', $operation->summary); - $this->assertEquals('Please do not use this action.', $operation->description); - $this->assertTrue($operation->deprecated); + self::assertEquals('This action is deprecated.', $operation->summary); + self::assertEquals('Please do not use this action.', $operation->description); + self::assertTrue($operation->deprecated); } public function testApiPlatform() @@ -175,7 +175,7 @@ public function testApiPlatform() public function testUserModel() { - $this->assertEquals( + self::assertEquals( [ 'type' => 'object', 'properties' => [ @@ -261,7 +261,7 @@ public function testUserModel() public function testFormSupport() { - $this->assertEquals([ + self::assertEquals([ 'type' => 'object', 'description' => 'this is the description of an user', 'properties' => [ @@ -311,7 +311,7 @@ public function testFormSupport() 'schema' => 'UserType', ], json_decode($this->getModel('UserType')->toJson(), true)); - $this->assertEquals([ + self::assertEquals([ 'type' => 'object', 'properties' => [ 'bar' => [ @@ -357,7 +357,7 @@ public function testFormSupport() 'schema' => 'DummyType', ], json_decode($this->getModel('DummyType')->toJson(), true)); - $this->assertEquals([ + self::assertEquals([ 'type' => 'object', 'properties' => [ 'quz' => [ @@ -381,7 +381,7 @@ public function testSecurityAction(string $route) ['basic' => []], ['oauth2' => ['scope_1']], ]; - $this->assertEquals($expected, $operation->security); + self::assertEquals($expected, $operation->security); } public function provideSecurityRoute(): iterable @@ -399,7 +399,7 @@ public function provideSecurityRoute(): iterable public function testSecurityOverrideAction(string $route) { $operation = $this->getOperation($route, 'get'); - $this->assertEquals([], $operation->security); + self::assertEquals([], $operation->security); } public function provideSecurityOverrideRoute(): iterable @@ -414,14 +414,14 @@ public function provideSecurityOverrideRoute(): iterable public function testInlinePHP81Parameters() { if (\PHP_VERSION_ID < 80100) { - $this->markTestSkipped('Attributes require PHP 8.1'); + self::markTestSkipped('Attributes require PHP 8.1'); } $operation = $this->getOperation('/api/inline_path_parameters', 'get'); - $this->assertCount(1, $operation->parameters); - $this->assertInstanceOf(OAAttributes\PathParameter::class, $operation->parameters[0]); - $this->assertSame($operation->parameters[0]->name, 'product_id'); - $this->assertSame($operation->parameters[0]->schema->type, 'string'); + self::assertCount(1, $operation->parameters); + self::assertInstanceOf(OAAttributes\PathParameter::class, $operation->parameters[0]); + self::assertSame($operation->parameters[0]->name, 'product_id'); + self::assertSame($operation->parameters[0]->schema->type, 'string'); } public function testClassSecurityAction() @@ -431,7 +431,7 @@ public function testClassSecurityAction() $expected = [ ['basic' => []], ]; - $this->assertEquals($expected, $operation->security); + self::assertEquals($expected, $operation->security); } public function testSymfonyConstraintDocumentation() @@ -572,25 +572,25 @@ public function testSymfonyConstraintDocumentation() ]; } - $this->assertEquals($expected, json_decode($this->getModel($modelName)->toJson(), true)); + self::assertEquals($expected, json_decode($this->getModel($modelName)->toJson(), true)); } public function testConfigReference() { $operation = $this->getOperation('/api/configReference', 'get'); - $this->assertEquals('#/components/schemas/Test', $this->getOperationResponse($operation, '200')->ref); - $this->assertEquals('#/components/responses/201', $this->getOperationResponse($operation, '201')->ref); + self::assertEquals('#/components/schemas/Test', $this->getOperationResponse($operation, '200')->ref); + self::assertEquals('#/components/responses/201', $this->getOperationResponse($operation, '201')->ref); } public function testOperationsWithOtherAnnotationsAction() { $getOperation = $this->getOperation('/api/multi-annotations', 'get'); - $this->assertSame('This is the get operation', $getOperation->description); - $this->assertSame('Worked well!', $this->getOperationResponse($getOperation, 200)->description); + self::assertSame('This is the get operation', $getOperation->description); + self::assertSame('Worked well!', $this->getOperationResponse($getOperation, 200)->description); $postOperation = $this->getOperation('/api/multi-annotations', 'post'); - $this->assertSame('This is post', $postOperation->description); - $this->assertSame('Worked well!', $this->getOperationResponse($postOperation, 200)->description); + self::assertSame('This is post', $postOperation->description); + self::assertSame('Worked well!', $this->getOperationResponse($postOperation, 200)->description); } public function testNoDuplicatedParameters() @@ -602,7 +602,7 @@ public function testNoDuplicatedParameters() public function testSerializedNameAction() { if (!class_exists(SerializedName::class)) { - $this->markTestSkipped('Annotation @SerializedName doesn\'t exist.'); + self::markTestSkipped('Annotation @SerializedName doesn\'t exist.'); } if (TestKernel::isAttributesAvailable()) { @@ -611,7 +611,7 @@ public function testSerializedNameAction() $model = $this->getModel('SerializedNameEnt'); } - $this->assertCount(2, $model->properties); + self::assertCount(2, $model->properties); $this->assertNotHasProperty('foo', $model); $this->assertHasProperty('notfoo', $model); @@ -747,31 +747,31 @@ public function testCompoundEntityAction() public function testInvokableController() { $operation = $this->getOperation('/api/invoke', 'get'); - $this->assertSame('Invokable!', $this->getOperationResponse($operation, 200)->description); + self::assertSame('Invokable!', $this->getOperationResponse($operation, 200)->description); } public function testDefaultOperationId() { $operation = $this->getOperation('/api/article/{id}', 'get'); - $this->assertEquals('get_api_nelmio_apidoc_tests_functional_api_fetcharticle', $operation->operationId); + self::assertEquals('get_api_nelmio_apidoc_tests_functional_api_fetcharticle', $operation->operationId); } public function testNamedRouteOperationId() { $operation = $this->getOperation('/api/named_route-operation-id', 'get'); - $this->assertEquals('get_api_named_route_operation_id', $operation->operationId); + self::assertEquals('get_api_named_route_operation_id', $operation->operationId); $operation = $this->getOperation('/api/named_route-operation-id', 'post'); - $this->assertEquals('post_api_named_route_operation_id', $operation->operationId); + self::assertEquals('post_api_named_route_operation_id', $operation->operationId); } public function testCustomOperationId() { $operation = $this->getOperation('/api/custom-operation-id', 'get'); - $this->assertEquals('get-custom-operation-id', $operation->operationId); + self::assertEquals('get-custom-operation-id', $operation->operationId); $operation = $this->getOperation('/api/custom-operation-id', 'post'); - $this->assertEquals('post-custom-operation-id', $operation->operationId); + self::assertEquals('post-custom-operation-id', $operation->operationId); } /** @@ -782,7 +782,7 @@ public function testPrivateProtectedExposure() { // Ensure that groups are supported $model = $this->getModel('PrivateProtectedExposure'); - $this->assertCount(1, $model->properties); + self::assertCount(1, $model->properties); $this->assertHasProperty('publicField', $model); $this->assertNotHasProperty('privateField', $model); $this->assertNotHasProperty('protectedField', $model); @@ -797,26 +797,26 @@ public function testModelsWithDiscriminatorMapAreLoadedWithOpenApiPolymorphism() $model = $this->getModel('SymfonyDiscriminator80'); } - $this->assertInstanceOf(OAAnnotations\Discriminator::class, $model->discriminator); - $this->assertSame('type', $model->discriminator->propertyName); - $this->assertCount(2, $model->discriminator->mapping); - $this->assertArrayHasKey('one', $model->discriminator->mapping); - $this->assertArrayHasKey('two', $model->discriminator->mapping); - $this->assertNotSame(Generator::UNDEFINED, $model->oneOf); - $this->assertCount(2, $model->oneOf); + self::assertInstanceOf(OAAnnotations\Discriminator::class, $model->discriminator); + self::assertSame('type', $model->discriminator->propertyName); + self::assertCount(2, $model->discriminator->mapping); + self::assertArrayHasKey('one', $model->discriminator->mapping); + self::assertArrayHasKey('two', $model->discriminator->mapping); + self::assertNotSame(Generator::UNDEFINED, $model->oneOf); + self::assertCount(2, $model->oneOf); } public function testModelsWithDiscriminatorMapAreLoadedWithOpenApiPolymorphismWhenUsingFileConfiguration() { $model = $this->getModel('SymfonyDiscriminatorFileMapping'); - $this->assertInstanceOf(OAAnnotations\Discriminator::class, $model->discriminator); - $this->assertSame('type', $model->discriminator->propertyName); - $this->assertCount(2, $model->discriminator->mapping); - $this->assertArrayHasKey('one', $model->discriminator->mapping); - $this->assertArrayHasKey('two', $model->discriminator->mapping); - $this->assertNotSame(Generator::UNDEFINED, $model->oneOf); - $this->assertCount(2, $model->oneOf); + self::assertInstanceOf(OAAnnotations\Discriminator::class, $model->discriminator); + self::assertSame('type', $model->discriminator->propertyName); + self::assertCount(2, $model->discriminator->mapping); + self::assertArrayHasKey('one', $model->discriminator->mapping); + self::assertArrayHasKey('two', $model->discriminator->mapping); + self::assertNotSame(Generator::UNDEFINED, $model->oneOf); + self::assertCount(2, $model->oneOf); } public function testDiscriminatorMapLoadsChildrenModels() @@ -830,7 +830,7 @@ public function testNoAdditionalPropertiesSupport() { $model = $this->getModel('AddProp'); - $this->assertFalse($model->additionalProperties); + self::assertFalse($model->additionalProperties); } /** @@ -840,19 +840,19 @@ public function testEnumSupport() { $model = $this->getModel('ArticleType81'); - $this->assertSame('string', $model->type); - $this->assertCount(2, $model->enum); + self::assertSame('string', $model->type); + self::assertCount(2, $model->enum); $model = $this->getModel('ArticleType81NotBacked'); - $this->assertSame('object', $model->type, 'Non backed enums cannot be described'); + self::assertSame('object', $model->type, 'Non backed enums cannot be described'); $model = $this->getModel('ArticleType81IntBacked'); - $this->assertSame('integer', $model->type); - $this->assertCount(2, $model->enum); + self::assertSame('integer', $model->type); + self::assertCount(2, $model->enum); - $this->assertEquals([ + self::assertEquals([ 'type' => 'object', 'properties' => [ 'id' => [ @@ -887,57 +887,57 @@ public function testEntitiesWithOverriddenSchemaTypeDoNotReadOtherProperties() $model = $this->getModel('EntityWithAlternateType80'); } - $this->assertSame('array', $model->type); - $this->assertSame('string', $model->items->type); - $this->assertSame(Generator::UNDEFINED, $model->properties); + self::assertSame('array', $model->type); + self::assertSame('string', $model->items->type); + self::assertSame(Generator::UNDEFINED, $model->properties); } public function testEntitiesWithRefInSchemaDoNoReadOtherProperties() { $model = $this->getModel('EntityWithRef'); - $this->assertSame(Generator::UNDEFINED, $model->type); - $this->assertSame('#/components/schemas/Test', $model->ref); - $this->assertSame(Generator::UNDEFINED, $model->properties); + self::assertSame(Generator::UNDEFINED, $model->type); + self::assertSame('#/components/schemas/Test', $model->ref); + self::assertSame(Generator::UNDEFINED, $model->properties); } public function testEntitiesWithObjectTypeStillReadProperties() { $model = $this->getModel('EntityWithObjectType'); - $this->assertSame('object', $model->type); - $this->assertCount(1, $model->properties); + self::assertSame('object', $model->type); + self::assertCount(1, $model->properties); $property = Util::getProperty($model, 'notIgnored'); - $this->assertSame('string', $property->type); + self::assertSame('string', $property->type); } public function testFormsWithOverriddenSchemaTypeDoNotReadOtherProperties() { $model = $this->getModel('FormWithAlternateSchemaType'); - $this->assertSame('string', $model->type); - $this->assertSame(Generator::UNDEFINED, $model->properties); + self::assertSame('string', $model->type); + self::assertSame(Generator::UNDEFINED, $model->properties); } public function testFormWithRefInSchemaDoNoReadOtherProperties() { $model = $this->getModel('FormWithRefType'); - $this->assertSame(Generator::UNDEFINED, $model->type); - $this->assertSame('#/components/schemas/Test', $model->ref); - $this->assertSame(Generator::UNDEFINED, $model->properties); + self::assertSame(Generator::UNDEFINED, $model->type); + self::assertSame('#/components/schemas/Test', $model->ref); + self::assertSame(Generator::UNDEFINED, $model->properties); } public function testFormCsrfIsOnlyDetectedIfCsrfExtensionIsEnabled(): void { // Make sure that test precondition is correct. $isCsrfFormExtensionEnabled = self::getContainer()->getParameter('form.type_extension.csrf.enabled'); - $this->assertFalse($isCsrfFormExtensionEnabled, 'The test needs the csrf form extension to be disabled.'); + self::assertFalse($isCsrfFormExtensionEnabled, 'The test needs the csrf form extension to be disabled.'); $model = $this->getModel('FormWithCsrfProtectionEnabledType'); // Make sure that no token property was added - $this->assertCount(1, $model->properties); + self::assertCount(1, $model->properties); $this->assertHasProperty('name', $model); } @@ -945,25 +945,25 @@ public function testEntityWithNullableSchemaSet() { $model = $this->getModel('EntityWithNullableSchemaSet'); - $this->assertCount(6, $model->properties); + self::assertCount(6, $model->properties); // nullablePropertyNullableNotSet - $this->assertTrue($model->properties[0]->nullable); + self::assertTrue($model->properties[0]->nullable); // nullablePropertyNullableFalseSet - $this->assertSame(Generator::UNDEFINED, $model->properties[1]->nullable); + self::assertSame(Generator::UNDEFINED, $model->properties[1]->nullable); // nullablePropertyNullableTrueSet - $this->assertTrue($model->properties[2]->nullable); + self::assertTrue($model->properties[2]->nullable); // nonNullablePropertyNullableNotSet - $this->assertSame(Generator::UNDEFINED, $model->properties[3]->nullable); + self::assertSame(Generator::UNDEFINED, $model->properties[3]->nullable); // nonNullablePropertyNullableFalseSet - $this->assertSame(Generator::UNDEFINED, $model->properties[4]->nullable); + self::assertSame(Generator::UNDEFINED, $model->properties[4]->nullable); // nonNullablePropertyNullableTrueSet - $this->assertTrue($model->properties[5]->nullable); + self::assertTrue($model->properties[5]->nullable); } public function testContextPassedToNameConverter() @@ -1190,7 +1190,7 @@ public function testEntityWithFalsyDefaults() { $model = $this->getModel('EntityWithFalsyDefaults'); - $this->assertSame(Generator::UNDEFINED, $model->required); + self::assertSame(Generator::UNDEFINED, $model->required); self::assertEquals([ 'schema' => 'EntityWithFalsyDefaults', diff --git a/tests/Functional/JMSFunctionalTest.php b/tests/Functional/JMSFunctionalTest.php index 214926bb4..c97903d71 100644 --- a/tests/Functional/JMSFunctionalTest.php +++ b/tests/Functional/JMSFunctionalTest.php @@ -24,7 +24,7 @@ protected function setUp(): void public function testModelPictureDocumentation() { - $this->assertEquals([ + self::assertEquals([ 'type' => 'object', 'properties' => [ 'id' => [ @@ -34,7 +34,7 @@ public function testModelPictureDocumentation() 'schema' => 'JMSPicture', ], json_decode($this->getModel('JMSPicture')->toJson(), true)); - $this->assertEquals([ + self::assertEquals([ 'type' => 'object', 'properties' => [ 'only_direct_picture_mini' => [ @@ -47,7 +47,7 @@ public function testModelPictureDocumentation() public function testModeChatDocumentation() { - $this->assertEquals([ + self::assertEquals([ 'type' => 'object', 'properties' => [ 'id' => [ @@ -63,7 +63,7 @@ public function testModeChatDocumentation() 'schema' => 'JMSChat', ], json_decode($this->getModel('JMSChat')->toJson(), true)); - $this->assertEquals([ + self::assertEquals([ 'type' => 'object', 'properties' => [ 'picture' => [ @@ -76,7 +76,7 @@ public function testModeChatDocumentation() public function testModelDocumentation() { - $this->assertEquals([ + self::assertEquals([ 'type' => 'object', 'properties' => [ 'id' => [ @@ -215,11 +215,11 @@ public function testModelDocumentation() 'schema' => 'JMSUser', ], json_decode($this->getModel('JMSUser')->toJson(), true)); - $this->assertEquals([ + self::assertEquals([ 'schema' => 'VirtualTypeClassDoesNotExistsHandlerNotDefined', ], json_decode($this->getModel('VirtualTypeClassDoesNotExistsHandlerNotDefined')->toJson(), true)); - $this->assertEquals([ + self::assertEquals([ 'type' => 'object', 'properties' => [ 'custom_prop' => [ @@ -232,7 +232,7 @@ public function testModelDocumentation() public function testModelComplexDualDocumentation() { - $this->assertEquals([ + self::assertEquals([ 'type' => 'object', 'properties' => [ 'id' => [ @@ -251,7 +251,7 @@ public function testModelComplexDualDocumentation() public function testNestedGroups() { - $this->assertEquals([ + self::assertEquals([ 'type' => 'object', 'properties' => [ 'living' => ['$ref' => '#/components/schemas/JMSChatLivingRoom'], @@ -260,7 +260,7 @@ public function testNestedGroups() 'schema' => 'JMSChatFriend', ], json_decode($this->getModel('JMSChatFriend')->toJson(), true)); - $this->assertEquals([ + self::assertEquals([ 'type' => 'object', 'properties' => [ 'id1' => ['type' => 'integer'], @@ -272,7 +272,7 @@ public function testNestedGroups() public function testModelComplexDocumentation() { - $this->assertEquals([ + self::assertEquals([ 'type' => 'object', 'properties' => [ 'id' => ['type' => 'integer'], @@ -291,7 +291,7 @@ public function testModelComplexDocumentation() public function testYamlConfig() { - $this->assertEquals([ + self::assertEquals([ 'type' => 'object', 'properties' => [ 'id' => [ @@ -321,7 +321,7 @@ public function testNoCollisionsAreGenerated() public function testNamingStrategyWithConstraints() { - $this->assertEquals([ + self::assertEquals([ 'type' => 'object', 'properties' => [ 'beautifulName' => [ @@ -340,7 +340,7 @@ public function testNamingStrategyWithConstraints() */ public function testEnumSupport() { - $this->assertEquals([ + self::assertEquals([ 'type' => 'object', 'properties' => [ 'id' => [ @@ -362,7 +362,7 @@ public function testEnumSupport() 'schema' => 'Article81', ], json_decode($this->getModel('Article81')->toJson(), true)); - $this->assertEquals([ + self::assertEquals([ 'schema' => 'ArticleType81', 'type' => 'string', 'enum' => [ @@ -374,7 +374,7 @@ public function testEnumSupport() public function testModeDiscriminatorMap() { - $this->assertEquals([ + self::assertEquals([ 'type' => 'object', 'properties' => [ 'username' => [ @@ -384,7 +384,7 @@ public function testModeDiscriminatorMap() 'schema' => 'JMSManager', ], json_decode($this->getModel('JMSManager')->toJson(), true)); - $this->assertEquals([ + self::assertEquals([ 'type' => 'object', 'properties' => [ 'username' => [ @@ -397,7 +397,7 @@ public function testModeDiscriminatorMap() 'schema' => 'JMSAdministrator', ], json_decode($this->getModel('JMSAdministrator')->toJson(), true)); - $this->assertEquals([ + self::assertEquals([ 'oneOf' => [ ['$ref' => '#/components/schemas/JMSManager'], ['$ref' => '#/components/schemas/JMSAdministrator'], diff --git a/tests/Functional/SwaggerPHPApiComplianceTest.php b/tests/Functional/SwaggerPHPApiComplianceTest.php index 6842b6115..177f8e58a 100644 --- a/tests/Functional/SwaggerPHPApiComplianceTest.php +++ b/tests/Functional/SwaggerPHPApiComplianceTest.php @@ -27,11 +27,10 @@ public function testAllContextsCopyRoot() { $openApi = $this->getOpenApiDefinition(); $root = $openApi->_context; - $this->assertTrue($root->is('version')); + self::assertTrue($root->is('version')); - $counter = 0; foreach ((new Analysis([$openApi], Util::createContext()))->annotations as $annotation) { - $this->assertSame($annotation->_context->version, $root->version); + self::assertSame($annotation->_context->version, $root->version); } } } diff --git a/tests/Functional/SwaggerUiTest.php b/tests/Functional/SwaggerUiTest.php index f90231ca1..e4def2db2 100644 --- a/tests/Functional/SwaggerUiTest.php +++ b/tests/Functional/SwaggerUiTest.php @@ -34,16 +34,16 @@ public function testSwaggerUi() $crawler = $this->client->request('GET', '/app_dev.php/default/docs'); $response = $this->client->getResponse(); - $this->assertEquals(200, $response->getStatusCode()); - $this->assertEquals('UTF-8', $response->getCharset()); - $this->assertEquals('text/html; charset=UTF-8', $response->headers->get('Content-Type')); + self::assertEquals(200, $response->getStatusCode()); + self::assertEquals('UTF-8', $response->getCharset()); + self::assertEquals('text/html; charset=UTF-8', $response->headers->get('Content-Type')); $expected = json_decode($this->getOpenApiDefinition()->toJson(), true); $expected['servers'] = [ ['url' => 'http://api.example.com/app_dev.php'], ]; - $this->assertEquals($expected, json_decode($crawler->filterXPath('//script[@id="swagger-data"]')->text(), true)['spec']); + self::assertEquals($expected, json_decode($crawler->filterXPath('//script[@id="swagger-data"]')->text(), true)['spec']); } public function testRedocly() @@ -51,17 +51,17 @@ public function testRedocly() $crawler = $this->client->request('GET', '/app_dev.php/default/redocly/docs'); $response = $this->client->getResponse(); - $this->assertEquals(200, $response->getStatusCode()); - $this->assertEquals('UTF-8', $response->getCharset()); - $this->assertEquals('text/html; charset=UTF-8', $response->headers->get('Content-Type')); + self::assertEquals(200, $response->getStatusCode()); + self::assertEquals('UTF-8', $response->getCharset()); + self::assertEquals('text/html; charset=UTF-8', $response->headers->get('Content-Type')); $expected = json_decode($this->getOpenApiDefinition()->toJson(), true); $expected['servers'] = [ ['url' => 'http://api.example.com/app_dev.php'], ]; - $this->assertSame(1, $crawler->filterXPath('//script[@src="/bundles/nelmioapidoc/redocly/redoc.standalone.js"]')->count()); - $this->assertEquals($expected, json_decode($crawler->filterXPath('//script[@id="swagger-data"]')->text(), true)['spec']); + self::assertCount(1, $crawler->filterXPath('//script[@src="/bundles/nelmioapidoc/redocly/redoc.standalone.js"]')); + self::assertEquals($expected, json_decode($crawler->filterXPath('//script[@id="swagger-data"]')->text(), true)['spec']); } public function testApiPlatformSwaggerUi() @@ -69,15 +69,15 @@ public function testApiPlatformSwaggerUi() $crawler = $this->client->request('GET', '/app_dev.php/test/docs'); $response = $this->client->getResponse(); - $this->assertEquals(200, $response->getStatusCode()); - $this->assertEquals('text/html; charset=UTF-8', $response->headers->get('Content-Type')); + self::assertEquals(200, $response->getStatusCode()); + self::assertEquals('text/html; charset=UTF-8', $response->headers->get('Content-Type')); $expected = json_decode($this->getOpenApiDefinition('test')->toJson(), true); $expected['servers'] = [ ['url' => 'http://api.example.com/app_dev.php'], ]; - $this->assertEquals($expected, json_decode($crawler->filterXPath('//script[@id="swagger-data"]')->text(), true)['spec']); + self::assertEquals($expected, json_decode($crawler->filterXPath('//script[@id="swagger-data"]')->text(), true)['spec']); } public function testJsonDocs() @@ -85,15 +85,15 @@ public function testJsonDocs() $this->client->request('GET', '/app_dev.php/default/docs.json'); $response = $this->client->getResponse(); - $this->assertEquals(200, $response->getStatusCode()); - $this->assertEquals('application/json', $response->headers->get('Content-Type')); + self::assertEquals(200, $response->getStatusCode()); + self::assertEquals('application/json', $response->headers->get('Content-Type')); $expected = json_decode($this->getOpenApiDefinition()->toJson(), true); $expected['servers'] = [ ['url' => 'http://api.example.com/app_dev.php'], ]; - $this->assertEquals($expected, json_decode($response->getContent(), true)); + self::assertEquals($expected, json_decode($response->getContent(), true)); } public function testInvalidJsonArea() @@ -101,7 +101,7 @@ public function testInvalidJsonArea() $this->client->request('GET', '/app_dev.php/nonexistent/docs.json'); $response = $this->client->getResponse(); - $this->assertEquals(400, $response->getStatusCode()); + self::assertEquals(400, $response->getStatusCode()); } public function testYamlDocs() @@ -109,13 +109,13 @@ public function testYamlDocs() $this->client->request('GET', '/app_dev.php/default/docs.yaml'); $response = $this->client->getResponse(); - $this->assertEquals(200, $response->getStatusCode()); - $this->assertEquals('text/x-yaml; charset=UTF-8', $response->headers->get('Content-Type')); + self::assertEquals(200, $response->getStatusCode()); + self::assertEquals('text/x-yaml; charset=UTF-8', $response->headers->get('Content-Type')); $spec = $this->getOpenApiDefinition(); $spec->servers = [new Server(['url' => 'http://api.example.com/app_dev.php', '_context' => new Context()])]; $expected = $spec->toYaml(); - $this->assertEquals($expected, $response->getContent()); + self::assertEquals($expected, $response->getContent()); } } diff --git a/tests/Functional/SymfonyFunctionalTest.php b/tests/Functional/SymfonyFunctionalTest.php index 0344bde4d..61db0c600 100644 --- a/tests/Functional/SymfonyFunctionalTest.php +++ b/tests/Functional/SymfonyFunctionalTest.php @@ -65,7 +65,7 @@ public function testMapQueryStringModelGetsCreated(): void 'type' => 'object', ]; - $this->assertSame($expected, json_decode($this->getModel('SymfonyMapQueryString')->toJson(), true)); + self::assertSame($expected, json_decode($this->getModel('SymfonyMapQueryString')->toJson(), true)); } public function testMapQueryString(): void diff --git a/tests/Functional/TestKernel.php b/tests/Functional/TestKernel.php index 926df7641..0f6b83d02 100644 --- a/tests/Functional/TestKernel.php +++ b/tests/Functional/TestKernel.php @@ -26,7 +26,6 @@ use Nelmio\ApiDocBundle\Tests\Functional\Entity\SymfonyConstraintsWithValidationGroups; use Nelmio\ApiDocBundle\Tests\Functional\ModelDescriber\NameConverter; use Nelmio\ApiDocBundle\Tests\Functional\ModelDescriber\VirtualTypeClassDoesNotExistsHandlerDefinedDescriber; -use Symfony\Bundle\FrameworkBundle\Command\CachePoolClearCommand; use Symfony\Bundle\FrameworkBundle\FrameworkBundle; use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait; use Symfony\Bundle\TwigBundle\TwigBundle; @@ -47,13 +46,13 @@ class TestKernel extends Kernel public const USE_VALIDATION_GROUPS = 8; public const USE_FORM_CSRF = 16; - private $flags; + private int $flag; - public function __construct(int $flags = 0) + public function __construct(int $flag = 0) { - parent::__construct('test'.$flags, true); + parent::__construct('test'.$flag, true); - $this->flags = $flags; + $this->flag = $flag; } public function registerBundles(): iterable @@ -70,10 +69,10 @@ public function registerBundles(): iterable $bundles[] = new FOSRestBundle(); } - if ($this->flags & self::USE_JMS) { + if (self::USE_JMS === $this->flag || self::USE_BAZINGA === $this->flag) { $bundles[] = new JMSSerializerBundle(); - if ($this->flags & self::USE_BAZINGA) { + if (self::USE_BAZINGA === $this->flag) { $bundles[] = new BazingaHateoasBundle(); } } @@ -89,11 +88,11 @@ protected function configureRoutes(RoutingConfigurator $routes) $routes->withPath('/')->import(__DIR__.'/Resources/routes-attributes.yaml', 'yaml'); } - if ($this->flags & self::USE_JMS) { + if (self::USE_JMS === $this->flag || self::USE_BAZINGA === $this->flag) { $routes->withPath('/')->import(__DIR__.'/Controller/JMSController.php', self::isAnnotationsAvailable() ? 'annotation' : 'attribute'); } - if ($this->flags & self::USE_BAZINGA) { + if (self::USE_BAZINGA === $this->flag) { $routes->withPath('/')->import(__DIR__.'/Controller/BazingaTypedController.php', self::isAnnotationsAvailable() ? 'annotation' : 'attribute'); try { @@ -103,7 +102,7 @@ protected function configureRoutes(RoutingConfigurator $routes) } } - if ($this->flags & self::USE_FOSREST) { + if (self::USE_FOSREST === $this->flag) { $routes->withPath('/')->import(__DIR__.'/Controller/FOSRestController.php', self::isAnnotationsAvailable() ? 'annotation' : 'attribute'); } } @@ -128,22 +127,20 @@ protected function configureContainer(ContainerBuilder $c, LoaderInterface $load 'property_access' => true, ]; - if ($this->flags & self::USE_FORM_CSRF) { + if (self::USE_FORM_CSRF === $this->flag) { $framework['csrf_protection']['enabled'] = true; $framework['session']['storage_factory_id'] = 'session.storage.factory.mock_file'; $framework['form'] = ['csrf_protection' => true]; } - // Support symfony/framework-bundle < 5.4 - if (method_exists(CachePoolClearCommand::class, 'complete')) { - $framework += [ - 'exceptions' => [ - 'Symfony\Component\HttpKernel\Exception\BadRequestHttpException' => [ - 'log_level' => 'debug', - ], + $framework += [ + 'exceptions' => [ + 'Symfony\Component\HttpKernel\Exception\BadRequestHttpException' => [ + 'log_level' => 'debug', ], - ]; - } + ], + ]; + $c->loadFromExtension('framework', $framework); $c->loadFromExtension('twig', [ @@ -250,7 +247,7 @@ protected function configureContainer(ContainerBuilder $c, LoaderInterface $load // Filter routes $c->loadFromExtension('nelmio_api_doc', [ - 'use_validation_groups' => boolval($this->flags & self::USE_VALIDATION_GROUPS), + 'use_validation_groups' => boolval(self::USE_VALIDATION_GROUPS === $this->flag), 'documentation' => [ 'info' => [ 'title' => 'My Default App', @@ -325,7 +322,7 @@ protected function configureContainer(ContainerBuilder $c, LoaderInterface $load ], ]); - if ($this->flags & self::USE_JMS && \PHP_VERSION_ID >= 80100) { + if (self::USE_JMS === $this->flag && \PHP_VERSION_ID >= 80100) { $c->loadFromExtension('jms_serializer', [ 'enum_support' => true, ]); @@ -342,22 +339,12 @@ protected function configureContainer(ContainerBuilder $c, LoaderInterface $load public function getCacheDir(): string { - return parent::getCacheDir().'/'.$this->flags; + return parent::getCacheDir().'/'.$this->flag; } public function getLogDir(): string { - return parent::getLogDir().'/'.$this->flags; - } - - public function serialize() - { - return serialize($this->useJMS); - } - - public function unserialize($str) - { - $this->__construct(unserialize($str)); + return parent::getLogDir().'/'.$this->flag; } public static function isAnnotationsAvailable(): bool diff --git a/tests/Functional/ValidationGroupsFunctionalTest.php b/tests/Functional/ValidationGroupsFunctionalTest.php index e9ece6b72..c7ee31d4a 100644 --- a/tests/Functional/ValidationGroupsFunctionalTest.php +++ b/tests/Functional/ValidationGroupsFunctionalTest.php @@ -44,7 +44,7 @@ public function testConstraintGroupsAreRespectedWhenDescribingModels() 'schema' => 'SymfonyConstraintsTestGroup', ]; - $this->assertEquals( + self::assertEquals( $expected, json_decode($this->getModel('SymfonyConstraintsTestGroup')->toJson(), true) ); @@ -81,7 +81,7 @@ public function testConstraintDefaultGroupsAreRespectedWhenReadingAnnotations() ], ]; - $this->assertEquals( + self::assertEquals( $expected, json_decode($this->getModel('SymfonyConstraintsDefaultGroup')->toJson(), true) ); diff --git a/tests/Functional/WebTestCase.php b/tests/Functional/WebTestCase.php index c3e4cc260..f932fe0b3 100644 --- a/tests/Functional/WebTestCase.php +++ b/tests/Functional/WebTestCase.php @@ -31,7 +31,7 @@ protected function getOpenApiDefinition($area = 'default'): OA\OpenApi public function hasModel(string $name): bool { $api = $this->getOpenApiDefinition(); - $key = array_search($name, array_column($api->components->schemas, 'schema')); + $key = array_search($name, array_column($api->components->schemas, 'schema'), true); return false !== $key; } @@ -39,7 +39,7 @@ public function hasModel(string $name): bool protected function getModel($name): OA\Schema { $api = $this->getOpenApiDefinition(); - $key = array_search($name, array_column($api->components->schemas, 'schema')); + $key = array_search($name, array_column($api->components->schemas, 'schema'), true); static::assertNotFalse($key, sprintf('Model "%s" does not exist.', $name)); return $api->components->schemas[$key]; @@ -49,7 +49,7 @@ protected function getOperation($path, $method): OA\Operation { $path = $this->getPath($path); - $this->assertInstanceOf( + self::assertInstanceOf( OA\Operation::class, $path->{$method}, sprintf('Operation "%s" for path "%s" does not exist', $method, $path->path) @@ -61,7 +61,7 @@ protected function getOperation($path, $method): OA\Operation protected function getOperationResponse(OA\Operation $operation, $response): OA\Response { $this->assertHasResponse($response, $operation); - $key = array_search($response, array_column($operation->responses, 'response')); + $key = array_search($response, array_column($operation->responses, 'response'), true); return $operation->responses[$key]; } @@ -69,16 +69,18 @@ protected function getOperationResponse(OA\Operation $operation, $response): OA\ protected function getProperty(OA\Schema $annotation, $property): OA\Property { $this->assertHasProperty($property, $annotation); - $key = array_search($property, array_column($annotation->properties, 'property')); + $key = array_search($property, array_column($annotation->properties, 'property'), true); return $annotation->properties[$key]; } + /** + * @param OA\Operation|OA\OpenApi $annotation + */ protected function getParameter(OA\AbstractAnnotation $annotation, $name, $in): OA\Parameter { - /* @var OA\Operation|OA\OpenApi $annotation */ $this->assertHasParameter($name, $in, $annotation); - $parameters = array_filter($annotation->parameters ?: [], function (OA\Parameter $parameter) use ($name, $in) { + $parameters = array_filter($annotation->parameters ?? [], function (OA\Parameter $parameter) use ($name, $in) { return $parameter->name === $name && $parameter->in === $in; }); @@ -90,7 +92,7 @@ protected function getPath($path): OA\PathItem $api = $this->getOpenApiDefinition(); self::assertHasPath($path, $api); - return $api->paths[array_search($path, array_column($api->paths, 'path'))]; + return $api->paths[array_search($path, array_column($api->paths, 'path'), true)]; } public function assertHasPath($path, OA\OpenApi $api) @@ -123,9 +125,11 @@ public function assertHasResponse($responseCode, OA\Operation $operation) ); } + /** + * @param OA\Operation|OA\OpenApi $annotation + */ public function assertHasParameter($name, $in, OA\AbstractAnnotation $annotation) { - /* @var OA\Operation|OA\OpenApi $annotation */ $parameters = array_filter(Generator::UNDEFINED !== $annotation->parameters ? $annotation->parameters : [], function (OA\Parameter $parameter) use ($name, $in) { return $parameter->name === $name && $parameter->in === $in; }); @@ -136,9 +140,11 @@ public function assertHasParameter($name, $in, OA\AbstractAnnotation $annotation ); } + /** + * @param OA\Operation|OA\OpenApi $annotation + */ public function assertNotHasParameter($name, $in, OA\AbstractAnnotation $annotation) { - /* @var OA\Operation|OA\OpenApi $annotation */ $parameters = array_column(Generator::UNDEFINED !== $annotation->parameters ? $annotation->parameters : [], 'name', 'in'); static::assertNotContains( $name, @@ -147,9 +153,11 @@ public function assertNotHasParameter($name, $in, OA\AbstractAnnotation $annotat ); } + /** + * @param OA\Schema|OA\Property|OA\Items $annotation + */ public function assertHasProperty($property, OA\AbstractAnnotation $annotation) { - /* @var OA\Schema|OA\Property|OA\Items $annotation */ $properties = array_column(Generator::UNDEFINED !== $annotation->properties ? $annotation->properties : [], 'property'); static::assertContains( $property, @@ -158,9 +166,11 @@ public function assertHasProperty($property, OA\AbstractAnnotation $annotation) ); } + /** + * @param OA\Schema|OA\Property|OA\Items $annotation + */ public function assertNotHasProperty($property, OA\AbstractAnnotation $annotation) { - /* @var OA\Schema|OA\Property|OA\Items $annotation */ $properties = array_column(Generator::UNDEFINED !== $annotation->properties ? $annotation->properties : [], 'property'); static::assertNotContains( $property, @@ -168,21 +178,4 @@ public function assertNotHasProperty($property, OA\AbstractAnnotation $annotatio sprintf('Failed asserting that property "%s" does not exist.', $property) ); } - - /** - * BC symfony < 5.3 and symfony >= 7. - * - * KernelTestCase::getContainer has a Container return type object in symfony 7 - * which is incompatible with the return type of previous versions or - * at least the return type of overridden method (which was added for BC compatibility), - * hence moving it to the magic method. - */ - public static function __callStatic(string $name, array $arguments) - { - if ('getContainer' === $name) { - return static::$container; - } - - return null; - } } diff --git a/tests/Model/ModelRegistryTest.php b/tests/Model/ModelRegistryTest.php index f504e33a0..f43559f93 100644 --- a/tests/Model/ModelRegistryTest.php +++ b/tests/Model/ModelRegistryTest.php @@ -32,7 +32,7 @@ public function testNameAliasingNotAppliedForCollections() $registry = new ModelRegistry([], $this->createOpenApi(), $alternativeNames); $type = new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true); - $this->assertEquals('#/components/schemas/array', $registry->register(new Model($type, ['group1']))); + self::assertEquals('#/components/schemas/array', $registry->register(new Model($type, ['group1']))); } /** @@ -166,7 +166,7 @@ public function testNameAliasingForObjects(string $expected, $groups, array $alt $registry = new ModelRegistry([], $this->createOpenApi(), $alternativeNames); $type = new Type(Type::BUILTIN_TYPE_OBJECT, false, self::class); - $this->assertEquals($expected, $registry->register(new Model($type, $groups))); + self::assertEquals($expected, $registry->register(new Model($type, $groups))); } public function getNameAlternatives() @@ -248,11 +248,11 @@ public function unsupportedTypesProvider() public function testUnsupportedTypeExceptionWithNonExistentClass() { - $className = DoesNotExist::class; + $className = 'Some\\Class\\That\\DoesNotExist'; $type = new Type(Type::BUILTIN_TYPE_OBJECT, false, $className); - $this->expectException('\LogicException'); - $this->expectExceptionMessage(sprintf('Schema of type "\%s" can\'t be generated, no describer supports it. Class "\Nelmio\ApiDocBundle\Tests\Model\DoesNotExist" does not exist, did you forget a use statement, or typed it wrong?', $className)); + $this->expectException(\LogicException::class); + $this->expectExceptionMessage(sprintf('Schema of type "\%s" can\'t be generated, no describer supports it. Class "\Some\Class\That\DoesNotExist" does not exist, did you forget a use statement, or typed it wrong?', $className)); $registry = new ModelRegistry([], $this->createOpenApi()); $registry->register(new Model($type)); diff --git a/tests/ModelDescriber/Annotations/AnnotationReaderTest.php b/tests/ModelDescriber/Annotations/AnnotationReaderTest.php index 4aedd3798..19cadd414 100644 --- a/tests/ModelDescriber/Annotations/AnnotationReaderTest.php +++ b/tests/ModelDescriber/Annotations/AnnotationReaderTest.php @@ -47,11 +47,11 @@ class_exists(AnnotationReader::class) ? new AnnotationReader() : null, $symfonyConstraintAnnotationReader->updateProperty(new \ReflectionProperty($entity, 'property1'), $schema->properties[0]); $symfonyConstraintAnnotationReader->updateProperty(new \ReflectionProperty($entity, 'property2'), $schema->properties[1]); - $this->assertEquals($schema->properties[0]->example, 1); - $this->assertEquals($schema->properties[0]->description, Generator::UNDEFINED); + self::assertEquals($schema->properties[0]->example, 1); + self::assertEquals($schema->properties[0]->description, Generator::UNDEFINED); - $this->assertEquals($schema->properties[1]->example, 'some example'); - $this->assertEquals($schema->properties[1]->description, 'some description'); + self::assertEquals($schema->properties[1]->example, 'some example'); + self::assertEquals($schema->properties[1]->description, 'some description'); } public function provideProperty(): iterable @@ -60,19 +60,19 @@ public function provideProperty(): iterable /** * @OA\Property(example=1) */ - private $property1; + public $property1; /** * @OA\Property(example="some example", description="some description") */ - private $property2; + public $property2; }]; if (\PHP_VERSION_ID >= 80100) { yield 'Attributes' => [new class() { #[OAattr\Property(example: 1)] - private $property1; + public $property1; #[OAattr\Property(example: 'some example', description: 'some description')] - private $property2; + public $property2; }]; } } diff --git a/tests/ModelDescriber/Annotations/SymfonyConstraintAnnotationReaderTest.php b/tests/ModelDescriber/Annotations/SymfonyConstraintAnnotationReaderTest.php index 011001705..7f4a58204 100644 --- a/tests/ModelDescriber/Annotations/SymfonyConstraintAnnotationReaderTest.php +++ b/tests/ModelDescriber/Annotations/SymfonyConstraintAnnotationReaderTest.php @@ -45,21 +45,21 @@ public function testUpdatePropertyFix1283() * * @Assert\Length(min = 1) */ - private $property1; + public $property1; /** * @Assert\NotBlank() */ - private $property2; + public $property2; }; } else { $entity = new class() { #[Assert\Length(min: 1)] #[Assert\NotBlank()] - private $property1; + public $property1; #[Assert\NotBlank()] - private $property2; + public $property2; }; } @@ -74,7 +74,7 @@ public function testUpdatePropertyFix1283() $symfonyConstraintAnnotationReader->updateProperty(new \ReflectionProperty($entity, 'property2'), $schema->properties[1]); // expect required to be numeric array with sequential keys (not [0 => ..., 2 => ...]) - $this->assertEquals($schema->required, ['property1', 'property2']); + self::assertEquals($schema->required, ['property1', 'property2']); } /** @@ -85,7 +85,7 @@ public function testUpdatePropertyFix1283() public function testOptionalProperty($entity) { if (!\property_exists(Assert\NotBlank::class, 'allowNull')) { - $this->markTestSkipped('NotBlank::allowNull was added in symfony/validator 4.3.'); + self::markTestSkipped('NotBlank::allowNull was added in symfony/validator 4.3.'); } $schema = $this->createObj(OA\Schema::class, []); @@ -99,7 +99,7 @@ public function testOptionalProperty($entity) $symfonyConstraintAnnotationReader->updateProperty(new \ReflectionProperty($entity, 'property2'), $schema->properties[1]); // expect required to be numeric array with sequential keys (not [0 => ..., 2 => ...]) - $this->assertEquals($schema->required, ['property2']); + self::assertEquals($schema->required, ['property2']); } public function provideOptionalProperty(): iterable @@ -112,12 +112,12 @@ public function provideOptionalProperty(): iterable * * @Assert\Length(min = 1) */ - private $property1; + public $property1; /** * @Assert\NotBlank() */ - private $property2; + public $property2; }, ]; } @@ -126,9 +126,9 @@ public function provideOptionalProperty(): iterable yield 'Attributes' => [new class() { #[Assert\NotBlank(allowNull: true)] #[Assert\Length(min: 1)] - private $property1; + public $property1; #[Assert\NotBlank] - private $property2; + public $property2; }]; } } @@ -149,7 +149,7 @@ public function testAssertChoiceResultsInNumericArray($entity) $symfonyConstraintAnnotationReader->updateProperty(new \ReflectionProperty($entity, 'property1'), $schema->properties[0]); // expect enum to be numeric array with sequential keys (not [1 => "active", 2 => "active"]) - $this->assertEquals($schema->properties[0]->enum, ['active', 'blocked']); + self::assertEquals($schema->properties[0]->enum, ['active', 'blocked']); } public function provideAssertChoiceResultsInNumericArray(): iterable @@ -167,7 +167,7 @@ public function provideAssertChoiceResultsInNumericArray(): iterable * * @Assert\Choice(choices=TEST_ASSERT_CHOICE_STATUSES) */ - private $property1; + public $property1; }, ]; } @@ -176,7 +176,7 @@ public function provideAssertChoiceResultsInNumericArray(): iterable yield 'Attributes' => [new class() { #[Assert\Length(min: 1)] #[Assert\Choice(choices: TEST_ASSERT_CHOICE_STATUSES)] - private $property1; + public $property1; }]; } } @@ -196,8 +196,8 @@ public function testMultipleChoiceConstraintsApplyEnumToItems($entity) $symfonyConstraintAnnotationReader->updateProperty(new \ReflectionProperty($entity, 'property1'), $schema->properties[0]); - $this->assertInstanceOf(OA\Items::class, $schema->properties[0]->items); - $this->assertEquals($schema->properties[0]->items->enum, ['one', 'two']); + self::assertInstanceOf(OA\Items::class, $schema->properties[0]->items); + self::assertEquals($schema->properties[0]->items->enum, ['one', 'two']); } public function provideMultipleChoiceConstraintsApplyEnumToItems(): iterable @@ -207,14 +207,14 @@ public function provideMultipleChoiceConstraintsApplyEnumToItems(): iterable /** * @Assert\Choice(choices={"one", "two"}, multiple=true) */ - private $property1; + public $property1; }]; } if (\PHP_VERSION_ID >= 80000) { yield 'Attributes' => [new class() { #[Assert\Choice(choices: ['one', 'two'], multiple: true)] - private $property1; + public $property1; }]; } } @@ -236,8 +236,8 @@ public function testLengthConstraintDoesNotSetMaxLengthIfMaxIsNotSet($entity) $symfonyConstraintAnnotationReader->updateProperty(new \ReflectionProperty($entity, 'property1'), $schema->properties[0]); - $this->assertSame(Generator::UNDEFINED, $schema->properties[0]->maxLength); - $this->assertSame(1, $schema->properties[0]->minLength); + self::assertSame(Generator::UNDEFINED, $schema->properties[0]->maxLength); + self::assertSame(1, $schema->properties[0]->minLength); } public function provideLengthConstraintDoesNotSetMaxLengthIfMaxIsNotSet(): iterable @@ -248,7 +248,7 @@ public function provideLengthConstraintDoesNotSetMaxLengthIfMaxIsNotSet(): itera /** * @Assert\Length(min = 1) */ - private $property1; + public $property1; }, ]; } @@ -256,7 +256,7 @@ public function provideLengthConstraintDoesNotSetMaxLengthIfMaxIsNotSet(): itera if (\PHP_VERSION_ID >= 80000) { yield 'Attributes' => [new class() { #[Assert\Length(min: 1)] - private $property1; + public $property1; }]; } } @@ -278,8 +278,8 @@ public function testLengthConstraintDoesNotSetMinLengthIfMinIsNotSet($entity) $symfonyConstraintAnnotationReader->updateProperty(new \ReflectionProperty($entity, 'property1'), $schema->properties[0]); - $this->assertSame(Generator::UNDEFINED, $schema->properties[0]->minLength); - $this->assertSame(100, $schema->properties[0]->maxLength); + self::assertSame(Generator::UNDEFINED, $schema->properties[0]->minLength); + self::assertSame(100, $schema->properties[0]->maxLength); } public function provideLengthConstraintDoesNotSetMinLengthIfMinIsNotSet(): iterable @@ -290,7 +290,7 @@ public function provideLengthConstraintDoesNotSetMinLengthIfMinIsNotSet(): itera /** * @Assert\Length(max = 100) */ - private $property1; + public $property1; }, ]; } @@ -298,7 +298,7 @@ public function provideLengthConstraintDoesNotSetMinLengthIfMinIsNotSet(): itera if (\PHP_VERSION_ID >= 80000) { yield 'Attributes' => [new class() { #[Assert\Length(max: 100)] - private $property1; + public $property1; }]; } } @@ -310,12 +310,12 @@ public function testCompoundValidationRules() /** * @CustomAssert\CompoundValidationRule() */ - private $property1; + public $property1; }; } else { $entity = new class() { #[CustomAssert\CompoundValidationRule()] - private $property1; + public $property1; }; } $propertyName = 'property1'; @@ -329,17 +329,17 @@ public function testCompoundValidationRules() $symfonyConstraintAnnotationReader->updateProperty(new \ReflectionProperty($entity, $propertyName), $schema->properties[0]); if (Helper::isCompoundValidatorConstraintSupported()) { - $this->assertSame([$propertyName], $schema->required); - $this->assertSame(0, $schema->properties[0]->minimum); - $this->assertTrue($schema->properties[0]->exclusiveMinimum); - $this->assertSame(5, $schema->properties[0]->maximum); - $this->assertTrue($schema->properties[0]->exclusiveMaximum); + self::assertSame([$propertyName], $schema->required); + self::assertSame(0, $schema->properties[0]->minimum); + self::assertTrue($schema->properties[0]->exclusiveMinimum); + self::assertSame(5, $schema->properties[0]->maximum); + self::assertTrue($schema->properties[0]->exclusiveMaximum); } else { - $this->assertSame(Generator::UNDEFINED, $schema->required); - $this->assertSame(Generator::UNDEFINED, $schema->properties[0]->minimum); - $this->assertSame(Generator::UNDEFINED, $schema->properties[0]->exclusiveMinimum); - $this->assertSame(Generator::UNDEFINED, $schema->properties[0]->maximum); - $this->assertSame(Generator::UNDEFINED, $schema->properties[0]->exclusiveMaximum); + self::assertSame(Generator::UNDEFINED, $schema->required); + self::assertSame(Generator::UNDEFINED, $schema->properties[0]->minimum); + self::assertSame(Generator::UNDEFINED, $schema->properties[0]->exclusiveMinimum); + self::assertSame(Generator::UNDEFINED, $schema->properties[0]->maximum); + self::assertSame(Generator::UNDEFINED, $schema->properties[0]->exclusiveMaximum); } } @@ -360,8 +360,8 @@ public function testCountConstraintDoesNotSetMinItemsIfMinIsNotSet($entity) $symfonyConstraintAnnotationReader->updateProperty(new \ReflectionProperty($entity, 'property1'), $schema->properties[0]); - $this->assertSame(Generator::UNDEFINED, $schema->properties[0]->minItems); - $this->assertSame(10, $schema->properties[0]->maxItems); + self::assertSame(Generator::UNDEFINED, $schema->properties[0]->minItems); + self::assertSame(10, $schema->properties[0]->maxItems); } public function provideCountConstraintDoesNotSetMinItemsIfMinIsNotSet(): iterable @@ -372,7 +372,7 @@ public function provideCountConstraintDoesNotSetMinItemsIfMinIsNotSet(): iterabl /** * @Assert\Count(max = 10) */ - private $property1; + public $property1; }, ]; } @@ -380,7 +380,7 @@ public function provideCountConstraintDoesNotSetMinItemsIfMinIsNotSet(): iterabl if (\PHP_VERSION_ID >= 80000) { yield 'Attributes' => [new class() { #[Assert\Count(max: 10)] - private $property1; + public $property1; }]; } } @@ -402,8 +402,8 @@ public function testCountConstraintDoesNotSetMaxItemsIfMaxIsNotSet($entity) $symfonyConstraintAnnotationReader->updateProperty(new \ReflectionProperty($entity, 'property1'), $schema->properties[0]); - $this->assertSame(Generator::UNDEFINED, $schema->properties[0]->maxItems); - $this->assertSame(10, $schema->properties[0]->minItems); + self::assertSame(Generator::UNDEFINED, $schema->properties[0]->maxItems); + self::assertSame(10, $schema->properties[0]->minItems); } public function provideCountConstraintDoesNotSetMaxItemsIfMaxIsNotSet(): iterable @@ -414,7 +414,7 @@ public function provideCountConstraintDoesNotSetMaxItemsIfMaxIsNotSet(): iterabl /** * @Assert\Count(min = 10) */ - private $property1; + public $property1; }, ]; } @@ -422,7 +422,7 @@ public function provideCountConstraintDoesNotSetMaxItemsIfMaxIsNotSet(): iterabl if (\PHP_VERSION_ID >= 80000) { yield 'Attributes' => [new class() { #[Assert\Count(min: 10)] - private $property1; + public $property1; }]; } } @@ -444,8 +444,8 @@ public function testRangeConstraintDoesNotSetMaximumIfMaxIsNotSet($entity) $symfonyConstraintAnnotationReader->updateProperty(new \ReflectionProperty($entity, 'property1'), $schema->properties[0]); - $this->assertSame(Generator::UNDEFINED, $schema->properties[0]->maximum); - $this->assertSame(10, $schema->properties[0]->minimum); + self::assertSame(Generator::UNDEFINED, $schema->properties[0]->maximum); + self::assertSame(10, $schema->properties[0]->minimum); } public function provideRangeConstraintDoesNotSetMaximumIfMaxIsNotSet(): iterable @@ -456,7 +456,7 @@ public function provideRangeConstraintDoesNotSetMaximumIfMaxIsNotSet(): iterable /** * @Assert\Range(min = 10) */ - private $property1; + public $property1; }, ]; } @@ -464,7 +464,7 @@ public function provideRangeConstraintDoesNotSetMaximumIfMaxIsNotSet(): iterable if (\PHP_VERSION_ID >= 80000) { yield 'Attributes' => [new class() { #[Assert\Range(min: 10)] - private $property1; + public $property1; }]; } } @@ -486,8 +486,8 @@ public function testRangeConstraintDoesNotSetMinimumIfMinIsNotSet($entity) $symfonyConstraintAnnotationReader->updateProperty(new \ReflectionProperty($entity, 'property1'), $schema->properties[0]); - $this->assertSame(Generator::UNDEFINED, $schema->properties[0]->minimum); - $this->assertSame(10, $schema->properties[0]->maximum); + self::assertSame(Generator::UNDEFINED, $schema->properties[0]->minimum); + self::assertSame(10, $schema->properties[0]->maximum); } public function provideRangeConstraintDoesNotSetMinimumIfMinIsNotSet(): iterable @@ -498,7 +498,7 @@ public function provideRangeConstraintDoesNotSetMinimumIfMinIsNotSet(): iterable /** * @Assert\Range(max = 10) */ - private $property1; + public $property1; }, ]; } @@ -506,7 +506,7 @@ public function provideRangeConstraintDoesNotSetMinimumIfMinIsNotSet(): iterable if (\PHP_VERSION_ID >= 80000) { yield 'Attributes' => [new class() { #[Assert\Range(max: 10)] - private $property1; + public $property1; }]; } } @@ -532,7 +532,7 @@ public function testReaderWithValidationGroupsEnabledChecksForDefaultGroupWhenNo $schema->properties[0] ); - $this->assertSame(10, $schema->properties[0]->maximum, 'should have read constraints in the default group'); + self::assertSame(10, $schema->properties[0]->maximum, 'should have read constraints in the default group'); } /** @@ -555,8 +555,8 @@ public function testReaderWithValidationGroupsEnabledDoesNotReadAnnotationsWitho $schema->properties[0] ); - $this->assertSame(['property1'], $schema->required, 'should have read constraint in default group'); - $this->assertSame(Generator::UNDEFINED, $schema->properties[0]->minimum, 'should not have read constraint in other group'); + self::assertSame(['property1'], $schema->required, 'should have read constraint in default group'); + self::assertSame(Generator::UNDEFINED, $schema->properties[0]->minimum, 'should not have read constraint in other group'); } /** @@ -580,8 +580,8 @@ public function testReaderWithValidationGroupsEnabledReadsOnlyConstraintsWithGro ['other'] ); - $this->assertSame(Generator::UNDEFINED, $schema->required, 'should not have read constraint in default group'); - $this->assertSame(1, $schema->properties[0]->minimum, 'should have read constraint in other group'); + self::assertSame(Generator::UNDEFINED, $schema->required, 'should not have read constraint in default group'); + self::assertSame(1, $schema->properties[0]->minimum, 'should have read constraint in other group'); } /** @@ -605,8 +605,8 @@ public function testReaderWithValidationGroupsEnabledCanReadFromMultipleValidati ['other', Constraint::DEFAULT_GROUP] ); - $this->assertSame(['property1'], $schema->required, 'should have read constraint in default group'); - $this->assertSame(1, $schema->properties[0]->minimum, 'should have read constraint in other group'); + self::assertSame(['property1'], $schema->required, 'should have read constraint in default group'); + self::assertSame(1, $schema->properties[0]->minimum, 'should have read constraint in other group'); } public function provideConstraintsWithGroups(): iterable @@ -618,7 +618,7 @@ public function provideConstraintsWithGroups(): iterable * * @Assert\Range(min=1, groups={"other"}) */ - private $property1; + public $property1; }]; } @@ -626,7 +626,7 @@ public function provideConstraintsWithGroups(): iterable yield 'Attributes' => [new class() { #[Assert\NotBlank()] #[Assert\Range(min: 1, groups: ['other'])] - private $property1; + public $property1; }]; } } diff --git a/tests/ModelDescriber/ApplyOpenApiDiscriminatorTraitTest.php b/tests/ModelDescriber/ApplyOpenApiDiscriminatorTraitTest.php index 20fb7582b..cce5d45e7 100644 --- a/tests/ModelDescriber/ApplyOpenApiDiscriminatorTraitTest.php +++ b/tests/ModelDescriber/ApplyOpenApiDiscriminatorTraitTest.php @@ -43,15 +43,15 @@ public function testApplyAddsDiscriminatorProperty() 'two' => 'SecondType', ]); - $this->assertInstanceOf(OA\Discriminator::class, $this->schema->discriminator); - $this->assertSame('type', $this->schema->discriminator->propertyName); - $this->assertArrayHasKey('one', $this->schema->discriminator->mapping); - $this->assertSame( + self::assertInstanceOf(OA\Discriminator::class, $this->schema->discriminator); + self::assertSame('type', $this->schema->discriminator->propertyName); + self::assertArrayHasKey('one', $this->schema->discriminator->mapping); + self::assertSame( $this->modelRegistry->register($this->createModel('FirstType')), $this->schema->discriminator->mapping['one'] ); - $this->assertArrayHasKey('two', $this->schema->discriminator->mapping); - $this->assertSame( + self::assertArrayHasKey('two', $this->schema->discriminator->mapping); + self::assertSame( $this->modelRegistry->register($this->createModel('SecondType')), $this->schema->discriminator->mapping['two'] ); @@ -64,13 +64,13 @@ public function testApplyAddsOneOfFieldToSchema() 'two' => 'SecondType', ]); - $this->assertNotSame(Generator::UNDEFINED, $this->schema->oneOf); - $this->assertCount(2, $this->schema->oneOf); - $this->assertSame( + self::assertNotSame(Generator::UNDEFINED, $this->schema->oneOf); + self::assertCount(2, $this->schema->oneOf); + self::assertSame( $this->modelRegistry->register($this->createModel('FirstType')), $this->schema->oneOf[0]->ref ); - $this->assertSame( + self::assertSame( $this->modelRegistry->register($this->createModel('SecondType')), $this->schema->oneOf[1]->ref ); diff --git a/tests/ModelDescriber/FormModelDescriberTest.php b/tests/ModelDescriber/FormModelDescriberTest.php index e0f6e2f32..928f225e3 100644 --- a/tests/ModelDescriber/FormModelDescriberTest.php +++ b/tests/ModelDescriber/FormModelDescriberTest.php @@ -33,20 +33,27 @@ class FormModelDescriberTest extends TestCase public function testDescribeCreatesTokenPropertyDependingOnOptions(bool $csrfProtectionEnabled, string $tokenName, bool $expectProperty): void { $formConfigMock = $this->createMock(FormConfigInterface::class); - $formConfigMock->expects($this->exactly($csrfProtectionEnabled ? 2 : 1)) + $formConfigMock->expects(self::exactly($csrfProtectionEnabled ? 2 : 1)) ->method('getOption') - ->willReturnMap([ - ['csrf_protection', false, $csrfProtectionEnabled], - ['csrf_field_name', null, $tokenName], - ]); + ->willReturnCallback(function (string $option, $default) use ($csrfProtectionEnabled, $tokenName) { + if ('csrf_protection' === $option) { + return $csrfProtectionEnabled; + } + + if ('csrf_field_name' === $option) { + return $tokenName; + } + + return $default; + }); $formMock = $this->createMock(FormInterface::class); - $formMock->expects($this->exactly($csrfProtectionEnabled ? 2 : 1)) + $formMock->expects(self::exactly($csrfProtectionEnabled ? 2 : 1)) ->method('getConfig') ->willReturn($formConfigMock); $formFactoryMock = $this->createMock(FormFactoryInterface::class); - $formFactoryMock->expects($this->once()) + $formFactoryMock->expects(self::once()) ->method('create') ->willReturn($formMock); @@ -67,9 +74,9 @@ public function testDescribeCreatesTokenPropertyDependingOnOptions(bool $csrfPro return $property->property === $tokenName; }); - $this->assertCount(1, $filteredProperties); + self::assertCount(1, $filteredProperties); } else { - $this->assertSame(Generator::UNDEFINED, $schema->properties); + self::assertSame(Generator::UNDEFINED, $schema->properties); } } diff --git a/tests/ModelDescriber/SelfDescribingModelDescriberTest.php b/tests/ModelDescriber/SelfDescribingModelDescriberTest.php index 38decbe68..102045b9b 100644 --- a/tests/ModelDescriber/SelfDescribingModelDescriberTest.php +++ b/tests/ModelDescriber/SelfDescribingModelDescriberTest.php @@ -24,14 +24,14 @@ public function testSupports() { $describer = new SelfDescribingModelDescriber(); - $this->assertTrue($describer->supports(new Model(new Type('object', false, SelfDescribingModel::class)))); + self::assertTrue($describer->supports(new Model(new Type('object', false, SelfDescribingModel::class)))); } public function testDoesNotSupport() { $describer = new SelfDescribingModelDescriber(); - $this->assertFalse($describer->supports(new Model(new Type('object', false, \stdClass::class)))); + self::assertFalse($describer->supports(new Model(new Type('object', false, \stdClass::class)))); } public function testDescribe() @@ -42,7 +42,7 @@ public function testDescribe() $schema = new Schema([]); $describer->describe($model, $schema); - $this->assertSame('SelfDescribingTitle', $schema->title); - $this->assertSame(SelfDescribingModel::class, $schema->description); + self::assertSame('SelfDescribingTitle', $schema->title); + self::assertSame(SelfDescribingModel::class, $schema->description); } } diff --git a/tests/Render/Html/GetNelmioAssetTest.php b/tests/Render/Html/GetNelmioAssetTest.php index 3ba8f91e8..0c77116fb 100644 --- a/tests/Render/Html/GetNelmioAssetTest.php +++ b/tests/Render/Html/GetNelmioAssetTest.php @@ -14,7 +14,6 @@ use Nelmio\ApiDocBundle\Render\Html\AssetsMode; use Nelmio\ApiDocBundle\Render\Html\GetNelmioAsset; use Nelmio\ApiDocBundle\Tests\Functional\WebTestCase; -use Twig\TwigFunction; class GetNelmioAssetTest extends WebTestCase { @@ -24,8 +23,10 @@ public function test($mode, $asset, $expectedContent) static::bootKernel(); /** @var GetNelmioAsset $getNelmioAsset */ $getNelmioAsset = static::getContainer()->get('nelmio_api_doc.render_docs.html.asset'); - /** @var TwigFunction */ + $twigFunction = $getNelmioAsset->getFunctions()[0]; + + self::assertInstanceOf(GetNelmioAsset::class, $twigFunction->getCallable()); self::assertSame($expectedContent, $twigFunction->getCallable()->__invoke($mode, $asset)); } diff --git a/tests/Render/RenderOpenApiTest.php b/tests/Render/RenderOpenApiTest.php index c8d6cc164..5e259abf7 100644 --- a/tests/Render/RenderOpenApiTest.php +++ b/tests/Render/RenderOpenApiTest.php @@ -27,7 +27,7 @@ public function testRender() { $openApiRenderer = $this->createMock(OpenApiRenderer::class); $openApiRenderer->method('getFormat')->willReturn($this->format); - $openApiRenderer->expects($this->once())->method('render'); + $openApiRenderer->expects(self::once())->method('render'); $this->renderOpenApi($openApiRenderer); } @@ -49,7 +49,7 @@ public function testNullFormat() { $openApiRenderer = $this->createMock(OpenApiRenderer::class); $openApiRenderer->method('getFormat')->willReturn($this->format); - $openApiRenderer->expects($this->once())->method('render'); + $openApiRenderer->expects(self::once())->method('render'); $availableOpenApiRenderers = [ $openApiRenderer, diff --git a/tests/RouteDescriber/FosRestDescriberTest.php b/tests/RouteDescriber/FosRestDescriberTest.php index 5d94b7b42..09f7d9322 100644 --- a/tests/RouteDescriber/FosRestDescriberTest.php +++ b/tests/RouteDescriber/FosRestDescriberTest.php @@ -25,7 +25,11 @@ class FosRestDescriberTest extends TestCase public function testQueryParamWithChoiceConstraintIsAddedAsEnum() { if (Kernel::MAJOR_VERSION >= 7) { - $this->markTestSkipped('FosRest is not supported in symfony 7'); + self::markTestSkipped('FosRest is not supported in symfony 7'); + } + + if (!class_exists(QueryParam::class)) { + self::markTestSkipped('FOSRestBundle is not installed'); } $choices = ['foo', 'bar']; @@ -50,6 +54,6 @@ public function testQueryParamWithChoiceConstraintIsAddedAsEnum() $this->createMock(\ReflectionMethod::class) ); - $this->assertSame($choices, $api->paths[0]->get->parameters[0]->schema->enum); + self::assertSame($choices, $api->paths[0]->get->parameters[0]->schema->enum); } } diff --git a/tests/RouteDescriber/RouteMetadataDescriberTest.php b/tests/RouteDescriber/RouteMetadataDescriberTest.php index c8f61b98d..0940b93f6 100644 --- a/tests/RouteDescriber/RouteMetadataDescriberTest.php +++ b/tests/RouteDescriber/RouteMetadataDescriberTest.php @@ -24,7 +24,7 @@ public function testUndefinedCheck() { $routeDescriber = new RouteMetadataDescriber(); - $this->assertNull($routeDescriber->describe(new OpenApi(['_context' => new Context()]), new Route('foo'), new \ReflectionMethod(__CLASS__, 'testUndefinedCheck'))); + self::assertNull($routeDescriber->describe(new OpenApi(['_context' => new Context()]), new Route('foo'), new \ReflectionMethod(__CLASS__, 'testUndefinedCheck'))); } public function testRouteRequirementsWithPattern() @@ -38,13 +38,13 @@ public function testRouteRequirementsWithPattern() new \ReflectionMethod(__CLASS__, 'testRouteRequirementsWithPattern') ); - $this->assertEquals('/index/{bar}/{foo}.html', $api->paths[0]->path); + self::assertEquals('/index/{bar}/{foo}.html', $api->paths[0]->path); $getPathParameter = $api->paths[0]->get->parameters[1]; if ('foo' === $getPathParameter->name) { - $this->assertEquals('path', $getPathParameter->in); - $this->assertEquals('foo', $getPathParameter->name); - $this->assertEquals('string', $getPathParameter->schema->type); - $this->assertEquals('[0-9]|[a-z]', $getPathParameter->schema->pattern); + self::assertEquals('path', $getPathParameter->in); + self::assertEquals('foo', $getPathParameter->name); + self::assertEquals('string', $getPathParameter->schema->type); + self::assertEquals('[0-9]|[a-z]', $getPathParameter->schema->pattern); } } @@ -62,13 +62,13 @@ public function testSimpleOrRequirementsAreHandledAsEnums($req) new \ReflectionMethod(__CLASS__, 'testSimpleOrRequirementsAreHandledAsEnums') ); - $this->assertEquals('/index/{bar}/{foo}.html', $api->paths[0]->path); + self::assertEquals('/index/{bar}/{foo}.html', $api->paths[0]->path); $getPathParameter = $api->paths[0]->get->parameters[1]; - $this->assertEquals('path', $getPathParameter->in); - $this->assertEquals('foo', $getPathParameter->name); - $this->assertEquals('string', $getPathParameter->schema->type); - $this->assertEquals(explode('|', $req), $getPathParameter->schema->enum); - $this->assertEquals($req, $getPathParameter->schema->pattern); + self::assertEquals('path', $getPathParameter->in); + self::assertEquals('foo', $getPathParameter->name); + self::assertEquals('string', $getPathParameter->schema->type); + self::assertEquals(explode('|', $req), $getPathParameter->schema->enum); + self::assertEquals($req, $getPathParameter->schema->pattern); } /** @@ -86,8 +86,8 @@ public function testNonEnumPatterns($pattern) ); $getPathParameter = $api->paths[0]->get->parameters[0]; - $this->assertEquals($pattern, $getPathParameter->schema->pattern); - $this->assertEquals(Generator::UNDEFINED, $getPathParameter->schema->enum); + self::assertEquals($pattern, $getPathParameter->schema->pattern); + self::assertEquals(Generator::UNDEFINED, $getPathParameter->schema->enum); } public function provideEnumPattern() diff --git a/tests/Routing/FilteredRouteCollectionBuilderTest.php b/tests/Routing/FilteredRouteCollectionBuilderTest.php index 132c4f4fc..557f97dfa 100644 --- a/tests/Routing/FilteredRouteCollectionBuilderTest.php +++ b/tests/Routing/FilteredRouteCollectionBuilderTest.php @@ -20,7 +20,6 @@ use OpenApi\Annotations\Parameter; use OpenApi\Context; use PHPUnit\Framework\TestCase; -use Symfony\Bundle\FrameworkBundle\Controller\ControllerNameParser; use Symfony\Component\DependencyInjection\Container; use Symfony\Component\OptionsResolver\Exception\InvalidArgumentException; use Symfony\Component\Routing\Route; @@ -67,7 +66,7 @@ public function testFilter() ); $filteredRoutes = $routeBuilder->filter($routes); - $this->assertCount(4, $filteredRoutes); + self::assertCount(4, $filteredRoutes); } /** @@ -95,7 +94,7 @@ public function testFilterWithDeprecatedArgument() ); $filteredRoutes = $routeBuilder->filter($routes); - $this->assertCount(5, $filteredRoutes); + self::assertCount(5, $filteredRoutes); } /** @@ -166,7 +165,7 @@ public function testMatchingRoutes(string $name, Route $route, array $options = ); $filteredRoutes = $routeBuilder->filter($routes); - $this->assertCount(1, $filteredRoutes); + self::assertCount(1, $filteredRoutes); } public function getMatchingRoutes(): iterable @@ -218,7 +217,7 @@ public function testMatchingRoutesWithAnnotation(string $name, Route $route, arr ); $filteredRoutes = $routeBuilder->filter($routes); - $this->assertCount(1, $filteredRoutes); + self::assertCount(1, $filteredRoutes); } public function getMatchingRoutesWithAnnotation(): iterable @@ -268,7 +267,7 @@ public function testNonMatchingRoutes(string $name, Route $route, array $options ); $filteredRoutes = $routeBuilder->filter($routes); - $this->assertCount(0, $filteredRoutes); + self::assertCount(0, $filteredRoutes); } public function getNonMatchingRoutes(): array @@ -321,7 +320,7 @@ public function testRoutesWithDisabledDefaultRoutes( ); $filteredRoutes = $routeBuilder->filter($routes); - $this->assertCount($expectedRoutesCount, $filteredRoutes); + self::assertCount($expectedRoutesCount, $filteredRoutes); } /** @@ -356,13 +355,6 @@ public function getRoutesWithDisabledDefaultRoutes(): array private function createControllerReflector(): ControllerReflector { - if (class_exists(ControllerNameParser::class)) { - return new ControllerReflector( - new Container(), - $this->createMock(ControllerNameParser::class) - ); - } - return new ControllerReflector(new Container()); } } diff --git a/tests/SwaggerPhp/UtilTest.php b/tests/SwaggerPhp/UtilTest.php index 6eed5867a..05e4f0659 100644 --- a/tests/SwaggerPhp/UtilTest.php +++ b/tests/SwaggerPhp/UtilTest.php @@ -65,22 +65,22 @@ public function testCreateContextWithProperties() { $context = Util::createContext(['testing' => 'trait']); - $this->assertTrue($context->is('testing')); - $this->assertSame('trait', $context->testing); + self::assertTrue($context->is('testing')); + self::assertSame('trait', $context->testing); } public function testCreateChild() { $info = Util::createChild($this->rootAnnotation, OA\Info::class); - $this->assertInstanceOf(OA\Info::class, $info); + self::assertInstanceOf(OA\Info::class, $info); } public function testCreateChildHasContext() { $info = Util::createChild($this->rootAnnotation, OA\Info::class); - $this->assertInstanceOf(Context::class, $info->_context); + self::assertInstanceOf(Context::class, $info->_context); } public function testCreateChildHasNestedContext() @@ -107,7 +107,7 @@ public function testCreateChildWithEmptyProperties() return 0 !== \strpos($key, '_'); }, ARRAY_FILTER_USE_KEY); - $this->assertEquals([Generator::UNDEFINED], array_unique(array_values($properties))); + self::assertEquals([Generator::UNDEFINED], array_unique(array_values($properties))); $this->assertIsNested($this->rootAnnotation, $info); $this->assertIsConnectedToRootContext($info); @@ -119,9 +119,9 @@ public function testCreateChildWithProperties() /** @var OA\Info $info */ $info = Util::createChild($this->rootAnnotation, OA\Info::class, $properties); - $this->assertSame($info->title, $properties['title']); - $this->assertSame($info->version, $properties['version']); - $this->assertSame($info->x, $properties['x']); + self::assertSame($info->title, $properties['title']); + self::assertSame($info->version, $properties['version']); + self::assertSame($info->x, $properties['x']); $this->assertIsNested($this->rootAnnotation, $info); $this->assertIsConnectedToRootContext($info); @@ -133,16 +133,16 @@ public function testCreateCollectionItemAddsCreatedItemToCollection() $class = OA\PathItem::class; $p1 = Util::createCollectionItem($this->rootAnnotation, $collection, $class); - $this->assertSame(0, $p1); - $this->assertCount(1, $this->rootAnnotation->{$collection}); - $this->assertInstanceOf($class, $this->rootAnnotation->{$collection}[$p1]); + self::assertSame(0, $p1); + self::assertCount(1, $this->rootAnnotation->{$collection}); + self::assertInstanceOf($class, $this->rootAnnotation->{$collection}[$p1]); $this->assertIsNested($this->rootAnnotation, $this->rootAnnotation->{$collection}[$p1]); $this->assertIsConnectedToRootContext($this->rootAnnotation->{$collection}[$p1]); $p2 = Util::createCollectionItem($this->rootAnnotation, $collection, $class); - $this->assertSame(1, $p2); - $this->assertCount(2, $this->rootAnnotation->{$collection}); - $this->assertInstanceOf($class, $this->rootAnnotation->{$collection}[$p2]); + self::assertSame(1, $p2); + self::assertCount(2, $this->rootAnnotation->{$collection}); + self::assertInstanceOf($class, $this->rootAnnotation->{$collection}[$p2]); $this->assertIsNested($this->rootAnnotation, $this->rootAnnotation->{$collection}[$p2]); $this->assertIsConnectedToRootContext($this->rootAnnotation->{$collection}[$p2]); @@ -152,9 +152,9 @@ public function testCreateCollectionItemAddsCreatedItemToCollection() $class = OA\Schema::class; $d1 = Util::createCollectionItem($this->rootAnnotation->components, $collection, $class); - $this->assertSame(0, $d1); - $this->assertCount(1, $this->rootAnnotation->components->{$collection}); - $this->assertInstanceOf($class, $this->rootAnnotation->components->{$collection}[$d1]); + self::assertSame(0, $d1); + self::assertCount(1, $this->rootAnnotation->components->{$collection}); + self::assertInstanceOf($class, $this->rootAnnotation->components->{$collection}[$d1]); $this->assertIsNested($this->rootAnnotation->components, $this->rootAnnotation->components->{$collection}[$d1]); $this->assertIsConnectedToRootContext($this->rootAnnotation->components->{$collection}[$d1]); } @@ -164,13 +164,18 @@ public function testCreateCollectionItemDoesNotAddToUnknownProperty() $collection = 'foobars'; $class = OA\Info::class; - $expectedRegex = "/Property \"{$collection}\" doesn't exist .*/"; - set_error_handler(function ($_, $err) { echo $err; }); - $this->expectOutputRegex($expectedRegex); - Util::createCollectionItem($this->rootAnnotation, $collection, $class); - $this->expectOutputRegex($expectedRegex); - $this->assertNull($this->rootAnnotation->{$collection}); - restore_error_handler(); + $expectedRegex = "/Property \"foobars\" doesn't exist .*/"; + try { + Util::createCollectionItem($this->rootAnnotation, $collection, $class); + } catch (\Exception $e) { + self::assertMatchesRegularExpression($expectedRegex, $e->getMessage()); + } + + try { + self::assertNull($this->rootAnnotation->{$collection}); /* @phpstan-ignore-line */ + } catch (\Exception $e) { + self::assertMatchesRegularExpression($expectedRegex, $e->getMessage()); + } } public function testSearchCollectionItem() @@ -190,25 +195,24 @@ public function testSearchCollectionItem() $item2, ]; - $this->assertSame(0, Util::searchCollectionItem($collection, \get_object_vars($item1))); - $this->assertSame(1, Util::searchCollectionItem($collection, \get_object_vars($item2))); + self::assertSame(0, Util::searchCollectionItem($collection, \get_object_vars($item1))); + self::assertSame(1, Util::searchCollectionItem($collection, \get_object_vars($item2))); - $this->assertNull(Util::searchCollectionItem( + self::assertNull(Util::searchCollectionItem( $collection, array_merge(\get_object_vars($item2), ['prop3' => 'foobar']) )); $search = ['baz' => 'foobar']; - $this->expectOutputString('Undefined property: stdClass::$baz'); try { Util::searchCollectionItem($collection, array_merge(\get_object_vars($item2), $search)); } catch (\Exception $e) { - echo $e->getMessage(); + self::assertSame('Undefined property: stdClass::$baz', $e->getMessage()); } // no exception on empty collection - $this->assertNull(Util::searchCollectionItem([], \get_object_vars($item2))); + self::assertNull(Util::searchCollectionItem([], \get_object_vars($item2))); } /** @@ -218,7 +222,7 @@ public function testSearchIndexedCollectionItem($setup, $asserts) { foreach ($asserts as $collection => $items) { foreach ($items as $assert) { - $setupCollection = empty($assert['components']) ? + $setupCollection = !isset($assert['components']) ? ($setup[$collection] ?? []) : (Generator::UNDEFINED !== $setup['components']->{$collection} ? $setup['components']->{$collection} : []); @@ -233,7 +237,7 @@ public function testSearchIndexedCollectionItem($setup, $asserts) ]); } - $this->assertSame( + self::assertSame( $assert['index'], Util::searchIndexedCollectionItem($properties, $assert['key'], $assert['value']), sprintf('Failed to get the correct index for %s', print_r($assert, true)) @@ -254,7 +258,7 @@ public function testGetIndexedCollectionItem($setup, $asserts) foreach ($asserts as $collection => $items) { foreach ($items as $assert) { - $itemParent = empty($assert['components']) ? $parent : $parent->components; + $itemParent = !isset($assert['components']) ? $parent : $parent->components; $child = Util::getIndexedCollectionItem( $itemParent, @@ -262,14 +266,14 @@ public function testGetIndexedCollectionItem($setup, $asserts) $assert['value'] ); - $this->assertInstanceOf($assert['class'], $child); - $this->assertSame($child->{$assert['key']}, $assert['value']); - $this->assertSame( + self::assertInstanceOf($assert['class'], $child); + self::assertSame($child->{$assert['key']}, $assert['value']); + self::assertSame( $itemParent->{$collection}[$assert['index']], $child ); - $setupHaystack = empty($assert['components']) ? + $setupHaystack = !isset($assert['components']) ? $setup[$collection] ?? [] : $setup['components']->{$collection} ?? []; @@ -384,14 +388,14 @@ public function testGetChild($setup, $asserts) } $child = Util::getChild($parent, $assert['class'], $assert['props']); - $this->assertInstanceOf($assert['class'], $child); - $this->assertSame($child, $parent->{$key}); + self::assertInstanceOf($assert['class'], $child); + self::assertSame($child, $parent->{$key}); if (\array_key_exists($key, $setup)) { - $this->assertSame($setup[$key], $parent->{$key}); + self::assertSame($setup[$key], $parent->{$key}); } - $this->assertEquals($assert['props'], $this->getNonDefaultProperties($child)); + self::assertEquals($assert['props'], $this->getNonDefaultProperties($child)); } } @@ -470,7 +474,7 @@ public function testGetOperationParameterReturnsExisting() ]]); $actual = Util::getOperationParameter($operation, $name, $in); - $this->assertSame($parameter, $actual); + self::assertSame($parameter, $actual); } public function testGetOperationParameterCreatesWithNameAndIn() @@ -487,9 +491,8 @@ public function testGetOperationParameterCreatesWithNameAndIn() ]]); $actual = Util::getOperationParameter($operation, $name, $in); - $this->assertInstanceOf(OA\Parameter::class, $actual); - $this->assertSame($name, $actual->name); - $this->assertSame($in, $actual->in); + self::assertSame($name, $actual->name); + self::assertSame($in, $actual->in); } public function testGetOperationReturnsExisting() @@ -497,7 +500,7 @@ public function testGetOperationReturnsExisting() $get = $this->createObj(OA\Get::class, []); $path = $this->createObj(OA\PathItem::class, ['get' => $get]); - $this->assertSame($get, Util::getOperation($path, 'get')); + self::assertSame($get, Util::getOperation($path, 'get')); } public function testGetOperationCreatesWithPath() @@ -506,8 +509,8 @@ public function testGetOperationCreatesWithPath() $path = $this->createObj(OA\PathItem::class, ['path' => $pathStr]); $get = Util::getOperation($path, 'get'); - $this->assertInstanceOf(OA\Get::class, $get); - $this->assertSame($pathStr, $get->path); + self::assertInstanceOf(OA\Get::class, $get); + self::assertSame($pathStr, $get->path); } public function testMergeWithEmptyArray() @@ -518,12 +521,12 @@ public function testMergeWithEmptyArray() Util::merge($api, [], false); $actual = json_encode($api); - $this->assertSame($expected, $actual); + self::assertSame($expected, $actual); Util::merge($api, [], true); $actual = json_encode($api); - $this->assertSame($expected, $actual); + self::assertSame($expected, $actual); } /** @@ -534,10 +537,10 @@ public function testMerge($setup, $merge, $assert) $api = $this->createObj(OA\OpenApi::class, $setup + ['_context' => new Context()]); Util::merge($api, $merge, false); - $this->assertTrue($api->validate()); + self::assertTrue($api->validate()); $actual = json_decode(json_encode($api), true); - $this->assertEquals($assert, $actual); + self::assertEquals($assert, $actual); } public function provideMergeData(): array @@ -842,7 +845,7 @@ public function assertIsConnectedToRootContext(OA\AbstractAnnotation $annotation public function assertContextIsConnectedToRootContext(Context $context) { - $this->assertSame($this->rootContext, $context->root()); + self::assertSame($this->rootContext, $context->root()); } private function getSetupPropertiesWithoutClass(array $setup) diff --git a/tests/Util/ControllerReflectorTest.php b/tests/Util/ControllerReflectorTest.php index 7abb6b076..36e204e4e 100644 --- a/tests/Util/ControllerReflectorTest.php +++ b/tests/Util/ControllerReflectorTest.php @@ -21,17 +21,17 @@ class ControllerReflectorTest extends TestCase public function testGetReflectionMethod(): void { $controllerReflector = new ControllerReflector(new Container()); - $this->assertEquals( + self::assertEquals( \ReflectionMethod::class, get_class($controllerReflector->getReflectionMethod([BazingaController::class, 'userAction'])) ); - $this->assertEquals( + self::assertEquals( \ReflectionMethod::class, get_class($controllerReflector->getReflectionMethod(BazingaController::class.'::userAction')) ); - $this->assertNull( + self::assertNull( $controllerReflector->getReflectionMethod('UnknownController::userAction') ); - $this->assertNull($controllerReflector->getReflectionMethod(null)); + self::assertNull($controllerReflector->getReflectionMethod(null)); } } diff --git a/tests/console-application.php b/tests/console-application.php new file mode 100644 index 000000000..d87aa6902 --- /dev/null +++ b/tests/console-application.php @@ -0,0 +1,34 @@ +