Skip to content

Handling PropertyTypeExtractorInterface with multiple types #2503

@JumpIfBelow

Description

@JumpIfBelow

Hi,

To first start with: thanks for all the work you are doing. It is able to achieve many things, even if it is sometimes a bit hard to understand.

I'm using API Platform 2.1 (I'm locked to Symfony 3.4 here) and I have an issue with the property_info service always using Doctrine to performs the type inference.
The issue there is that I have Doctrine fields that does not allows null while the property itself allows it. It then uses validation to says if null is allowed or not.

It could works great but that's where the property_info is working there to say something like The type of the "configuration" attribute must be "string", "NULL" given..
From now on, I was trying to use PhpDocs first to infer the type and then fallback to Doctrine type extractor.
I adds this in the services.yaml:

services:
#...
    php_doc_extractor:
        decorates: 'property_info.php_doc_extractor'
        class: 'Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor'
        tags:
            - { name: 'property_info.description_extractor', priority: -1000 }
            - { name: 'property_info.type_extractor', priority: -998 }

as Doctrine has a priority of -999 for type extractor, now the PhpDocs is triggered first. And it is!

But that's where the bug takes place: I have many types which are declared like this:

<?php

namespace Baz;

use Doctrine\Common\Collections\Collection;

class Foo {
  /**
   * @var Collection|Bar[] $bars
   */
  private $bars;
}

(I'm droping API Platform and Doctrine configuration here because it has nothing to do with the actual issue)

When the IRI generator will try to understands which type I'm trying to show, it will first hits the Collection type. The result is a cryptic bug like this: Could not denormalize object of type Doctrine\Common\Collections\Collection, no supporting normalizer found.
Sometimes, I have another one even more cryptic which says Uncaught PHP Exception Symfony\Component\Config\Exception\FileLoaderLoadException: "Resource "Doctrine\Common\Collections\Collection" not found in . (which is being imported from "/srv/app/config/routes/api_platform.yaml"). Make sure there is a loader supporting the "api_platform" type." at /srv/app/vendor/symfony/config/Loader/FileLoader.php line 168.

The bugs looks like when it hits an unhandled type, it simply crashes instead of testing other types.
The PropertyTypeExtractorInterface::getTypes() returns null if nothing is found, or an array. We should iterate through this array until a handled type is found. If none, then an error should be thrown.

I think this issue happens because no one ever tried to change this behavior and Doctrine always returns null or an array with one element inside. Handling many values could be better.

The workaround for me is to make the class above looking like this:

<?php

namespace Baz;

use Doctrine\Common\Collections\Collection;

class Foo {
  /**
   * @var Bar[]|Collection $bars
   */
  private $bars;
}

Then it will first hits Bar[], which is handled. Then everything works.

It really is an edge case and I understand it. If someone is able to fix it, it is cool. If not, this issue may be useful for anyone coming to the same case.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions