kinske kinske - 4 months ago 89
reST (reStructuredText) Question

Symfony serializer - set circular reference global

Is there any way to set the circular reference limit in the serializer component of Symfony (not JMSSerializer) with any config or something like that?

I have a REST Application with FOSRestBundle and some Entities that contain other entities which should be serialized too. But I'm running into circular reference errors.

I know how to set it like this:

$encoder = new JsonEncoder();
$normalizer = new ObjectNormalizer();

$normalizer->setCircularReferenceHandler(function ($object) {
return $object->getName();
});


But this has to be done in more than one controller (overhead for me).
I want to set it globally in the config (.yml) e.g. like this:

framework:
serializer:
enabled: true
circular_limit: 5


Found no serializer API reference for this so I wonder is it possible or not?

Answer

The only way I've found is to create your own object normalizer to add the circular reference handler.

A minimal working one can be:

<?php

namespace AppBundle\Serializer\Normalizer;

use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface;
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface;
use Symfony\Component\Serializer\NameConverter\NameConverterInterface;

class AppObjectNormalizer extends ObjectNormalizer
{
    public function __construct(ClassMetadataFactoryInterface $classMetadataFactory = null, NameConverterInterface $nameConverter = null, PropertyAccessorInterface $propertyAccessor = null, PropertyTypeExtractorInterface $propertyTypeExtractor = null)
    {
        parent::__construct($classMetadataFactory, $nameConverter, $propertyAccessor, $propertyTypeExtractor);

        $this->setCircularReferenceHandler(function ($object) {
            return $object->getName()
        });
    }
}

Then declare as a service with a slithly higher priority than the default one (which is -1000):

<service
    id="app.serializer.normalizer.object"
    class="AppBundle\Serializer\Normalizer\AppObjectNormalizer"
    public="false"
    parent="serializer.normalizer.object">

    <tag name="serializer.normalizer" priority="-500" />
</service>

This normalizer will be used by default everywhere in your project.