Symfony 3.2 Обнаружена круговая ссылка (сконфигурированный предел: 1)
У меня есть два объекта в моем проекте
class PoliceGroupe
{
/**
* @var int
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
*
* @ORM\Column(name="code", type="string", length=50)
*/
private $code;
/**
* @ORM\ManyToMany(targetEntity="PointVente", inversedBy="policegroupe")
* @ORM\JoinTable(name="police_groupe_point_vente",
* joinColumns={@ORM\JoinColumn(name="police_groupe_id", referencedColumnName="id")},
* inverseJoinColumns={@ORM\JoinColumn(name="point_vente_id", referencedColumnName="id")}
* )
*/
private $pointVente;
/**
* Constructor
*/
public function __construct($produit)
{
$this->pointVente = new \Doctrine\Common\Collections\ArrayCollection();
}
}
А вот и другая моя сущность
class PointVente
{
/**
* @var string
*
* @ORM\Column(name="abb", type="string", length=50)
*/
private $abb;
/**
* @var string
*
* @ORM\Column(name="libelle", type="string", length=255)
*/
private $libelle;
/**
*
* @ORM\ManyToMany(targetEntity="PoliceGroupe", mappedBy="pointVente")
*/
private $policegroupe;
}
и я пытаюсь запустить этот код в моем контроллере
$encoders = array(new XmlEncoder(), new JsonEncoder());
$normalizers = array(new ObjectNormalizer());
$serializer = new Serializer($normalizers, $encoders);
$em = $this->getDoctrine()->getManager();
$data = $request->get('data');
$policegroupe=$em->getRepository('StatBundle:PoliceGroupe')->findOneBy(array('id' => $data));
$pointventes = $policegroupe->getPointVente();
$jsonContent = $serializer->serialize($pointventes, 'json');
return new JsonResponse( array('pointventes'=>$jsonContent) );
Но я получаю это исключение
Symfony\Component\Serializer\Exception\CircularReferenceException: A circular reference has been detected (configured limit: 1).
at n/a
in C:\wamp\www\Sys\vendor\symfony\symfony\src\Symfony\Component\Serializer\Normalizer\AbstractNormalizer.php line 194
Я нанес на карту свои сущности в соответствии с аннотациями доктрины. Я что-то пропустил?
Ответы
Ответ 1
Symfony 3.2
Используйте метод useCircularReferenceLimit
. Например:
$normalizer = new ObjectNormalizer();
$normalizer->setCircularReferenceLimit(2);
// Add Circular reference handler
$normalizer->setCircularReferenceHandler(function ($object) {
return $object->getId();
});
$normalizers = array($normalizer);
$serializer = new Serializer($normalizers, $encoders);
Причина в том, что циклические ссылки в ваших сущностях вызывают некоторые проблемы при попытке их сериализации. Результатом метода является определение максимальной глубины иерархии сериализации.
Изменение: добавлен обработчик циклических ссылок (Обнаружена циклическая ссылка (настроено ограничение: 1) Сериализатор SYMFONY)
ОБНОВЛЕНИЕ: обновление (Symfony 4.2)
Испытать с Symfony 3.2, но здесь circular_reference_limit
не является проблемой (по умолчанию 1 - ОК, иначе ваша сущность будет извлечена 2 раза), проблема в том, как она обрабатывается circular_reference_handler
. Сообщение о том, что id
является идентификатором сущности, решает проблему. См. документы Symfony внизу этого абзаца.
Поскольку setCircularReferenceHandler
устарело в пользу следующих ключей контекста circular_reference_handler
, мы можем написать:
// Tip : Inject SerializerInterface $serializer in the controller method
// and avoid these 3 lines of instanciation/configuration
$encoders = [new JsonEncoder()]; // If no need for XmlEncoder
$normalizers = [new ObjectNormalizer()];
$serializer = new Serializer($normalizers, $encoders);
// Serialize your object in Json
$jsonObject = $serializer->serialize($objectToSerialize, 'json', [
'circular_reference_handler' => function ($object) {
return $object->getId();
}
]);
// For instance, return a Response with encoded Json
return new Response($jsonObject, 200, ['Content-Type' => 'application/json']);
Ответ 2
Лучший способ - использовать метод useCircularReferenceLimit
. Как уже было четко объяснено в этом посте.
Но у нас есть другой вариант. Как вариант, есть способ игнорировать атрибуты из исходного объекта. Мы можем игнорировать это, если нам определенно не нужно это в сериализованном объекте.
Преимущество этого решения заключается в том, что сериализованный объект меньше по размеру и его легче читать, а недостатком является то, что мы больше не будем ссылаться на атрибут ignored.
Symfony 2,3 - 4,1
Чтобы удалить эти атрибуты, используйте метод setIgnoredAttributes() в определении нормализатора:
use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
$normalizer = new ObjectNormalizer();
$normalizer->setIgnoredAttributes(array('age'));
$encoder = new JsonEncoder();
$serializer = new Serializer(array($normalizer), array($encoder));
$serializer->serialize($person, 'json'); // Output: {"name":"foo","sportsperson":false}
Метод setIgnoredAttributes()
был введен в Symfony 2.3.
До Symfony 2.7 атрибуты игнорировались только при сериализации. Начиная с Symfony 2.7, они также игнорируются при десериализации.
Symfony 4.2 - 5.0
Метод setIgnoredAttributes()
, который использовался в качестве альтернативы опции ignored_attributes, в Symfony 4.2 устарел.
Чтобы удалить эти атрибуты, предоставьте массив с помощью клавиши ignored_attributes
в параметре context желаемого метода сериализатора:
use Acme\Person;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;
$person = new Person();
$person->setName('foo');
$person->setAge(99);
$normalizer = new ObjectNormalizer();
$encoder = new JsonEncoder();
$serializer = new Serializer([$normalizer], [$encoder]);
$serializer->serialize($person, 'json', ['ignored_attributes' => ['age']]); // Output: {"name":"foo"}
В моих проектах Symfony 3.4 я использую сочетание этих двух методов setIgnoredAttributes()
и setCircularReferenceLimit()
, и он отлично работает.
Источник: https://symfony.com/doc/3.4/components/serializer.html
Ответ 3
Исправлена такая же проблема с помощью
use JMS\Serializer\SerializerBuilder;
...
$products = $em->getRepository('AppBundle:Product')->findAll();
$serializer = SerializerBuilder::create()->build();
$jsonObject = $serializer->serialize($products, 'json');
Прочитайте здесь