gpt4 book ai didi

Symfony/Doctrine 无限递归,同时从具有多对一关系反转侧的数据库中获取

转载 作者:行者123 更新时间:2023-12-04 01:16:56 27 4
gpt4 key购买 nike

语境
在一个简单的 Symfony 项目中,我创建了两个实体,ProductCategory ,由 @ManyToOne 关联和 @OneToMany与教义注释的关系。一个类别可以有多个产品,一个产品与一个类别相关。我已在 Category 中手动插入数据 table 。
当我使用 Category 获取数据时实体存储库,我用 var_dump(...) 显示它,发生无限递归。当我返回包含这些数据的 JSON 响应时,它只是空的。它应该准确检索我手动插入的数据。
您是否知道如何在不删除 Category 中的反向关系的情况下避免此错误?实体?
我试过的

  • 添加教义注释fetch="LAZY"在一方,另一方和双方的关系。
  • 插入 Category使用 Doctrine 在数据库中的对象查看数据库连接是否正常。是的。
  • 删除 inverse side的关系。它有效,但这不是我想要的。

  • 代码片段
    Controller
    dummy/src/Controller/DefaultController.php

    ...

    $entityManager = $this->getDoctrine()->getManager();
    $repository = $entityManager->getRepository(Category::class);

    // ===== PROBLEM HERE =====
    //var_dump($repository->findOneByName('house'));
    //return $this->json($repository->findOneByName('house'));

    ...

    实体
    dummy/src/Entity/Category.php

    <?php

    namespace App\Entity;

    use App\Repository\CategoryRepository;
    use Doctrine\Common\Collections\ArrayCollection;
    use Doctrine\Common\Collections\Collection;
    use Doctrine\ORM\Mapping as ORM;

    /**
    * @ORM\Entity(repositoryClass=CategoryRepository::class)
    */
    class Category
    {
    /**
    * @ORM\Id()
    * @ORM\GeneratedValue()
    * @ORM\Column(name="id", type="integer")
    */
    private $id;

    /**
    * @ORM\Column(name="name", type="string", length=255)
    */
    private $name;

    /**
    * @ORM\OneToMany(targetEntity=Product::class, mappedBy="category", fetch="LAZY")
    */
    private $products;

    public function __construct()
    {
    $this->products = new ArrayCollection();
    }

    public function getId(): ?int
    {
    return $this->id;
    }

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

    public function setName(string $name): self
    {
    $this->name = $name;

    return $this;
    }

    /**
    * @return Collection|Product[]
    */
    public function getProducts(): Collection
    {
    return $this->products;
    }

    public function addProduct(Product $product): self
    {
    if (!$this->products->contains($product)) {
    $this->products[] = $product;
    $product->setCategory($this);
    }

    return $this;
    }

    public function removeProduct(Product $product): self
    {
    if ($this->products->contains($product)) {
    $this->products->removeElement($product);
    // set the owning side to null (unless already changed)
    if ($product->getCategory() === $this) {
    $product->setCategory(null);
    }
    }

    return $this;
    }
    }

    dummy/src/Entity/Product.php

    <?php

    namespace App\Entity;

    use App\Repository\ProductRepository;
    use Doctrine\Common\Collections\ArrayCollection;
    use Doctrine\Common\Collections\Collection;
    use Doctrine\ORM\Mapping as ORM;

    /**
    * @ORM\Entity(repositoryClass=ProductRepository::class)
    */
    class Product
    {
    /**
    * @ORM\Id()
    * @ORM\GeneratedValue()
    * @ORM\Column(name="id", type="integer")
    */
    private $id;

    /**
    * @ORM\Column(name="name", type="string", length=255)
    */
    private $name;

    /**
    * @ORM\ManyToOne(targetEntity=Category::class, inversedBy="products", fetch="LAZY")
    * @ORM\JoinColumn(name="category_id", referencedColumnName="id")
    */
    private $category;

    public function getId(): ?int
    {
    return $this->id;
    }

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

    public function setName(string $name): self
    {
    $this->name = $name;

    return $this;
    }

    public function getCategory(): ?Category
    {
    return $this->category;
    }

    public function setCategory(?Category $category): self
    {
    $this->category = $category;

    return $this;
    }
    }

    最佳答案

    我假设你使用 var_dump用于调试目的。出于调试目的,请使用 dumpdd来自 symfony/debug并且应该已经在 dev 上启用默认情况下。两个dumpdd应该及时中止无限递归。 (很多 symfony/doctrine 对象/服务有循环引用或者只是很多引用的对象。)dump将给定的 php var(s) 添加到分析器(分析器栏中的目标标记符号)或输出。 dd添加给定的变量,如 dump但也结束了这个过程(所以 d ump 和 d 即)。 - 在生产中永远不要使用 dump/dd/var_dump,而是正确地序列化你的数据。
    其次,$this->json本质上是打包的捷径json_encode变成 JsonResponse对象(或使用 symfony/serializer 代替)。 json_encode另一方面,序列化给定对象的公共(public)属性,除非对象实现 JsonSerializable (见下文)。由于几乎所有实体通常都具有私有(private)属性,因此结果通常是一个空对象序列化。
    有很多选项可供选择,但本质上您需要解决无限递归的问题。恕我直言的标准选项是:

  • 使用 symfony serializer哪个可以handle circular references (这会导致无限递归/循环),从而将对象转换为安全数组。但是,结果可能仍然不是您喜欢的...
  • 实现 JsonSerializable 在您的实体上,并小心避免递归添加子对象。
  • 自己从对象构建一个安全数组,传递给 $this->json (“手动方法”)。

  • 在这种情况下,一个安全数组是一个,它只包含字符串、数字以及字符串和数字的(嵌套)数组,这本质上意味着丢失所有实际对象。
    可能还有其他选择,但我发现这些是最方便的。我通常更喜欢 JsonSerializable选项,但这是一个品味问题。一个例子是:
    class Category implements \JsonSerializable { // <-- new implements!
    // ... your entity stuff

    public function jsonSerialize() {
    return [
    'id' => $this->id,
    'name' => $this->name,
    'products' => $this->products->map(function(Product $product) {
    return [
    'id' => $product->getId(),
    'name' => $product->getName(),
    // purposefully excluding category here!
    ];
    })->toArray(),
    ];
    }
    }
    添加此代码后,您的代码应该可以正常工作。对于开发人员,您始终应该使用 dump如前所述,所有 $this->json会工作的。这就是为什么我通常更喜欢这个选项。但是,需要注意的是:这种方式只能为类别提供一个 json 序列化方案。对于任何其他方式,您将不得不使用其他选项......无论如何这几乎总是正确的。

    关于Symfony/Doctrine 无限递归,同时从具有多对一关系反转侧的数据库中获取,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63198364/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com