How to deep populate, eg turn JSON into entity?

82 Views Asked by At

I have the following (extremly simplified) example entity:

class Reseller {
    private ?Uuid $id;
    private string $name;
    private ContactInfo $contactInfo;
}
class ContactInfo {
    private ?Uuid $id;
    private string $defaultEmail;
}

I have JSON, I want to serialize into an existing $reseller (but the same goes for new):

{"name":"Changed name","contactInfo":{"defaultEmail":"[email protected]"}}

The documentation tells this:

When the AbstractObjectNormalizer::DEEP_OBJECT_TO_POPULATE option is set to true, existing children of the root OBJECT_TO_POPULATE are updated from the normalized data, instead of the denormalizer re-creating them. Note that DEEP_OBJECT_TO_POPULATE only works for single child objects, but not for arrays of objects. Those will still be replaced when present in the normalized data.

So I've made this my serializer:

return $serializer->deserialize(
    $jsonString,
    Reseller::class,
    'json',
    [
        AbstractObjectNormalizer::DEEP_OBJECT_TO_POPULATE => true,
        AbstractNormalizer::OBJECT_TO_POPULATE => $reseller,
        AbstractNormalizer::GROUPS => $groups,
    ]
);

However, this leads to a

App\Entity\Reseller::setContactInfo(): Argument #1 ($contactInfo) must be of type App\Entity\ContactInfo, array given, called in [...]vendor/symfony/property-access/PropertyAccessor.php on line 509

What am I missing here? I've tried various locations and combinations to no avail. And Googling this just give endless examples how to serialize simple objects, without children.
The rest of my serializer config is pretty much the documentations version + a circular-reference-handler

1

There are 1 best solutions below

1
Tuomas Valtonen On

Symfony does not know how to handle the inner object and assumes it is just an array conversion.

You need to create custom normalizer for it but this can be difficult since the only data you got is {"defaultEmail":"[email protected]"}. You might need to hint using context but this becomes messy fast.

I would not recommend using symfony serializer/normalizer to map this kind of complex structures and especially to map json/xml/etc to entity and back. It will simply not scale.

You should look into some kind of 3rd party mapping solution like https://github.com/mark-gerarts/automapper-plus and use some kind of Dto's in-between to avoid mapping straight to entity which alone is problematic.