Skip to content

[Serializer] Handle circular references. symfony/symfony#12098. #4299

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 28, 2014
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 96 additions & 1 deletion components/serializer.rst
Original file line number Diff line number Diff line change
Expand Up @@ -238,14 +238,109 @@ When serializing, you can set a callback to format a specific object property::
$serializer->serialize($person, 'json');
// Output: {"name":"cordoval", "age": 34, "createdAt": "2014-03-22T09:43:12-0500"}

Handling Circular References
----------------------------

.. versionadded:: 2.6
Handling of circular references was introduced in Symfony 2.6. In previous
versions of Symfony, circular references led to infinite loops.

Circular references are common when dealing with entity relations::

class Organization
{
private $name;
private $members;

public function setName($name)
{
$this->name = $name;
}

public function getName()
{
return $this->name;
}

public function setMembers(array $members)
{
$this->members = $members;
}

public function getMembers()
{
return $this->members;
}
}

class Member
{
private $name;
private $organization;

public function setName($name)
{
$this->name = $name;
}

public function getName()
{
return $this->name;
}

public function setOrganization(Organization $organization)
{
$this->organization = $organization;
}

public function getOrganization()
{
return $this->organization;
}
}

To avoid infinite loops, :class:`Symfony\\Component\\Serializer\\Normalizer\\GetSetMethodNormalizer`
throws a :class:`Symfony\\Component\\Serializer\\Exception\\CircularReferenceException`
when such case is encountered::

$member = new Member();
$member->setName('Kévin');

$org = new Organization();
$org->setName('Les-Tilleuls.coop');
$org->setMembers(array($member));

$member->setOrganization($kevin);

echo $serializer->serialize($org, 'json'); // Throws a CircularReferenceException

The ``setCircularReferenceLimit()`` method of this normalizer sets the number
of times serializing the same object must occur before considering being
in a circular reference. Its default value is ``1``.

Instead of throwing an exception, circular references can also be handled
by custom callables. This is especially useful when serializing entities
having unique identifiers::

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

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

$serializer = new Serializer(array($normalizer), array($encoder));
echo $serializer->serialize($org, 'json');
// {"name":"Les-Tilleuls.coop","members":[{"name":"K\u00e9vin", organization: "Les-Tilleuls.coop"]}

JMSSerializer
-------------

A popular third-party library, `JMS serializer`_, provides a more
sophisticated albeit more complex solution. This library includes the
ability to configure how your objects should be serialized/deserialized via
annotations (as well as YAML, XML and PHP), integration with the Doctrine ORM,
and handling of other complex cases (e.g. circular references).
and handling of other complex cases.

.. _`JMS serializer`: https://github.com/schmittjoh/serializer
.. _Packagist: https://packagist.org/packages/symfony/serializer