symfony deserialize nested objects

wyllyjon picture wyllyjon · Apr 11, 2018 · Viewed 7.2k times · Source

I have used the Symfony serializer to serialize my Recherche object. In a Recherche object, I have sub objects : Categorie and Lieu.

When I deserialize my Recherche object, all the sub objects are transformed in arrays. I would like them to be objects again.

This is how I have serialized my object:

$encoders = array(new JsonEncoder());
$normalizer = new ObjectNormalizer();
$normalizer->setIgnoredAttributes(array('parent', 'enfants'));
$normalizer->setCircularReferenceHandler(function ($object) {
    return $object->getCode();
});
$normalizers = array($normalizer);
$serializer = new Serializer($normalizers, $encoders);
$rechercheJson= $serializer->serialize($recherche, 'json');

And this is how I deserialize it :

$encoders = array(new JsonEncoder());
$normalizer = new ObjectNormalizer();
$normalizer->setIgnoredAttributes(array('parent', 'enfants'));
$normalizer->setCircularReferenceHandler(function ($object) {
    return $object->getCode();
});
$normalizers = array($normalizer);
$serializer = new Serializer($normalizers, $encoders);
$recherche = $serializer->deserialize($recherche_json, Recherche::class, 'json');

I think maybe there is something to do with normalizer, but I can't find anything that helps me in the docs.

Anyone has an idea to help ?

Thanks !

EDIT : After seeing this post : Denormalize nested structure in objects with symfony 2 serializer

I tried this :

$encoders = array(new JsonEncoder());
            $normalizer = new ObjectNormalizer(null, null, null, new SerializationPropertyTypeExtractor());
            $normalizer->setIgnoredAttributes(array('parent', 'enfants'));
            $normalizer->setCircularReferenceHandler(function ($object) {
                return $object->getCode();
            });
            $normalizers = array($normalizer,  new ArrayDenormalizer());
            $serializer = new Serializer($normalizers, $encoders);
            $recherche = $serializer->deserialize($recherche_json, Recherche::class, 'json');

And the SerializationPropertyTypeExtractor:

class SerializationPropertyTypeExtractor implements PropertyTypeExtractorInterface {
    /**
     * {@inheritdoc}
     */
    public function getTypes($class, $property, array $context = array())
    {
        if (!is_a($class, Recherche::class, true)) {
            return null;
        }

        if ('make' !== $property) {
            return null;
        }

        if ('lieu' === $property)
        {
            return [new Type(Type::BUILTIN_TYPE_OBJECT, true, LieuRecherche::class)];
        }
        if ('categorie' === $property)
        {
            return [new Type(Type::BUILTIN_TYPE_OBJECT, true, Categorie::class)];
        }

        return null;
    }
}

And this works well !

Answer

LocNgu picture LocNgu · Feb 21, 2020

I had a similar issue and tried to solve the problem with a custom PropertyTypeExtractor. Since I have many Entities with nested Objects this felt quite cumbersome also it doesn't work when the nested Object has nested Object again.

I found a better solution using the PhpDocExtractor and the ReflectionExtractor, which extracts the property info for you.

$encoder = [new JsonEncoder()];
$extractor = new PropertyInfoExtractor([], [new PhpDocExtractor(), new ReflectionExtractor()]);
$normalizer = [new ArrayDenormalizer(), new ObjectNormalizer(null, null, null, $extractor)];
$serializer = new Serializer($normalizer, $encoder);
$result = $serializer->deserialize($data,someEntity::class,'json');

This does all the work for me. I hope this will help someone.