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

Я сопоставил свои объекты в соответствии с аннотациями доктрины. Я что-то упускаю?


person Chaymae    schedule 31.05.2017    source источник


Ответы (3)


Симфония 3.2

Используйте метод setCircularReferenceLimit. Например:

$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);

Причина в том, что циклическая ссылка в ваших сущностях вызывает некоторые проблемы, когда вы пытаетесь сериализовать их. Эффект метода заключается в определении максимальной глубины иерархии сериализации.

Изменить: добавлен обработчик циклических ссылок (A обнаружена циклическая ссылка (настроено ограничение: 1) Serializer 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']);
person Ilario Pierbattista    schedule 31.05.2017
comment
я добавляю его, но получаю метод 'setCircularReferenceLimit' not found in class \Symfony\Component\Serializer\Serializer - person Chaymae; 31.05.2017
comment
Извиняюсь! Это метод нормализаторов! Позвольте мне исправить это. - person Ilario Pierbattista; 31.05.2017
comment
@Chaymae попробуй сейчас - person Ilario Pierbattista; 31.05.2017
comment
большое спасибо за быстрый ответ, но теперь я получаю A circular reference has been detected (configured limit: 2) - person Chaymae; 31.05.2017
comment
Я добавил это, и теперь это работает $normalizer->setCircularReferenceLimit(2); $normalizer->setCircularReferenceHandler(function ($object) { return $object->getId(); }); - person Chaymae; 31.05.2017
comment
Как можно заставить нормализатор воздействовать на сериализатор, если мы получаем сервис сериализатора? (т.е. $this-›get('сериализатор');) - person Graph; 04.09.2017
comment
Предполагая, что вы используете ту же основную версию исходного вопроса symfony, я думаю, вам нужно изменить конфигурацию сериализатора по умолчанию, как описано здесь (symfony.com/doc/3.2/). Я не думаю, что возможно динамически изменить нормализатор после создания сериализатора. - person Ilario Pierbattista; 04.09.2017
comment
setCircularReferenceLimit и setCircularReferenceHandler теперь устарели. Какие еще у нас есть альтернативы? - person Victor Anuebunwa; 21.02.2019
comment
@VictorAnuebunwa Обновлено, дайте мне знать, если это сработает для вас. - person Ilario Pierbattista; 21.02.2019
comment
Здравствуйте, я использую Symfony 4.2, и когда я попытался сделать то, что вы сделали, я получил следующую ошибку: Предупреждение: нельзя использовать скалярное значение в качестве массива. Любая идея, как это исправить? - person tomfl; 05.03.2019
comment
Привет @tomfl, я не могу тебе помочь из-за отсутствия контекста. Если у вас есть другой вопрос, задайте его, нажав кнопку Задать вопрос. - person Ilario Pierbattista; 05.03.2019

Лучше всего использовать метод useCircularReferenceLimit. Как это уже было ясно объяснено в этом посте.

Но у нас есть другой вариант. Как вариант, есть способ игнорировать атрибуты исходного объекта. Мы можем игнорировать его, если он нам определенно не нужен в сериализованном объекте. Преимущество этого решения в том, что сериализованный объект меньше и его легче читать, а недостаток в том, что мы больше не будем ссылаться на игнорируемый атрибут.

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 в параметре контекста нужного метода сериализатора:

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

person PHP php    schedule 21.09.2019

Исправлена ​​та же проблема

use JMS\Serializer\SerializerBuilder;
...

$products = $em->getRepository('AppBundle:Product')->findAll();
$serializer = SerializerBuilder::create()->build();
$jsonObject = $serializer->serialize($products, 'json');

Прочитайте здесь

person Galina Bublik    schedule 13.07.2017
comment
Что не решает поставленную задачу. Вы просто заменяете компонент/службу сериализатора сторонним решением, которое в данном случае даже не обеспечивает нормализацию циклических ссылок. - person onigunn; 24.11.2017