I want to make a deep copy / clone of a doctrine entry in a symfony project. The existing copy method ($ deep) does not work properly with $ deep = true.
As an example, consider a lesson in a classroom. This lesson has a start and end date, and there are several gaps between them. This class is in the building.
lesson-break is a one-to-many relationship, so there can be many breaks in a lesson. A building lesson is a one-to-one relationship, so a lesson can only be in ONE building.
If I want to make a copy of the room, I also need to copy the breaks. The building should remain unchanged (no copy here).
I found several examples on the Internet that create a PHP class that extends from sfDoctrineRecord and overrides the copy method.
What I tried was:
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; } }
Now this leads to a crash: Doctrine_Connection_Mysql_Exception: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '2-1' for key 'PRIMARY'
Therefore, I need to βnullifyβ the new record identifier ($ ret), because it must be a new record. Where and how could I do this?
UPDATE: Error fixed by the following code:
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; } }
But that does not work. In the DoctrineCollection-> Breaks lesson, all new breaks are in order. But they are not stored in the database. I want to copy the lesson and add 7 days to it:
foreach($new_shift->Breaks as $break) { $break->start_at = $this->addOneWeek($break->start_at); $break->end_at = $this->addOneWeek($break->end_at); $break->save(); }
So, as you can see, the gaps remain, but they don't seem to be in db.
clone php deep-copy symfony1 doctrine
hering
source share