2010-08-09 30 views
6

Symfony projesinde bir doktrin kaydının derin bir kopyasını/kopyasını yapmak istiyorum. Mevcut kopya ($ deep) -method, $ deep = true ile düzgün çalışmıyor.Doktrin kaydının derin kopyası

Örneğin bir sınıf dersine bir göz atalım. Bu dersin bir başlangıç ​​ve bitiş tarihi vardır ve aralarında birkaç mola vardır. Bu sınıf bir yapı içinde.

ders-arası bire-bir ilişkidir, bu nedenle derste çok fazla mola olabilir. ders-bina bire-bir ilişkidir, bu yüzden bir ders sadece ONE Building'de olabilir.

Odanın bir kopyasını yapmak istersem, kopmalar da kopyalanmalıdır. Bina aynı kalmalıdır (burada kopya yok).

Web'de sfDoctrineRecord'dan genişleyen ve kopyalama yöntemini geçersiz kılan bir PHP sınıfı oluşturan bazı örnekler buldum. Denedim ne

oldu:

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

Şimdi bu başarısızlıkla neden olur:

yüzden yeni kayıt ($ ret) arasında "boş" id bu olmalı, çünkü gerek Doctrine_Connection_Mysql_Exception: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '2-1' for key 'PRIMARY' Yeni Rekor. Nerede ve nasıl yapabilirim?

GÜNCELLEME: hata aşağıdaki kodla sabittir:

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

Ama iyi çalışmaz. DoctrineCollection dersinde -> Tüm yeni molalar iyi. Ama veritabanına kayıtlı değiller. Ben bir ders kopyalayıp zamanı geldi 7 gün eklemek istiyorum: Gördüğünüz gibi

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

Yani, sonları kaydedilir, ancak bunların db değildir görünüyor.

+0

Gereksinimlerim için özel bir yöntem yazdım. Genel çözüm çözdüğünden daha fazla sorun üretir ... Peki, şu anda herhangi bir problemi çözmüyor :) – hering

cevap

0

Thomas the Tank Engine şu anda kulağımda patlıyor, bu yüzden sorunuzun daha hassas noktalarına konsantre olamıyorum, ama tanıdık geliyor. Bu sorunuza cevap veriyor mu?

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

ben inanamıyorum:

Copy a Doctrine object with all relations

Temelde Doctrine_Record::link() yöntem arkadaşın :) Bu benim için çalışıyor

+1

aslında ... Sorunu yanlış okudum. Verdiğim cevap, bir kaydı kopyalamak istediğinizde, ancak orijinal referansları saklamak için, yani: * değil * ilgili kayıtları kopyalamak içindir. Doctrine 1.0'ı kullandığınıza bahse girerim. Kopyalama (derin) sorunu, Doctrine 1.2'de (synchronizeWithArray() gibi diğer birçok yararlı şeyle birlikte) çözülür. Doctrine 1.2'de derinlemesine kopyalarken, referansları kopyalayıp kaydetmeyecek ve sorun olmayacaktır. Ancak, 1.2'ye yükseltmenin bir seçenek olup olmadığını bilmiyorum ... –

+1

Aslında 1.4.4 sürümüne sahibim :) – hering

+0

haha. oh doğru ... boşver: D –

0

, bu soru kodundan bir varyant var 2017 yılında Doctrine 1.2 ile çalışma.