her*_*ing 6 php doctrine symfony1 clone deep-copy
我想在symfony项目中对doctrine记录进行深层复制/克隆.使用$ deep = true,现有副本($ deep)-method无法正常工作.
举个例子,我们来看看课堂课程.本课有一个开始和结束日期,它们之间有几个休息时间.这个教室正在建设中.
课间休息是一对多的关系,因此课程中可能会有很多休息时间.课程建设是一种多对一的关系,所以课程只能在一栋楼里.
如果我想复制房间,也应该复制休息时间.建筑应该保持不变(这里没有副本).
我在网上找到了一些示例,它们创建了一个PHP类,它从sfDoctrineRecord扩展并覆盖了copy-method.
我试过的是:
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;
}
}
Run Code Online (Sandbox Code Playgroud)
现在这会导致失败: Doctrine_Connection_Mysql_Exception: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '2-1' for key 'PRIMARY'
所以我需要"取消"新记录($ ret)的id,因为这应该是一个新记录.我应该在哪里以及如何做?
更新:错误已通过以下代码修复:
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;
}
}
Run Code Online (Sandbox Code Playgroud)
但它效果不好.在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();
}
Run Code Online (Sandbox Code Playgroud)
如你所见,中断被保存,但似乎它们不在数据库中.
这对我有用,它是问题代码的变体:
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;
}
Run Code Online (Sandbox Code Playgroud)
我不敢相信我在 2017 年就在使用 Doctrine 1.2。