How can I deserialize an array of objects in Symfony Serializer? How can I deserialize an array of objects in Symfony Serializer? symfony symfony

How can I deserialize an array of objects in Symfony Serializer?


I found a way to do this :). I installed the Symfony PropertyAccess package through Composer. With this package, you can add adders, removers and hassers. This way Symfony Serializer will automaticly fill the array with the correct objects.Example:

private $npcs = [];public function addNpc(Npc $npc): void{    $this->npcs[] = $npc;}public function hasNpcs(): bool{    return count($this->npcs) > 0}

etc.

This way you can use the ObjectNormalizer with:

$normalizer = new ObjectNormalizer(null, null, null, new ReflectionExtractor());

Edit: At least since v3.4 you have to create a remover method as well. Otherwise it just won't work (no error or warning).


I have struggled with this many hours without getting a result.Every time i added an adder function, the objectnormalizer wanted to invoke this function but got an error something like "The field xyz should be of type xyz[], array given".

This is cause i forgot to add the ArrayDenormalizer to the normalizer pool of the serializer. After adding this, everything worked fine.

Hope this is helpful for somebody.


The following (full) example is working for me with Symfony 5.3 components. It combines some of the above and adds some more necessary parts:

The Serializer needs to include ArrayDenormalizer as well as ObjectNormalizer. The ObjectNormalizer needs proper configuration. The full creation can look like this:

return new Serializer(    [        new ArrayDenormalizer(),        new DateTimeNormalizer(),        new ObjectNormalizer(            null,            null,            null,            new ReflectionExtractor()        ),    ],    [        new JsonEncoder(),    ]);

It seems like order is important regarding the normalizer / denormalizer, probably due to priority. Placing DateTimeNormalizer after ObjectNormalizer won't work.

The target class needs to provide three methods in order to allow mapping of an array of other classes:

class Place{    /**     * @var OpeningHour[]     */    protected $openingHours = [];    /**     * @return OpeningHour[]     */    public function getOpeningHoursSpecification(): array    {        return $this->openingHours;    }    public function addOpeningHoursSpecification(OpeningHour $openingHour): void    {        $this->openingHours[] = $openingHour;    }    public function removeOpeningHoursSpecification(OpeningHour $openingHour): void    {    }}

All three methods need to exist. The first in order to allow Serializer to fetch existing values and allow comparison. The other two need to exist in order to adapt existing value to match expected one by adding missing and removing no longer existing entities.

The above does not provide implementation for removal as this is taken from a one way project.