【问题标题】:Symfony 3.2 A circular reference has been detected (configured limit: 1)Symfony 3.2 检测到循环引用(配置限制:1)
【发布时间】:2023-04-03 11:15:01
【问题描述】:

我的项目中有这两个实体

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

我根据教义注释映射了我的实体。我错过了什么吗?

【问题讨论】:

    标签: symfony serialization symfony-3.2


    【解决方案1】:

    Symfony 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 circular reference has been detected (configured limit: 1) Serializer SYMFONY)

    编辑:更新(Symfony 4.2)

    尝试使用 Symfony 3.2,但 circular_reference_limit 不是这里的问题(默认为 1 即可,否则您的实体将被检索 2 次),问题是 @ 处理实体的方式987654327@。告诉id 是实体标识符可以解决问题。请参阅 Symfony 文档at the bottom of this paragraph

    由于setCircularReferenceHandler 已弃用in favour of the following keys of the context 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']);
    

    【讨论】:

    • 我添加了它,但我得到了 Method 'setCircularReferenceLimit' not found in class \Symfony\Component\Serializer\Serializer
    • 对不起!这是规范器的一种方法!让我解决这个问题。
    • @Chaymae 立即尝试
    • 非常感谢您的快速回答,但现在我收到了A circular reference has been detected (configured limit: 2)
    • 我添加了这个,现在它正在工作$normalizer->setCircularReferenceLimit(2); $normalizer->setCircularReferenceHandler(function ($object) { return $object->getId(); });
    【解决方案2】:

    最好的方法是使用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() 方法被用作 ignore_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

    【讨论】:

      【解决方案3】:

      你需要使用上下文:

      $normalizer->normalize($article, 'It doesn`t matter', [
          AbstractNormalizer::CIRCULAR_REFERENCE_HANDLER => function($object) {
              return $object->getId();
          }
      ]);
      

      大例子:

      namespace App\Command;
      
      use App\Entity\Oltp\Article;
      use Doctrine\ORM\EntityManagerInterface;
      use Symfony\Component\Console\Command\Command;
      use Symfony\Component\Console\Input\InputInterface;
      use Symfony\Component\Console\Output\OutputInterface;
      use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
      use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
      
      use function json_encode;
      
      class SqliteFirstCommand extends Command
      {
          protected static $defaultName = 'app:first';
          private EntityManagerInterface $entityManager;
          private NormalizerInterface $normalizer;
      
          public function __construct(
              EntityManagerInterface $entityManager,
              NormalizerInterface $normalizer
          )
          {
              parent::__construct(self::$defaultName);
              $this->entityManager = $entityManager;
              $this->normalizer = $normalizer;
          }
      
          protected function execute(InputInterface $input, OutputInterface $output): int
          {
              $articles = $this->entityManager->getRepository(Article::class)->findAll();
              foreach ($articles as $article) {
                  $array = $this->normalizer->normalize($article, 'It doesn`t matter', [
                      AbstractNormalizer::CIRCULAR_REFERENCE_HANDLER => function($object) {
                          return $object->getId();
                      }
                  ]);
                  $output->writeln(json_encode($array));
              }
      
              return 0;
          }
      }
      

      【讨论】:

        【解决方案4】:

        修复了相同的问题
        use JMS\Serializer\SerializerBuilder;
        ...
        
        $products = $em->getRepository('AppBundle:Product')->findAll();
        $serializer = SerializerBuilder::create()->build();
        $jsonObject = $serializer->serialize($products, 'json');
        

        阅读here

        【讨论】:

        • 这不能解决给定的问题。您只是用第三方解决方案替换序列化程序组件/服务,在这种情况下甚至不提供循环引用的规范化。
        猜你喜欢
        • 2020-04-03
        • 2022-12-11
        • 2016-12-15
        • 2018-04-14
        • 2017-04-06
        • 1970-01-01
        • 2012-11-10
        • 1970-01-01
        • 2014-04-12
        相关资源
        最近更新 更多