Symfony2克隆具有集合和实体字段类型的实体

时间:2015-03-30 13:19:51

标签: symfony clone symfony-forms

我有一个对象A,它包含一个对象集合B,而这些对象又包含一个对象集合C,它又包含一个对象集合。

我需要从DB中检索对象A,从中创建一个表单,在表单的字段中更改一些值(将来还可以在集合中添加和删除元素)并在DB上保留一个新的对象A适当引用新B,新C和新D。

下面的对象CVC是我的A.

如果我这样做:

    $storedCVC = $this->getDoctrine()
                      ->getRepository('AppBundle:CVC')
                      ->find($id);

    $clonedCVC = clone $storedCVC;
    $form = $this->createForm(new CVCFormType(), $ClonedCVC);

当我转储两个对象时,AI会看到对象A的不同引用,但是当我挖掘对象C,B和D级别时,引用与原始对象相同(我们可能期望“浅”克隆,见下面的截图)。

尽管如此,它还是正确地创建了新对象A,并且(毫无疑问)它也会持久保存新对象B,C和D(可能是因为我在每个父子关系中指定了以下持久性):

/**
 * @ORM\ManyToOne(targetEntity="CVC", cascade={"persist"}, inversedBy="BenefitItems")
 */
protected $CVC; 

请注意,BenefitItems是我的对象B.当然,在对象A中我有:

/**
 * @ORM\oneToMany(targetEntity="BenefitItem", mappedBy="CVC")
 */    
protected $BenefitItems;

到目前为止一直很好(虽然对我来说很神秘)。当我尝试映射属于对象C的实体类型字段(典型的“类别”字段)时出现问题。当我在表单上更新该实体时,它也会更新原始类别。

我尝试了以下操作来执行深度克隆:

function cloneCVC ($oldCVC) {
$newCVC = new CVC();
foreach ($oldCVC->getBenefitItems() as $oldBI)
    {
    $newBI = new BenefitItem();
    foreach ($oldBI->getBenefitGroups() as $oldBG)
        {
        $newBG = new BenefitGroup();
        foreach ($oldBG->getBenefitSubItems() as $oldSI)
            {
            $newSI = new BenefitSubItem();
            $newSI->setComment($oldSI->getComment());
            $newBG->addBenefitSubItem($newSI);
            }
        $newBG->setBenefitGroupCategory($oldBG->getBenefitGroupCategory());
        $newBI->addBenefitGroup($newBG);
        }
    $newBI->setComment($oldBI->getComment());

    $newCVC->addBenefitItem($newBI);
    }
return $newCVC;
}

问题是我创建的对象不同,所以当我尝试在其上调用create表单时它会失败:

enter image description here

任何帮助?

编辑:关系是A-> B-> C-> D因此我认为与Stepan存在误解。然后我们有C-> E,它是实体类型字段的关系。

在我的代码中:

A = CVC
B = BenefitItem
C = BenefitGroup
D = BenefitSubItem
E = BenefitGroupCategory

下面建议的代码在CVC中正常工作(我现在确实对BenefitItems数组有不同的引用,请参见下面的红线)但即使我在CVC中执行以下操作:

public function __clone()
{
    if ($this->id) {
        $this->id = null;
        $this->BenefitItems = clone $this->BenefitItems;
    }
}

不会发生福利项目的克隆(参见黄色和浅蓝色线条)。福利项目实体内的代码是:

public function __clone()
{
    if ($this->id) {
        $this->id = null;
        $this->BenefitGroups = clone $this->BenefitGroups;
    }
}

但它永远不会进入if。我改变了

$this->id = null

$this->idXXX = null

导致错误但不会被调用。

我应该简单地删除if?

以下是视觉上的情况:

enter image description here

1 个答案:

答案 0 :(得分:2)

您必须在实体中实现__clone()方法,将id设置为null并根据需要克隆关系。因为如果您将ID保留在相关对象中,则会假定您的新实体A与现有实体BC有关系。

A的克隆方法:

public function __clone() {
    if ($this->id) {
        $this->setId(null);
        $this->B = clone $this->B;
        $this->C = clone $this->C;
    }
}

BC的克隆方法:

public function __clone() {
    if ($this->id) {
        $this->setId(null);
    }
}

https://groups.google.com/forum/?fromgroups=#!topic/doctrine-user/Nu2rayrDkgQ

https://doctrine-orm.readthedocs.org/en/latest/cookbook/implementing-wakeup-or-clone.html