Сущность, созданная в прослушивателе postRemove, не сохраняется

Я работаю над проектом на основе Symfony 2.8, который по сути представляет собой онлайн-адресную книгу.

EntityDeletionListener используется для обработки событий postRemove, чтобы добавить некоторую информацию в журнал удаления, который необходим для некоторого внутреннего бухгалтерского учета:

class EntityDeletionListener implements EventSubscriber {
    public function getSubscribedEvents() {
        return array('postRemove');
    }

    public function postRemove(LifecycleEventArgs $args) {
        $entity = $args->getEntity();

        if (!$entity->shouldAddToDeleteLog())
           return ;

        $em = $args->getEntityManager();
        $repo = $em->getRepository('AppBundle:DeleteLog');

        $log = $repo->createEntity();
        $log->setGuid($entity->getGuid());
        ...

        $em->persist($log);

        // Flush entity manager if not disabled in entity settings
        if ($entity->shouldFlushDeleteLog())
            $em->flush();
    }
}

Это работает без каких-либо проблем: каждый раз, когда объект Contact удаляется, запись в журнале удаления создается автоматически.

Сейчас я работаю над возможностью массового удаления любого количества выбранных Contacts. Чтобы ускорить процесс, менеджер сущностей очищается не после каждой операции удаления, а только после обработки некоторого пакета.

class ContactRepository extends EntityRepository {
    public function bulkDelete($guids) {
        $this->_em->getConnection()->beginTransaction();

        try {
            $batchSize = 100;
            $currentBatch = 0;           

            foreach ($guids as $guid) {
                $contact = $this->findOneByGuid($guid);

                if ($contact) {        
                    // DO NOT FLUSH EVERY DELETE LOG
                    $contact->setDeleteLogFlush(false);

                    $this->_em->remove($contact);

                    $currentBatch++;
                    if ($currentBatch % $batchSize === 0)
                        $this->_em->flush();
                }
            }

            $this->_em->flush();  
            $this->_em->getConnection()->commit();
        } catch (\Exception $ex) {            
            $this->_em->getConnection()->rollBack();
            return false;
        }
    }
}

Проблема 1: Если я использую $contact->setDeleteLogFlush(false), чтобы избежать автоматической очистки каждого DeleteLog, DeleteLogs не сохраняются вообще. Также объекты Contact удаляются правильно, и postRemove выполняется для каждой операции удаления, журналы не сохраняются в БД.

Нет никаких исключений или других ошибок, которые объясняли бы, почему журналы не сохраняются. Даже если произойдет ошибка, в этом случае полная транзакция должна завершиться неудачно, и Contacts также не будет удален. Но они удалены ...

Проблема 2: Если НЕ использовать $contact->setDeleteLogFlush(false), прослушиватель postRemove сбрасывает каждый новый DeleteLog, я получаю следующее исключение, как только удаляется сразу несколько записей:

Uncaught PHP Exception Symfony\Component\Debug\Exception\FatalThrowableError: "Type error: Argument 2 passed to Doctrine\DBAL\Connection::delete() must be of the type array, null given

Как это решить? Почему журналы, созданные в прослушивателе postRemove, не сохраняются при очистке диспетчера сущностей?

Не прочитал весь вопрос, но я бы посоветовал не сохранять журналы в базе данных (а лучше не в реляционной базе данных). У вас будут проблемы, если эти объекты будут расти (в количестве), и у вас возникнут проблемы при обращении к таблице. Используйте файл или базу данных NoSQL для таких операций.

DonCallisto 02.05.2018 17:56
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Symfony Station Communiqué - 17 февраля 2023 г
Symfony Station Communiqué - 17 февраля 2023 г
Это коммюнике первоначально появилось на Symfony Station , вашем источнике передовых новостей Symfony, PHP и кибербезопасности.
Управление ответами api для исключений на Symfony с помощью KernelEvents
Управление ответами api для исключений на Symfony с помощью KernelEvents
Много раз при создании api нам нужно возвращать клиентам разные ответы в зависимости от возникшего исключения.
0
1
958
1

Ответы 1

Я думаю, проблема в том, что вы хотите создать и удалить несколько объектов Contact, но делаете это не в том случае, потому что, как указано в документация

The postRemove event occurs for an entity after the entity has been deleted. It will be invoked after the database delete operations. It is not called for a DQL DELETE statement.

и вы не должны вносить никаких изменений в базу данных как указано здесь

postUpdate, postRemove, postPersist

The three post events are called inside EntityManager#flush(). Changes in here are not relevant to the persistence in the database, but you can use these events to alter non-persistable items, like non-mapped fields, logging or even associated classes that are not directly mapped by Doctrine.

Поэтому я бы просто переместил всю логику postRemove в событие preRemove, поскольку

The preRemove event is called on every entity when its passed to the EntityManager#remove() method. It is cascaded for all associations that are marked as cascade delete.

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