Doctrine记录的深度复制

6
我希望能在Symfony项目中对Doctrine记录进行深度复制/克隆。 现有的copy($deep)方法无法正确处理$deep=true。
例如,我们来看一个课堂教学案例。这节课有开始和结束日期,在它们之间有几个休息时间。这个教室位于一个建筑物内。 lesson-break是一对多的关系,因此许多休息时间可能包含在一节课中。 lesson-building是多对一的关系,因此一节课只能在一个建筑物中。
如果我想复制房间,则应该同时复制休息时间。建筑物应保持不变(不进行复制)。
我在网上找到了一些示例,创建了一个PHP类,继承自sfDoctrineRecord并覆盖了copy方法。
我尝试过:
class BaseDoctrineRecord extends sfDoctrineRecord {
    public function copy($deep = false) {
        $ret = parent::copy(false);
        if (!$deep)
            return $ret;

        // ensure to have loaded all references (unlike Doctrine_Record)
        foreach ($this->getTable()->getRelations() as $name => $relation) {
            // ignore ONE sides of relationships
            if ($relation->getType() == Doctrine_Relation::MANY) {
                if (empty($this->$name))
                    $this->loadReference($name);

                // do the deep copy
                foreach ($this->$name as $record)
                    $ret->{$name}[] = $record->copy($deep);
            }
        }
        return $ret;
    }
}

现在这导致了一个失败:Doctrine_Connection_Mysql_Exception: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '2-1' for key 'PRIMARY'

所以我需要将新记录($ret)的id设置为“null”,因为这应该是一条新记录。在哪里和如何可以/应该做到这一点?

更新: 以下代码修复了错误:

class BaseDoctrineRecord extends sfDoctrineRecord {
    public function copy($deep = false)  {
        $ret = parent::copy(false);

        if($this->Table->getIdentifierType() === Doctrine_Core::IDENTIFIER_AUTOINC) {
            $id = $this->Table->getIdentifier();
            $this->_data[$id] = null;
        }

        if(!$deep) {
            return $ret;
        }

        // ensure to have loaded all references (unlike Doctrine_Record)
        foreach($this->getTable()->getRelations() as $name => $relation) {
            // ignore ONE sides of relationships
            if($relation->getType() == Doctrine_Relation::MANY) {
                if(empty($this->$name)) {
                    $this->loadReference($name);
                }

                // do the deep copy
                foreach($this->$name as $record) {
                    $ret->{$name}[] = $record->copy($deep);
                }
            }
        }

        return $ret;
    }
}

但情况并不理想。在DoctrineCollection课程中,所有新添加的断点都很好,但它们没有保存到数据库中。 我想复制一堂课,并将其时间延长7天:

foreach($new_shift->Breaks as $break) {
    $break->start_at = $this->addOneWeek($break->start_at);
    $break->end_at = $this->addOneWeek($break->end_at);
    $break->save();
}

正如您所看到的,这些断点已经被保存了,但是似乎它们并没有在数据库中。


我为我的需求编写了一个特定的方法。通用解决方案会产生更多的问题,而不是解决问题... 好吧,目前它根本没有解决任何问题 :) - hering
1个回答

0

这对我有用,它是从问题代码的变体:

public function realCopy($deep = false) {
    $ret = self::copy(false);

    if(!$deep) {
        return $ret;
    }

    // ensure to have loaded all references (unlike Doctrine_Record)
    foreach($this->getTable()->getRelations() as $name => $relation) {
        // ignore ONE sides of relationships
        if($relation->getType() == Doctrine_Relation::MANY) {
            if(empty($this->$name)) {
                $this->loadReference($name);
            }

            // do the deep copy
            foreach($this->$name as $record) {
                $ret->{$name}[] = $record->realCopy($deep);
            }
        }
    }

    // this need to be at the end to ensure Doctrine is able to load the relations data
    if($this->Table->getIdentifierType() === Doctrine_Core::IDENTIFIER_AUTOINC) {
        $id = $this->Table->getIdentifier();
        $this->_data[$id] = null;
    }

    return $ret;
}

我简直不敢相信在2017年我还在使用Doctrine 1.2。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接