Symfony: Recursive denormalization does not support object_to_populate

Created on 18 Feb 2017  路  3Comments  路  Source: symfony/symfony

| Q | A
| ---------------- | -----
| Bug report? | no
| Feature request? | yes
| BC Break report? | no
| RFC? | no
| Symfony version | 3.3.0

It would be really helpful if there was a way to recursively deseriailize objects.

Given an object like this:

class User
{

    /**
     * Set Name.
     *
     * @param Name $name
     */
    public function setName(Name $name) : self
    {
        $this->name = $name;

        return $this;
    }
}

The serializer throws a Symfony\Component\Serializer\Exception\UnexpectedValueException with the message "Expected argument of type 'Name', 'array' given" because it passes an array into setName() rather than running the denormilization on the Name class and then passing the result into setName(). I think having this feature would be really helpful. I could of course allow this method to accept Name and array, but then it will bypass:
1) Populating the existing name object
2) Any groups that may be used for access.

Since the method already has a typehint of the only thing it will accept (a class) I think it makes sense that if a non-scalar type hint is encountered in a setter, it should:
1) Run the denormalizer with the type hinted class as the type.
2) Pass the same groups from the parent to the child
3) Attempt to get the value of the property, if a value is returned, it should use that value in object_to_populate (assuming object_to_populate was set on the parent)

Feature Serializer

Most helpful comment

Well this wasn't immediately obvious, but I found this:
https://github.com/symfony/symfony/blob/3.2/src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.xml#L25

which lead me to install the ProperyInfo compoment and enable it in my config.yml:

framework:
    property_info:
        enabled: true

This _mostly_ fixes my problem(s). It does support recursion, and it does support groups, however, it does not support object_to_populate. I'm going to change this issue to be about that rather than recursion itself which Symfony clearly supports (albeit poorly documented).

All 3 comments

Well this wasn't immediately obvious, but I found this:
https://github.com/symfony/symfony/blob/3.2/src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.xml#L25

which lead me to install the ProperyInfo compoment and enable it in my config.yml:

framework:
    property_info:
        enabled: true

This _mostly_ fixes my problem(s). It does support recursion, and it does support groups, however, it does not support object_to_populate. I'm going to change this issue to be about that rather than recursion itself which Symfony clearly supports (albeit poorly documented).

There is a lack in the documentation about how you need to activate PropertyInfo in order to have embedded object deserialized, I've already posted an issue about that: https://github.com/symfony/symfony-docs/issues/7387

About the third problem (now only problem), object_to_populate is used to update/use an already existing object instead of creating a new one. You say that if the parent use this option, the embedded objects should used it too. I can see the need to use an existing object as value of a property, but:

  1. The use of an existing object doesn't mean that all properties that are objects are "objects to populate" (already existing objects). Sometimes you could need to create objects to add to the parent one, so extending the "object_to_populate" to all the properties by default is not a valid option
  2. So, you need a way to identify which properties are "objects to populate" and how to access to the already existing objects, and you don't have a unique and universal way to do it, because this value can be obtained from a database, from an API resource, even from some hashmap in memory. For example, in the API Platform project they use dereferenceables IRIs to identify embedded relations: https://api-platform.com/docs/core/serialization-groups-and-relations#embedding-relations. And even in this case, is used only to relate one exiting object with another, not to change/update the embedded object.

@davidbarratt's comment helped me figure-out that I needed to install the PropertyInfoComponent and add the framework.property_info.enabled config for the Serializer to be able to deserialize objects with \DateTime properties. This is not necessary for the serialization and I couldn't find anything in the doc that mentions it.
Without this, serializing an object with a \DateTime property works, but deserializing it just afterwards fails. It (serializing _and deserializing_ objects with \DateTime properties) seems like a likely scenario so I would propose mentionning it in the documentation to save other developers the frustration and frantic googling.

Was this page helpful?
0 / 5 - 0 ratings