Skip to content

chore: disable treat phpdoc type as certain for phpstan #7250

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 30, 2025

Conversation

VincentLanglet
Copy link
Contributor

Q A
Branch? main for features / current stable version branch for bug fixes
Tickets Closes #..., closes #...
License MIT
Doc PR api-platform/docs#...

I was fixing the identifier: instanceof.alwaysTrue errors and ends up with code like

 if (null === $parameter->getOpenApi() && ($openApi = $description[$key]['openapi'] ?? null) && $openApi instanceof OpenApiParameter) {

=> Here the $openApi instanceof OpenApiParameter check is reported as useless but the type is coming from phpdoc and there is a test which check what happen if the phpdoc is not respected

or

$repository = $manager->getRepository($documentClass);
if (!$repository instanceof DocumentRepository) {

Same here, instanceof DocumentRepository is reported as useless but, it's your right to not trust the getRepository phpdoc.

That's the purpose of treatPhpDocTypesAsCertain: false
https://phpstan.org/config-reference#treatphpdoctypesascertain ; this allows you to add extra safety check when the information is coming from the phpdoc (but report it as useless when the information is coming from a real native type).

This is useful for open source lib which extra safety check and allow you

  • To solve some phpstan issues
  • To remove some phpstan-ignore

@@ -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) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As soon as FieldMapping exists, it's the return type of the method.

@@ -100,10 +100,6 @@ private function buildAggregation(string $toClass, array $links, array $identifi

$classMetadata = $manager->getClassMetadata($aggregationClass);

if (!$classMetadata instanceof ClassMetadata) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getClassMetadata returns always a ClassMetadata according to the native return type.

Yes, objectManager only has phpdoc for doctrine/persistence < 4, but here we always has a documentManager and this one use native type since 2.0
https://github.com/doctrine/mongodb-odm/blob/cdae04333cc592e3c0d388aa6745d1d486aed6e3/lib/Doctrine/ODM/MongoDB/DocumentManager.php#L282

@@ -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
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is now no error with treatPhpdocAsCertain: false

@@ -49,9 +49,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));
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here options was always an Options.

  • Phpstan knows
  • PHPStorm doesn't

So I rewrite the code to help phpstorm understand it and avoid the false positive for phpstan

@@ -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;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already check $type instanceof CollectionType before

@@ -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)) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is

if (!$operation instanceof HttpOperation || !($request = $context['request'] ?? null)) {
            return $this->decorated?->provide($operation, $uriVariables, $context);
        }

before

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've also improved HttpOperation detection recently with 4dc91a0 don't hesitate if you find things that needs type definition improvement (we can always track them in a separated issue)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is another PHPStan failure to fix since the recent symfony release
#7255

@@ -62,7 +62,7 @@ public function onKernelRequest(RequestEvent $event): void
return;
}

if (null === $operation->canDeserialize() && $operation instanceof HttpOperation) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$this->initializeOperation always returns a HttpOperation and it use native return type.

Same idea for all the following $operation instanceof HttpOperation

@soyuka soyuka merged commit 078b1a6 into api-platform:main Jun 30, 2025
112 of 114 checks passed
@soyuka
Copy link
Member

soyuka commented Jun 30, 2025

thanks @VincentLanglet !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants