我试图使用Doctrine 2在Symfony 3中运行4个实体,但是当我想序列化一个Account实体时,我仍然坚持循环引用异常:
检测到循环引用(配置限制:1)。
我在我的实体中选择了双向关系,架构是这样的:
- Account [1] ---- [0..*] AccountSheet
- AccountSheet [1] ---- [0..*] Operation
- Operation [0..*] ---- [1] Category
以下是实体(为清晰起见,有一些清理):
SRC \的appbundle \实体\ Account.php
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use AppBundle\Entity\AbstractGenericEntity;
/**
* @ORM\Entity()
* @ORM\Table(name="accounts",
* uniqueConstraints={@ORM\UniqueConstraint(name="accounts_name_unique",columns={"name"})})
*/
class Account extends AbstractGenericEntity{
/**
* @ORM\OneToMany(targetEntity="AccountSheet", mappedBy="account")
* @var AccountSheet[]
*/
protected $accountSheets;
public function __construct($name = null, $description = null){
$this->accountSheets = new ArrayCollection();
$this->name = $name;
$this->description = $description;
}
}
SRC \的appbundle \实体\ AccountSheet.php
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use AppBundle\Entity\AbstractGenericEntity;
/**
* @ORM\Entity()
* @ORM\Table(name="accounts_sheets",
* uniqueConstraints={@ORM\UniqueConstraint(name="accountsheet_account_unique", columns={"name", "account_id"})})
* @ORM\HasLifecycleCallbacks
*/
class AccountSheet extends AbstractGenericEntity{
/**
* @ORM\ManyToOne(targetEntity="AppBundle\Entity\Account", inversedBy="accountSheets")
* @var Account
*/
protected $account;
/**
* @ORM\OneToMany(targetEntity="Operation", mappedBy="accountSheet")
* @var Operation[]
*/
protected $operations;
public function __construct($name = null){
$this->operations = new ArrayCollection();
$this->name = $name;
}
}
SRC \的appbundle \实体\ Operation.php
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use AppBundle\Entity\AbstractGenericEntity;
/**
* @ORM\Entity()
* @ORM\Table(name="operations")
*/
class Operation extends AbstractGenericEntity{
/**
* @ORM\ManyToOne(targetEntity="AppBundle\Entity\AccountSheet", inversedBy="operations")
* @ORM\JoinColumn(nullable=false)
* @var AccountSheet
*/
protected $accountSheet;
/**
* @ORM\ManyToOne(targetEntity="AppBundle\Entity\Category", inversedBy="operations")
* @var Category
*/
protected $category;
public function __construct($type = null, $label = null, $montant = null, $comment = null){
$this->label = $label;
$this->type = $type;
$this->comment = $comment;
$this->montant = $montant;
}
}
SRC \的appbundle \实体\ Category.php
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use AppBundle\Entity\AbstractGenericEntity;
/**
* @ORM\Entity()
* @ORM\Table(name="categories")
*/
class Category extends AbstractGenericEntity{
/**
* @ORM\Column(type="string")
*/
protected $label;
/**
* @ORM\Column(type="string")
*/
protected $description;
/**
* @ORM\OneToMany(targetEntity="Operation", mappedBy="category")
* @var Operation[]
*/
protected $operations;
public function __construct($name = null){
$this->operations = new ArrayCollection();
$this->name = $name;
}
}
我猜它在Operation实体上,再次引用了AccountSheet。实际上并不需要双向操作。
我怎么能重新安排这个?
谢谢!
答案 0 :(得分:7)
来自官方文件:
循环引用在处理实体关系时很常见
为避免无限循环,遇到这种情况时,GetSetMethodNormalizer会抛出CircularReferenceException:
$member = new Member();
$member->setName('Kévin');
$org = new Organization();
$org->setName('Les-Tilleuls.coop');
$org->setMembers(array($member));
$member->setOrganization($org);
echo $serializer->serialize($org, 'json'); // Throws a CircularReferenceException
所以,从这一点来说,你有3个解决方案可以摆脱这个问题:
循环引用也可以由自定义callables处理,而不是抛出异常。在序列化具有唯一标识符的实体时,这尤其有用:
$encoder = new JsonEncoder();
$normalizer = new ObjectNormalizer();
$normalizer->setCircularReferenceHandler(function ($object) {
return $object->getName();
});
$serializer = new Serializer(array($normalizer), array($encoder));
var_dump($serializer->serialize($org, 'json'));
// {"name":"Les-Tilleuls.coop","members":[{"name":"K\u00e9vin", organization: "Les-Tilleuls.coop"}]}
在你的情况下:
$encoder = new JsonEncoder();
$normalizer = new ObjectNormalizer();
normalizer->setIgnoredAttributes(array("account", "accountSheet", "category", "operation"));
$serializer = new Serializer(array($normalizer), array($encoder));
var_dump($serializer->serialize($org, 'json'));
Using Serialization Groups Annotations
例如,在您使用帐户实体的情况下,请在帐户端执行此操作:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use AppBundle\Entity\AbstractGenericEntity;
use Symfony\Component\Serializer\Annotation\Groups;
/**
* @ORM\Entity()
* @ORM\Table(name="accounts",
* uniqueConstraints={@ORM\UniqueConstraint(name="accounts_name_unique",columns={"name"})})
*/
class Account extends AbstractGenericEntity{
/**
* @ORM\OneToMany(targetEntity="AccountSheet", mappedBy="account")
* @var AccountSheet[]
* @Groups({"account"})
*/
protected $accountSheets;
public function __construct($name = null, $description = null){
$this->accountSheets = new ArrayCollection();
$this->name = $name;
$this->description = $description;
}
}
然后不要将此组注释放在AccountSheet实体的$ account字段中,以消除循环引用问题。
最后,您序列化您的帐户:
$encoder = new JsonEncoder();
$normalizer = new ObjectNormalizer();
$serializer = new Serializer(array($normalizer), array($encoder));
var_dump($serializer->serialize($account, 'json', array('groups' => array('account')) ));
答案 1 :(得分:2)
$jsonContent = $serializer->serialize($yourObject, 'json', [
'circular_reference_handler' => function ($object) {
return $object->getId();
}
]);
以上代码对我有用,可以修复循环引用异常。 (Symfony> = 4.2)