2010-08-09 15 views
6

Chcę wykonać głęboką kopię/klon zapisu doktryny w projekcie symfony. Istniejąca kopia ($ deep) -method nie działa poprawnie z $ deep = true.głęboka kopia zapisu doktrynowego

Na przykład rzućmy okiem na lekcję w klasie. Ta lekcja ma datę początkową i końcową, a pomiędzy nimi jest kilka przerw. Ta klasa jest w buildung.

Przerwa lekcyjna to relacja jeden-do-wielu, więc podczas lekcji może być dużo przerw. Budowanie lekcji jest relacją wiele do jednego, więc lekcja może być tylko w JEDNYM budynku.

Jeśli chcę zrobić kopię pokoju, należy również skopiować kopie. Budynek powinien pozostać taki sam (brak kopii tutaj).

Znalazłem kilka przykładów w Internecie, które tworzą klasę PHP, która rozciąga się od sfDoctrineRecord i nadpisuje metodę copy.

Co próbowałem było:

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

Teraz to powoduje wystąpienie błędu: Doctrine_Connection_Mysql_Exception: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '2-1' for key 'PRIMARY'

Więc muszę „null” Identyfikator nowego rekordu ($ ret), ponieważ to powinno być nowy rekord. Gdzie i jak mogę/powinienem to zrobić?

UPDATE: Błąd jest mocowana za pomocą następującego kodu:

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

Ale to nie działa dobrze. W lekcji DoctrineCollection-> Breaks wszystkie nowe przerwy są w porządku. Ale nie są one zapisane w bazie danych. Chcę skopiować nauczkę i dodać 7 dni na to czas:

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

Więc jak widać, przerwy są zapisywane, ale wydaje się, że nie są w db.

+0

Napisałem konkretną metodę do moich potrzeb. Ogólne rozwiązanie powoduje więcej problemów, niż rozwiązuje ... Cóż, obecnie nie rozwiązuje żadnego problemu :) – hering

Odpowiedz

0

Silnik czołgów Thomasa buchnie mi teraz do ucha, więc nie mogę skoncentrować się na drobniejszych punktach twojego pytania, ale brzmi to znajomo. Czy to odpowiada na twoje pytanie?

Copy a Doctrine object with all relations

Zasadniczo metoda Doctrine_Record::link() jest twoim przyjacielem :)

+1

faktycznie ... Złe pytanie przeczytałem. Odpowiedź, którą podałem, dotyczy tego, kiedy chcesz skopiować rekord, ale zachowaj oryginalne odniesienia, tj .: * nie * skopiuj powiązanych rekordów. Jestem gotów się założyć, że używasz Doctrine 1.0. Problem kopii (deep) został rozwiązany (wraz z wieloma innymi przydatnymi rzeczami, takimi jak synchronizeWithArray()) w Doctrine 1.2. Gdy głęboko skopiujesz do Doctrine 1.2, skopiujesz i zapiszesz odniesienia również nie będzie problemu. Nie wiem, czy aktualizacja do wersji 1.2 jest dla ciebie opcją ... –

+1

Właściwie dostałem wersję 1.4.4 :) – hering

+0

haha. o rację ... nieważne: D –

0

Działa to dla mnie, jest to wariant z kodu zapytania:

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

Nie mogę uwierzyć, że jestem praca z Doctrine 1.2 w 2017 roku.