Symfony2使用集合和实体字段类型克隆实体 [英] Symfony2 Cloning entities with collections and entity field type

查看:89
本文介绍了Symfony2使用集合和实体字段类型克隆实体的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有对象A,其中包含对象B的集合,对象B又包含对象C的集合,对象C又包含对象D的集合。



我需要从数据库中检索对象A,从中创建表单,更改表单字段中的某些值(以后还将在集合中添加和删除元素),并在DB上持久保存具有新对象A的所有适当引用的新对象A ,新的C和新的D。



下面的对象CVC是我的A。



如果我这样做:

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

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

当我丢弃两个对象AI时,看到对象A的引用不同,但是当我挖掘对象时C,B和D级别,引用与原始引用相同(我们可能期望从浅克隆获得,请参见下面的屏幕截图)。



尽管如此,它还是正确的创建新对象A并(还令人惊奇地)还保留了新对象B,C和D(可能是因为我在每个父子关系上指定了以下持久性对象):

  / ** 
* @ ORM\ManyToOne(targetEntity = CVC,级联= { persist},inversedBy = BenefitItems)
* /
受保护的CVC;

请注意,BenefitItems是我的对象B。当然,对象AI中有:

  / ** 
* @ ORM\oneToMany(targetEntity = BenefitItem,mappingBy = CVC)
* /
受保护的$ BenefitItems;

到目前为止,一切都很好(尽管对我来说很晦涩)。当我尝试映射属于对象C的实体类型字段(典型的类别字段)时,就会出现问题。当我在表单上更新该实体时,它还会更新原始类别。



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

  function cloneCVC($ oldCVC){
$ newCVC =新的CVC();
foreach($ oldCVC-> getBenefitItems()as $ oldBI)
{
$ newBI = new BenefitItem();
foreach($ oldBI-> getBenefitGroups()as $ oldBG)
{
$ newBG = new BenefitGroup();
foreach($ oldBG-> getBenefitSubItems()为$ 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);
}
返回$ newCVC;
}

问题是我创建的对象是不同的,所以当我尝试调用失败的创建表单:





有帮助吗?



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



在我的代码中:

  A = CVC 
B = BenefitItem
C = BenefitGroup
D = BenefitSubItem
E = BenefitGroup类别

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

 公共函数__clone()
{
if($ this-> ; id){
$ this-> id = null;
$ this-> BenefitItems =克隆$ this-> BenefitItems;
}
}

福利项目的克隆未发生(请参见黄色和浅蓝色线条)。福利项目实体内部的代码为:

 公共函数__clone()
{
if($ this-> id){
$ this-> id = null;
$ this-> BenefitGroups =克隆$ this-> BenefitGroups;
}
}

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



$ this-> id = null



with



$ this-> idXXX = null



会导致错误,但不会被调用)。



我是否只需消除if?



视觉上是这样:



解决方案

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



A 的克隆方法:

 公共函数__clone(){
if($ this-&id; id){
$ this-> setId(null);
$ this-> B =克隆$ this-&B;
$ this-> C =克隆$ this-> C;
}
}

B的克隆方法 C

 公共函数__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


I have object A which contains a collection of objects B which in turn contain a collection of objects C which again contains a collection of object D.

I need to retrieve object A from DB, create a form from it, change some values in fields of the form (in the future also add and remove elements from the collections) and persist on DB a new object A with all the appropriate references to the new B, new C and new D.

The object CVC below is my A.

If I do:

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

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

When I dump the two objects A I see a different references for objects A, but when I dig to objects C, B and D level, the references are the same as the original (what we might expect from a "shallow" clone, see screenshot below).

Nonetheless it properly creates the new object A and (surpsingly) it also persists the new objects B, C and D as well (could it be because I specified the following persist on each father-child relationship):

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

Note that BenefitItems is my object B. Of course in object A I have:

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

So far so good (albeit misterious to me). The problem arises when I try to map an entity type field (the typical "category" field), which belongs to object C. When I update that entity on the form, it updates also the original category.

I tried the following to perform a deep clone:

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;
}

The problem is that the object I create is different, so when I try to call the create form on it it fails:

Any help?

EDIT: the relationship is A->B->C->D so I assume there was a misunderstanding with Stepan. Then we have C->E that is the relationship for the entity type field.

In my code:

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

The code suggested below properly works in CVC (I indeed have different references now to the arrays of BenefitItems, see red lines below) but even if I do the following inside CVC:

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

the clone of the benefit items does not happen (see yellow and light blue lines). The code inside the benefit item entity is:

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

But it never gets into the if. I changed

$this->id = null

with

$this->idXXX = null

to cause an error but it doesn't get called).

Shall I simply eliminate the if?

Here is the situation visually:

解决方案

You have to implement a __clone() method in your entities that sets the id to null and clones the relations if desired. Because if you keep the id in the related object it assumes that your new entity A has a relation to the existing entities B and C.

Clone-method for A:

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

Clone-method for B and C:

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

这篇关于Symfony2使用集合和实体字段类型克隆实体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆