在一个简单的Symfony项目中,我创建了两个实体Product
和Category
,这两个实体通过与{Doctrine Annotations的@ManyToOne
和@OneToMany
关系来关联。一个类别可以有多个产品,而一个产品涉及一个类别。我已经在Category
表中手动插入了数据。
当我使用Category
实体存储库获取数据并用var_dump(...)
显示数据时,将发生无限递归。当我返回带有这些数据的JSON响应时,它只是空的。它应该准确检索我手动插入的数据。
您是否知道如何在不删除Category
实体的反边关系的情况下避免此错误?
Category
对象,以查看数据库连接是否正常工作。是的。控制器
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;
}
}
答案 0 :(得分:3)
我假设您使用var_dump
进行调试。为了进行调试,请使用dump
中的dd
或symfony/debug
,默认情况下应已在dev
上启用。 dump
和dd
都应中止时间上的无限递归。 (许多symfony / doctrine对象/服务具有循环引用,或者只是很多个引用对象。)dump
将给定的php var添加到分析器(目标标记符号位于探查器栏)或输出。 dd
像dump
一样添加给定的变量,但也结束该过程(因此 d ump和 d 即)。 -在生产环境中,切勿使用dump / dd / var_dump,而是正确序列化数据。
第二,$this->json
本质上是将json_encode
包装到JsonResponse
对象中的快捷方式(或者使用symfony / serializer代替)。另一方面,json_encode
对给定的对象的公共属性进行序列化,除非对象实现JsonSerializable
(见下文)。由于几乎所有实体通常都将其所有属性都私有,因此结果通常是空对象序列化。
有许多选项可供选择,但是本质上您需要解决无限递归的问题。 imho标准选项为:
JsonSerializable
,并小心避免递归添加子对象。$this->json
(“手动方法”)。在此上下文中,一个 safe 数组是一个数组,它仅包含字符串,数字和(嵌套的)字符串和数字数组,这实际上意味着丢失了所有实际对象。
可能还有其他选择,但是我发现这些是最方便的选择。我通常更喜欢使用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序列化方案。对于任何其他方式,您都必须使用其他选项,然后...几乎总是如此。