Symfony, Доктрина: как отключить Entity Listeners?

Мне нужно сохранить некоторые фикстуры с помощью Alice Fixtures Bundle, не запуская определенный Entity Listener. Слушатель связан с моей сущностью через аннотацию EntityListeners. Я бы предпочел не менять самого слушателя.

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

Я уже пробовал этот ответ, но $em->getEventManager()->getListeners() не возвращает Entity Listeners.

ClassMetadata дает мне список подписанных Entity Listeners для этого объекта, но это просто массив только для чтения.

Есть ли способ отключить эти прослушиватели сущностей?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать 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 нам нужно возвращать клиентам разные ответы в зависимости от возникшего исключения.
8
0
2 367
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Я нашел способ. Вот что я делаю в загрузчике:

$em = $this->container->get('doctrine.orm.default_entity_manager');

$entitiesWithListeners = [
    Post::class,
    Comment::class
];

$listenersToDisable = [
    MyListener::class
];

foreach ($entitiesWithListeners as $entity) {
    $metadata = $em->getMetadataFactory()->getMetadataFor($entity);

    foreach ($metadata->entityListeners as $event => $listeners) {
        
        foreach ($listeners as $key => $listener) {
            if (in_array($listener['class'], $listenersToDisable)) {
                unset($listeners[$key]);
            }
        }
        $metadata->entityListeners[$event] = $listeners;
    }
    $em->getMetadataFactory()->setMetadataFor($entity, $metadata);
}

Я просто получаю метаданные для каждой сущности, удаляю их из моих Entity Listeners и возвращаю в соответствующий класс.

Это некрасиво, но это работает. Поскольку на данный момент я застрял с AliceBundle v1.4, и мне придется все изменить, когда мы обновим проект, это подойдет.

Поскольку $ metadata является объектом и из-за того, как объекты передаются по этой строке, $ em-> getMetadataFactory () -> setMetadataFor ($ entity, $ metadata); является избыточным. Большое спасибо за публикацию, это сэкономило мне кучу времени.

vitoriodachef 20.07.2021 15:08

Вы можете использовать EntityListenerResolver API

$em->getConfiguration()->getEntityListenerResolver()->clear();

или если вы хотите очистить слушателя определенного класса

$em->getConfiguration()->getEntityListenerResolver()->clear(YourEntityListener::class);

Обратитесь к интерфейсу EntityListenerResolver для получения дополнительной информации.

Когда я вызываю глобальный метод clear(), кажется, что он действительно отключает некоторые прослушиватели сущностей, некоторые из которых я не хочу отключать. Но когда я вызываю его именем класса, который хочу удалить слушателей, это не работает. ListenersInvoker по-прежнему вызывает этого слушателя из метаданных.

vctls 28.11.2018 12:20

Конечно, он очищает все прослушиватели сущностей, если вы не передаете аргумент, но вы можете передать определенный класс для отключения. Проверьте мой обновленный ответ.

DrKey 28.11.2018 12:23

Извините, я редактировал свой комментарий. Сдать урок по какой-то причине не удалось. Отлаживаю стек, посмотрю, понимаю, как это работает ...

vctls 28.11.2018 12:25

На самом деле я не вижу, где EntityListenerResolver может пригодиться. Например: в UnitOfWork :: persistNew () единственное, что определяет, вызываются ли слушатели, - это ListenersInvoker, который, по-видимому, полагается исключительно на метаданные класса. github.com/doctrine/doctrine2/blob/…

vctls 28.11.2018 12:46

Ха, собирался прокомментировать это, но я вижу, вы только что исправили этот ответ;) Да, это действительно работает с именем класса слушателя.

vctls 28.11.2018 12:59

Извините, я только что попробовал и заметил, что вам нужно передать класс слушателя, а не класс сущности. Таким образом, вы либо явно перебираете свой класс слушателей, либо свои сущности, а затем связанные слушатели, которые вы получаете от $em->getMetadataFactory()->getMetadataFor($entityClass)->ent‌​ityListeners.

DrKey 28.11.2018 13:00

Подожди, нет, что-то не так Один слушатель все еще активен.

vctls 28.11.2018 13:06

Я отлаживаю ContainerAwareListenerResolver, и по какой-то причине мой слушатель не указан в свойстве instances, а в serviceIds, поэтому метод clear() не удаляет его.

vctls 28.11.2018 13:09

Может быть, потому, что этот конкретный слушатель объявлен ленивым сервисом?

vctls 28.11.2018 13:16

Ага, вот и все. Слушатели объектов, помеченные как «ленивые», не регистрируются как «экземпляры» в ContainerAwareEnityListenerResolver и не могут быть очищены таким образом.

vctls 28.11.2018 13:29

На мой взгляд, это похоже на ошибку, но полезно знать, я не знал об этом, спасибо :)

DrKey 28.11.2018 13:38

Позвольте нам продолжить обсуждение в чате.

vctls 28.11.2018 13:40

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