Deep copy of doctrine

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.

+6
clone php deep-copy symfony1 doctrine
source share
2 answers

Thomas The tank engine will explode in my ear, so I can’t concentrate on the subtleties of your question, but that sounds familiar. Does this answer your question?

Copy a Doctrine object with all relationships

Basically the Doctrine_Record::link() method is your friend :)

0
source share

This works for me, this is an option from the question code:

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

I can not believe that I am working with Doctrine 1.2 in 2017.

0
source share

All Articles