6

symfony プロジェクトでドクトリン レコードのディープ コピー/クローンを作成したいと考えています。既存の copy($deep) メソッドは $deep=true では正しく動作しません。

例として、教室でのレッスンを見てみましょう。このレッスンには開始日と終了日があり、その間にいくつかの休憩があります。この教室はビルの中にあります。

レッスンと休憩は 1 対多の関係であるため、多くの休憩がレッスン内にある可能性があります。レッスンと建物は多対 1 の関係であるため、レッスンは 1 つの建物にしか存在できません。

部屋のコピーを作成したい場合は、休憩もコピーする必要があります。建物は同じままである必要があります (ここにコピーはありません)。

sfDoctrineRecord から拡張して copy-method をオーバーライドする PHP クラスを作成する Web 上の例をいくつか見つけました。

私が試したのは:

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

これにより、失敗が発生します。Doctrine_Connection_Mysql_Exception: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '2-1' for key 'PRIMARY'

したがって、これは新しいレコードである必要があるため、新しいレコード ($ret) の ID を「null」にする必要があります。どこで、どのようにすればよいですか?

更新: エラーは次のコードで修正されています。

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

しかし、うまくいきません。DoctrineCollection レッスン -> ブレークでは、新しいブレークはすべて問題ありません。ただし、データベースには保存されません。レッスンをコピーして、その時間に 7 日間を追加したい:

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

ご覧のとおり、休憩は保存されていますが、データベースにはないようです。

4

1 に答える 1