2010-08-09 12 views
6

Ich möchte eine tiefe Kopie/Klon eines Doktrin Datensatzes in einem symfony Projekt machen. Die vorhandene Kopie ($ deep) -Methode funktioniert nicht ordnungsgemäß mit $ deep = true.tiefe Kopie der Doktrin

Für ein Beispiel schauen wir uns eine Unterrichtseinheit an. Diese Lektion hat ein Start- und Enddatum und dazwischen gibt es mehrere Pausen. Dieses Klassenzimmer befindet sich in einem Gebäude.

Lektionen brechen ist eine Eins-zu-viele-Beziehung, so dass viele Pausen in einer Lektion sein können. Das Lernen von Unterricht ist eine Beziehung, in der viele miteinander in Beziehung stehen, so dass eine Lektion nur in EINEM Gebäude stattfinden kann.

Wenn ich eine Kopie des Zimmers machen möchte, sollten die Pausen auch kopiert werden. Das Gebäude sollte gleich bleiben (keine Kopie hier).

Ich habe einige Beispiele im Web gefunden, die eine PHP-Klasse erstellen, die sich von sfDoctrineRecord erstreckt und die Kopiermethode überschreibt.

Was ich versucht war:

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

Jetzt führt dies zu einem Fehler: Doctrine_Connection_Mysql_Exception: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '2-1' for key 'PRIMARY'

Also habe ich die ID des neuen Datensatzes ($ ret) auf "null" müssen, weil dies eine sein sollte, Neuer Eintrag. Wo und wie könnte/sollte ich es tun?

UPDATE: Der Fehler mit folgendem Code festgelegt ist:

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

Aber es funktioniert nicht gut. In der DoctrineCollection-Lektion-> Pausen sind alle neuen Pausen in Ordnung. Sie werden jedoch nicht in der Datenbank gespeichert. Ich mag eine Lektion kopieren und 7 Tage in dem es an der Zeit:

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 wie Sie sehen, sind die Pausen gespeichert, aber es scheint, dass sie nicht in der db sind.

+0

Ich habe eine spezielle Methode für meine Bedürfnisse geschrieben. Die generische Lösung erzeugt mehr Probleme als sie löst ... Nun, im Moment löst sie überhaupt kein Problem :) – hering

Antwort

0

Thomas die Tank Engine spritzt gerade in mein Ohr, so dass ich mich nicht wirklich auf die Feinheiten Ihrer Frage konzentrieren kann, aber es kommt mir bekannt vor. Beantwortet das deine Frage?

Copy a Doctrine object with all relations

Grundsätzlich ist die Doctrine_Record::link() Methode ist dein Freund :)

+1

eigentlich ... Ich habe deine Frage falsch gelesen. Die Antwort, die ich gab, ist, wenn Sie einen Datensatz kopieren möchten, aber behalten Sie die ursprünglichen Referenzen, d. h .: * nicht * kopieren Sie die zugehörigen Datensätze. Ich wette, dass Sie Doctrine 1.0 verwenden. Das Kopierproblem wurde (zusammen mit vielen anderen nützlichen Dingen wie synchronizeWithArray()) in Doctrine 1.2 gelöst. Wenn Sie Doctrine 1.2 tief kopieren, wird es auch die Referenzen kopieren und speichern, kein Problem. Ich weiß nicht, ob ein Upgrade auf 1.2 für Sie eine Option ist ... –

+1

Eigentlich habe ich Version 1.4.4 :) – hering

+0

haha. oh richtig ... macht nichts: D –

0

Dies funktioniert für mich, es ist eine Variante von der Frage 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; 
} 

Ich kann nicht glauben, ich bin Arbeiten mit Doctrine 1.2 in 2017.

Verwandte Themen