глубокая копия доктрины - PullRequest
       15

глубокая копия доктрины

6 голосов
/ 09 августа 2010

Я хочу сделать глубокую копию / клон записи доктрины в проекте Symfony. Существующий метод копирования ($ deep) не работает должным образом с $ deep = true.

Для примера давайте посмотрим на урок в классе. У этого урока есть дата начала и окончания, и между ними есть несколько перерывов. Этот класс находится в здании.

перерыв в уроке - это отношение один ко многим, поэтому в уроке может быть много перерывов. построение урока - это отношения многих к одному, поэтому урок может быть только в ОДНОМ здании.

Если я хочу сделать копию комнаты, перерывы также должны быть скопированы. Здание должно остаться прежним (здесь нет копии).

Я нашел несколько примеров в Интернете, которые создают класс PHP, который выходит из sfDoctrineRecord и переопределяет метод копирования.

То, что я пробовал, было:

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), потому что это должна быть новая запись. Где и как я мог / должен это сделать?

UPDATE: Ошибка исправлена ​​с помощью следующего кода:

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

Итак, как вы видите, разрывы сохраняются, но, похоже, их нет в БД.

1 Ответ

0 голосов
/ 05 апреля 2017

Это работает для меня, это вариант из кода вопроса:

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

Не могу поверить, что я работаю с Doctrine 1.2 в 2017 году.

...