Core: There is no PropertyInfo extractor supporting the class

Created on 27 Feb 2019  路  9Comments  路  Source: api-platform/core

Hello,
After upgrade from Api Platform 2.4 beta.1 to beta.2, I get the following error

There is no PropertyInfo extractor supporting the class \"App\\DTO\\CredentialsDTO\"

Here is the class in question:

/**
 * @method string getSessionId()
 * @method self setSessionId(?string $sessionId)
 * @method string getToken()
 * @method self setToken(?string $token)
 */
class CredentialsDTO implements \JsonSerializable
{
/** @var array */
    protected $objectData = [];

    /**
     * {@inheritdoc}
     */
    public function __call($name, $arguments)
    {
        if ('get' === substr($name, 0, 3)) {
            return $this->objectData[$this->getProperty($name)] ?? null;
        } elseif ('set' === substr($name, 0, 3) && array_key_exists(0, $arguments)) {
            $this->objectData[$this->getProperty($name)] = $arguments[0];

            return $this;
        }
    }

    /**
     * {@inheritdoc}
     */
    public function __isset($name)
    {
        return array_key_exists($name, $this->objectData);
    }

    /**
     * From \JsonSerializable interface.
     *
     * Specify data which should be serialized to JSON
     * @link https://php.net/manual/en/jsonserializable.jsonserialize.php
     * @return mixed data which can be serialized by <b>json_encode</b>,
     * which is a value of any type other than a resource.
     */
    public function jsonSerialize()
    {
        return $this->objectData;
    }

    /**
     * Return the property from a function name.
     *
     * @param $name
     *
     * @return string
     */
    private function getProperty($name)
    {
        return lcfirst(substr($name, 3));
    }
}

I use magic_call to true of the property_access component in order to have dynamic properties. This worked perfectly fine in beta.1 but no longer works in beta.2...
I am not sure what the problem is...

bug

Most helpful comment

I think that documentation of DTO could be fixed https://api-platform.com/docs/core/dto/#using-data-transfer-objects-dtos

Copying code directly from this documentation leads to error like this.

All 9 comments

We now try to denormalize DTOs just as they were resources. This means we are indeed using the PropertyInfo component to gather properties and types for a given DTO.

Your use case is really hackish and indeed the property info component doesn't find any properties and fails. The proper way of fixing this would be to register a property info extractor that handles your special case (but you don't know the properties ahead?).

Can you give me the error stack trace please? Thanks!

This DTO is not even related to api platform, it has no ApiResource annotation so I am not sure why it is affected.
I use this DTO to serialize/deserialize data from Guzzle requests to an external API.
It's done this way because I need to be able to not include some properties in the encoded json (as opposed to sending them with null value), so for example if the setter for sessionId is not called but the setter for token is called, only token will be included in the encoded json and not session id with null since they are virtual properties. I can not use a normal DTO because in that case the encoded json would also contain the session id set to null and I do not want it to be included at all.
I now the properties ahead of time, that is why there are those @method in the doc blocks but I can not use a normal DTO because of null serializing. This is similar to Laravel approach.

Here is the stack trace:
https://pastebin.com/fQawkt0h

I have analyzed the trace and to me it seems that if the class does not have the ApiResource annotation it should not be handled by ApiPlatform at all, but by the default Symfony serializer functionality.

In the latest beta we decided to allow our serializer on classes that are not resources. This is good for many cases where DTO are used. Indeed before you had to declare these as fake resources to make it work.

Can you show me in which entity this DTO is used? Is it used with the json-ld format?

This DTO is not used in any entity, it is used directly in the SerializerInterface service:

$dto = new CredentialsDTO();
// call setters ...
...

$json = $this->serializer->serialize($dto, 'json')

// deserialize, this is were the error appears
$dto = $this->serializer->deserialize($json, CredentialsDTO::class, 'json');

That is why I don't understand why this error occurs since this is not used in any ApiResource class...

@raresserban because since the last beta (for DTOs), the API Platform normalizers are able to serialize any classes, even if they aren't marked with @ApiResource. See https://github.com/api-platform/core/pull/2566 for a fix.

@raresserban Could you try out #2592 and let us know if it fixes your issue?

@teohhanhui Yes, that seems to have fixed the issue. Thank you.

Nice thanks for the feedback @raresserban !

I think that documentation of DTO could be fixed https://api-platform.com/docs/core/dto/#using-data-transfer-objects-dtos

Copying code directly from this documentation leads to error like this.

Was this page helpful?
0 / 5 - 0 ratings