Создание / сохранение нового документа во время события preUpdate в doctrine-mongodb

Я использую doctrine-mongodb-odm-1.0.0-BETA10 и пытается обеспечить некоторую пользовательскую логику на основе \InitialDocument в то время как preUpdate событие работает.

Допустим \InitialDocument получил некоторое состояние, которое должно вести себя как начальное для нового \StateDocument, Я делаю что-то вроде этого:

class InitDocListener implements \Doctrine\Common\EventSubscriber {
    public function getSubscribedEvents()
    {
        return [
            Events::preUpdate
        ];
    }

    public function preUpdate($args){
        $document = $args->getDocument();
        if($document instanceOf InitialDocument && $document->getState() == 'mine'){
            $stateDocument = new \StateDocument();
            $stateDocument->setInitDocument($document);
            $args->getDocumentManager()->persist($stateDocument);
            //no flush cause recursion happens
        }
    }

}

prePersist событие от \StateDocument случается, но он не сохранит новый документ в БД. а также postPersist Событие соответственно никогда не будет запущено.

Есть еще немного пользовательской логики, но все в области событий. В какой-то момент эта логика может вызвать исключение, которое должно остановить событие обновления InitialDocument так InitialDocument состояние зависит от \StateDocument процесс создания в сфере бизнеса.

Как я могу решить эту проблему? preFlush событие для запуска до пересчета changeSet не определить InitialDocument пример. Так что это какой-то трюк для "поиска" обновлений на preFlush и заставить меня думать, что это не правильный путь. Пожалуйста, посоветуйте мне правильно. Благодарю.

1 ответ

Я создал тестовый пример для вашего варианта использования здесь. Одна вещь, которая выделялась из кода в вашем вопросе, заключалась в том, что вы не звонили recomputeSingleDocumentChangeSet() в документе, который вы изменяли во время обратного вызова жизненного цикла, как указано в preUpdate документация Но даже с этим вызовом новый документ не будет вставлен. Это связано с тем, что UnitOfWork выполняет обновления после вставок и загрузок. Полный заказ можно увидеть в UnitOfWork's commit() метод:

  • Документ upserts
  • Вставки документов
  • Обновление документа
  • Дополнительные обновления (запланированные внутри постоянных классов)
  • Удаление коллекций
  • Обновления коллекции
  • Удаление документов

Когда preUpdate событие отправлено, upserts/inserts для новых документов уже произошло. Даже с призывом recomputeSingleDocumentChangeSet() Вы заканчиваете тем, что планировали документ для вставки, но UnitOfWork игнорирует это и в конечном итоге отменяет его при очистке всех очередей расписания здесь.

В то время как ODM может легко проверить наличие дополнительных вставок после обработки обновлений, в некоторых ситуациях это может привести к бесконечному циклу. Заказ UnitOfWork предшествовал моей работе над проектом, но я рискую зацикливаться, возможно, была проблема, когда была задумана первоначальная реализация.

В качестве обходного пути вы можете захотеть, чтобы слушатель выгрузил новые документы для вставки в какой-то другой контейнер (или сам слушатель), а затем проверил после факта наличие дополнительных документов для сохранения / очистки.

Другие вопросы по тегам