From e159b3ec59ade2b45a54003cea3d4a013c26e79a Mon Sep 17 00:00:00 2001 From: Vincent Langlet Date: Sat, 28 Jun 2025 00:01:57 +0200 Subject: [PATCH] chore: use treat phpdoc type as certain --- phpstan.neon.dist | 5 +---- src/Doctrine/Odm/State/LinksHandlerTrait.php | 5 ----- .../Property/DoctrineOrmPropertyMetadataFactory.php | 2 +- src/Doctrine/Orm/State/CollectionProvider.php | 2 +- src/Doctrine/Orm/State/ItemProvider.php | 2 +- src/Elasticsearch/State/ItemProvider.php | 5 ++--- src/Metadata/ApiResource.php | 2 +- src/Metadata/Tests/Resource/OperationTest.php | 2 +- src/OpenApi/Factory/OpenApiFactory.php | 6 +++--- src/Serializer/AbstractItemNormalizer.php | 2 +- src/Serializer/Tests/AbstractItemNormalizerTest.php | 2 +- src/State/Provider/DeserializeProvider.php | 2 +- .../Bundle/DependencyInjection/ApiPlatformExtension.php | 1 - src/Symfony/Controller/MainController.php | 2 +- src/Symfony/EventListener/DeserializeListener.php | 3 +-- src/Symfony/EventListener/ReadListener.php | 3 +-- src/Symfony/EventListener/WriteListener.php | 3 +-- 17 files changed, 18 insertions(+), 31 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index dbfe3153b84..767d5b0293f 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -5,6 +5,7 @@ parameters: - tests - tests/Fixtures/app/console inferPrivatePropertyTypeFromConstructor: true + treatPhpDocTypesAsCertain: false symfony: containerXmlPath: tests/Fixtures/app/var/cache/test/AppKernelTestDebugContainer.xml constantHassers: false @@ -112,11 +113,7 @@ parameters: identifier: void.pure - identifier: varTag.nativeType - - - identifier: isset.offset - identifier: trait.unused - - - identifier: instanceof.alwaysTrue - identifier: catch.neverThrown diff --git a/src/Doctrine/Odm/State/LinksHandlerTrait.php b/src/Doctrine/Odm/State/LinksHandlerTrait.php index 764a692cf21..215f0cbb899 100644 --- a/src/Doctrine/Odm/State/LinksHandlerTrait.php +++ b/src/Doctrine/Odm/State/LinksHandlerTrait.php @@ -20,7 +20,6 @@ use ApiPlatform\State\Util\StateOptionsTrait; use Doctrine\ODM\MongoDB\Aggregation\Builder; use Doctrine\ODM\MongoDB\DocumentManager; -use Doctrine\ODM\MongoDB\Mapping\ClassMetadata; use Doctrine\Persistence\ManagerRegistry; /** @@ -94,10 +93,6 @@ private function buildAggregation(string $toClass, array $links, array $identifi $classMetadata = $manager->getClassMetadata($aggregationClass); - if (!$classMetadata instanceof ClassMetadata) { - throw new RuntimeException(\sprintf('The class metadata for "%s" must be an instance of "%s".', $aggregationClass, ClassMetadata::class)); - } - $aggregation = $previousAggregationBuilder; if ($aggregationClass !== $previousAggregationClass) { $aggregation = $manager->createAggregationBuilder($aggregationClass); diff --git a/src/Doctrine/Orm/Metadata/Property/DoctrineOrmPropertyMetadataFactory.php b/src/Doctrine/Orm/Metadata/Property/DoctrineOrmPropertyMetadataFactory.php index c450e85c1d8..1b6b75dc62d 100644 --- a/src/Doctrine/Orm/Metadata/Property/DoctrineOrmPropertyMetadataFactory.php +++ b/src/Doctrine/Orm/Metadata/Property/DoctrineOrmPropertyMetadataFactory.php @@ -70,7 +70,7 @@ public function create(string $resourceClass, string $property, array $options = if ($doctrineClassMetadata instanceof ClassMetadata && \in_array($property, $doctrineClassMetadata->getFieldNames(), true)) { $fieldMapping = $doctrineClassMetadata->getFieldMapping($property); - if (class_exists(FieldMapping::class) && $fieldMapping instanceof FieldMapping) { + if (class_exists(FieldMapping::class)) { $propertyMetadata = $propertyMetadata->withDefault($fieldMapping->default ?? $propertyMetadata->getDefault()); } else { $propertyMetadata = $propertyMetadata->withDefault($fieldMapping['options']['default'] ?? $propertyMetadata->getDefault()); diff --git a/src/Doctrine/Orm/State/CollectionProvider.php b/src/Doctrine/Orm/State/CollectionProvider.php index d67f7fe4431..3815447a8d3 100644 --- a/src/Doctrine/Orm/State/CollectionProvider.php +++ b/src/Doctrine/Orm/State/CollectionProvider.php @@ -56,7 +56,7 @@ public function provide(Operation $operation, array $uriVariables = [], array $c $manager = $this->managerRegistry->getManagerForClass($entityClass); $repository = $manager->getRepository($entityClass); - if (!method_exists($repository, 'createQueryBuilder')) { // @phpstan-ignore-line function.alreadyNarrowedType + if (!method_exists($repository, 'createQueryBuilder')) { throw new RuntimeException('The repository class must have a "createQueryBuilder" method.'); } diff --git a/src/Doctrine/Orm/State/ItemProvider.php b/src/Doctrine/Orm/State/ItemProvider.php index f69a208c7a4..b201d03b7d0 100644 --- a/src/Doctrine/Orm/State/ItemProvider.php +++ b/src/Doctrine/Orm/State/ItemProvider.php @@ -65,7 +65,7 @@ public function provide(Operation $operation, array $uriVariables = [], array $c } $repository = $manager->getRepository($entityClass); - if (!method_exists($repository, 'createQueryBuilder')) { // @phpstan-ignore-line function.alreadyNarrowedType + if (!method_exists($repository, 'createQueryBuilder')) { throw new RuntimeException('The repository class must have a "createQueryBuilder" method.'); } diff --git a/src/Elasticsearch/State/ItemProvider.php b/src/Elasticsearch/State/ItemProvider.php index d21e45a8e0a..49158ae547e 100644 --- a/src/Elasticsearch/State/ItemProvider.php +++ b/src/Elasticsearch/State/ItemProvider.php @@ -14,7 +14,6 @@ namespace ApiPlatform\Elasticsearch\State; use ApiPlatform\Elasticsearch\Serializer\DocumentNormalizer; -use ApiPlatform\Metadata\Exception\RuntimeException; use ApiPlatform\Metadata\InflectorInterface; use ApiPlatform\Metadata\Operation; use ApiPlatform\Metadata\Util\Inflector; @@ -49,9 +48,9 @@ public function __construct( public function provide(Operation $operation, array $uriVariables = [], array $context = []): ?object { $resourceClass = $operation->getClass(); - $options = $operation->getStateOptions() instanceof Options ? $operation->getStateOptions() : new Options(index: $this->getIndex($operation)); + $options = $operation->getStateOptions(); if (!$options instanceof Options) { - throw new RuntimeException(\sprintf('The "%s" provider was called without "%s".', self::class, Options::class)); + $options = new Options(index: $this->getIndex($operation)); } $params = [ diff --git a/src/Metadata/ApiResource.php b/src/Metadata/ApiResource.php index e85a996e14c..8fd24f20114 100644 --- a/src/Metadata/ApiResource.php +++ b/src/Metadata/ApiResource.php @@ -1026,7 +1026,7 @@ class: $class, } /** - * @return Operations + * @return Operations|null */ public function getOperations(): ?Operations { diff --git a/src/Metadata/Tests/Resource/OperationTest.php b/src/Metadata/Tests/Resource/OperationTest.php index c2d9e87a0e7..0d115fa76e2 100644 --- a/src/Metadata/Tests/Resource/OperationTest.php +++ b/src/Metadata/Tests/Resource/OperationTest.php @@ -36,7 +36,7 @@ public function testWithResourceTrait(): void $this->assertSame($operation->getShortName(), 'test'); $this->assertSame($operation->canRead(), false); - $this->assertSame($operation instanceof CollectionOperationInterface, true); + $this->assertInstanceOf(CollectionOperationInterface::class, $operation); } #[\PHPUnit\Framework\Attributes\DataProvider('operationProvider')] diff --git a/src/OpenApi/Factory/OpenApiFactory.php b/src/OpenApi/Factory/OpenApiFactory.php index 4a6f4ba658d..d7d3750523c 100644 --- a/src/OpenApi/Factory/OpenApiFactory.php +++ b/src/OpenApi/Factory/OpenApiFactory.php @@ -186,7 +186,7 @@ private function collectPaths(ApiResource $resource, ResourceMetadataCollection $openapiAttribute = $operation->getOpenapi(); // Operation ignored from OpenApi - if ($operation instanceof HttpOperation && false === $openapiAttribute) { + if (false === $openapiAttribute) { continue; } @@ -386,7 +386,7 @@ private function collectPaths(ApiResource $resource, ResourceMetadataCollection $existingResponses = $openapiOperation->getResponses() ?: []; $overrideResponses = $operation->getExtraProperties()[self::OVERRIDE_OPENAPI_RESPONSES] ?? $this->openApiOptions->getOverrideResponses(); $errors = null; - if ($operation instanceof HttpOperation && null !== ($errors = $operation->getErrors())) { + if (null !== ($errors = $operation->getErrors())) { /** @var array */ $errorOperations = []; foreach ($errors as $error) { @@ -629,7 +629,7 @@ private function getLinks(ResourceMetadataCollection $resourceMetadataCollection } // Operation ignored from OpenApi - if ($operation instanceof HttpOperation && (false === $operation->getOpenapi() || $operation->getOpenapi() instanceof Webhook)) { + if (false === $operation->getOpenapi() || $operation->getOpenapi() instanceof Webhook) { continue; } diff --git a/src/Serializer/AbstractItemNormalizer.php b/src/Serializer/AbstractItemNormalizer.php index 796f7011419..9767e1f0008 100644 --- a/src/Serializer/AbstractItemNormalizer.php +++ b/src/Serializer/AbstractItemNormalizer.php @@ -909,7 +909,7 @@ protected function getAttributeValue(object $object, string $attribute, ?string $data = $this->normalizeCollectionOfRelations($propertyMetadata, $attributeValue, $resourceClass, $format, $childContext); $context['data'] = $data; - $context['type'] = ($nullable && $type instanceof Type) ? Type::nullable($type) : $type; + $context['type'] = $nullable ? Type::nullable($type) : $type; if ($this->tagCollector) { $this->tagCollector->collect($context); diff --git a/src/Serializer/Tests/AbstractItemNormalizerTest.php b/src/Serializer/Tests/AbstractItemNormalizerTest.php index 7c9467250ef..950b277a938 100644 --- a/src/Serializer/Tests/AbstractItemNormalizerTest.php +++ b/src/Serializer/Tests/AbstractItemNormalizerTest.php @@ -1204,7 +1204,7 @@ public function testDeserializationPathForNotDenormalizableRelations(): void $errors = []; $actual = $normalizer->denormalize($data, Dummy::class, null, ['not_normalizable_value_exceptions' => &$errors]); $this->assertEmpty($actual->relatedDummies); - $this->assertCount(1, $errors); // @phpstan-ignore-line method.impossibleType (false positive) + $this->assertCount(1, $errors); $this->assertInstanceOf(NotNormalizableValueException::class, $errors[0]); $this->assertSame('relatedDummies[0]', $errors[0]->getPath()); $this->assertSame('Invalid IRI "wrong".', $errors[0]->getMessage()); diff --git a/src/State/Provider/DeserializeProvider.php b/src/State/Provider/DeserializeProvider.php index c3949cfa22b..e911d3018b0 100644 --- a/src/State/Provider/DeserializeProvider.php +++ b/src/State/Provider/DeserializeProvider.php @@ -75,7 +75,7 @@ public function provide(Operation $operation, array $uriVariables = [], array $c throw new UnsupportedMediaTypeHttpException('Format not supported.'); } - if ($operation instanceof HttpOperation && null === ($serializerContext[SerializerContextBuilderInterface::ASSIGN_OBJECT_TO_POPULATE] ?? null)) { + if (null === ($serializerContext[SerializerContextBuilderInterface::ASSIGN_OBJECT_TO_POPULATE] ?? null)) { $method = $operation->getMethod(); $assignObjectToPopulate = 'POST' === $method || 'PATCH' === $method diff --git a/src/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php b/src/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php index fdea9920b08..883a6a411a1 100644 --- a/src/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php +++ b/src/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php @@ -629,7 +629,6 @@ private function registerGraphQlConfiguration(ContainerBuilder $container, array $loader->load('graphql.xml'); - // @phpstan-ignore-next-line because PHPStan uses the container of the test env cache and in test the parameter kernel.bundles always contains the key TwigBundle if (!class_exists(Environment::class) || !isset($container->getParameter('kernel.bundles')['TwigBundle'])) { if ($graphiqlEnabled) { throw new RuntimeException(\sprintf('GraphiQL interfaces depend on Twig. Please activate TwigBundle for the %s environnement or disable GraphiQL.', $container->getParameter('kernel.environment'))); diff --git a/src/Symfony/Controller/MainController.php b/src/Symfony/Controller/MainController.php index 8c691bf654d..b609d11609a 100644 --- a/src/Symfony/Controller/MainController.php +++ b/src/Symfony/Controller/MainController.php @@ -49,7 +49,7 @@ public function __invoke(Request $request): Response { $operation = $this->initializeOperation($request); - if (!$operation || !$operation instanceof HttpOperation) { + if (!$operation instanceof HttpOperation) { throw new RuntimeException('Not an HTTP API operation.'); } diff --git a/src/Symfony/EventListener/DeserializeListener.php b/src/Symfony/EventListener/DeserializeListener.php index 403ebc647fe..e4350120e97 100644 --- a/src/Symfony/EventListener/DeserializeListener.php +++ b/src/Symfony/EventListener/DeserializeListener.php @@ -13,7 +13,6 @@ namespace ApiPlatform\Symfony\EventListener; -use ApiPlatform\Metadata\HttpOperation; use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface; use ApiPlatform\State\ProviderInterface; use ApiPlatform\State\SerializerContextBuilderInterface; @@ -62,7 +61,7 @@ public function onKernelRequest(RequestEvent $event): void return; } - if (null === $operation->canDeserialize() && $operation instanceof HttpOperation) { + if (null === $operation->canDeserialize()) { $operation = $operation->withDeserialize(\in_array($method, ['POST', 'PUT', 'PATCH'], true)); } diff --git a/src/Symfony/EventListener/ReadListener.php b/src/Symfony/EventListener/ReadListener.php index 0b1b5a7600c..203d2d27644 100644 --- a/src/Symfony/EventListener/ReadListener.php +++ b/src/Symfony/EventListener/ReadListener.php @@ -15,7 +15,6 @@ use ApiPlatform\Metadata\Exception\InvalidIdentifierException; use ApiPlatform\Metadata\Exception\InvalidUriVariableException; -use ApiPlatform\Metadata\HttpOperation; use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface; use ApiPlatform\Metadata\UriVariablesConverterInterface; use ApiPlatform\Metadata\Util\CloneTrait; @@ -73,7 +72,7 @@ public function onKernelRequest(RequestEvent $event): void } $uriVariables = []; - if (!$request->attributes->has('exception') && $operation instanceof HttpOperation) { + if (!$request->attributes->has('exception')) { try { $uriVariables = $this->getOperationUriVariables($operation, $request->attributes->all(), $operation->getClass()); } catch (InvalidIdentifierException|InvalidUriVariableException $e) { diff --git a/src/Symfony/EventListener/WriteListener.php b/src/Symfony/EventListener/WriteListener.php index 1ee78b53d48..c74c140d356 100644 --- a/src/Symfony/EventListener/WriteListener.php +++ b/src/Symfony/EventListener/WriteListener.php @@ -16,7 +16,6 @@ use ApiPlatform\Metadata\Error; use ApiPlatform\Metadata\Exception\InvalidIdentifierException; use ApiPlatform\Metadata\Exception\InvalidUriVariableException; -use ApiPlatform\Metadata\HttpOperation; use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface; use ApiPlatform\Metadata\UriVariablesConverterInterface; use ApiPlatform\Metadata\Util\ClassInfoTrait; @@ -70,7 +69,7 @@ public function onKernelView(ViewEvent $event): void } $uriVariables = $request->attributes->get('_api_uri_variables') ?? []; - if (!$uriVariables && !$operation instanceof Error && $operation instanceof HttpOperation) { + if (!$uriVariables && !$operation instanceof Error) { try { $uriVariables = $this->getOperationUriVariables($operation, $request->attributes->all(), $operation->getClass()); } catch (InvalidIdentifierException|InvalidUriVariableException $e) {