Мне нужно сохранить некоторые фикстуры с помощью Alice Fixtures Bundle, не запуская определенный Entity Listener.
Слушатель связан с моей сущностью через аннотацию EntityListeners.
Я бы предпочел не менять самого слушателя.
Я создал собственный загрузчик, у которого есть доступ к контейнеру, в надежде отключить всех слушателей перед созданием моих объектов.
Я уже пробовал этот ответ, но $em->getEventManager()->getListeners() не возвращает Entity Listeners.
ClassMetadata дает мне список подписанных Entity Listeners для этого объекта, но это просто массив только для чтения.
Есть ли способ отключить эти прослушиватели сущностей?




Я нашел способ. Вот что я делаю в загрузчике:
$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, и мне придется все изменить, когда мы обновим проект, это подойдет.
Вы можете использовать EntityListenerResolver API
$em->getConfiguration()->getEntityListenerResolver()->clear();
или если вы хотите очистить слушателя определенного класса
$em->getConfiguration()->getEntityListenerResolver()->clear(YourEntityListener::class);
Обратитесь к интерфейсу EntityListenerResolver для получения дополнительной информации.
Когда я вызываю глобальный метод clear(), кажется, что он действительно отключает некоторые прослушиватели сущностей, некоторые из которых я не хочу отключать. Но когда я вызываю его именем класса, который хочу удалить слушателей, это не работает. ListenersInvoker по-прежнему вызывает этого слушателя из метаданных.
Конечно, он очищает все прослушиватели сущностей, если вы не передаете аргумент, но вы можете передать определенный класс для отключения. Проверьте мой обновленный ответ.
Извините, я редактировал свой комментарий. Сдать урок по какой-то причине не удалось. Отлаживаю стек, посмотрю, понимаю, как это работает ...
На самом деле я не вижу, где EntityListenerResolver может пригодиться. Например: в UnitOfWork :: persistNew () единственное, что определяет, вызываются ли слушатели, - это ListenersInvoker, который, по-видимому, полагается исключительно на метаданные класса. github.com/doctrine/doctrine2/blob/…
Ха, собирался прокомментировать это, но я вижу, вы только что исправили этот ответ;) Да, это действительно работает с именем класса слушателя.
Извините, я только что попробовал и заметил, что вам нужно передать класс слушателя, а не класс сущности. Таким образом, вы либо явно перебираете свой класс слушателей, либо свои сущности, а затем связанные слушатели, которые вы получаете от $em->getMetadataFactory()->getMetadataFor($entityClass)->entityListeners.
Подожди, нет, что-то не так Один слушатель все еще активен.
Я отлаживаю ContainerAwareListenerResolver, и по какой-то причине мой слушатель не указан в свойстве instances, а в serviceIds, поэтому метод clear() не удаляет его.
Может быть, потому, что этот конкретный слушатель объявлен ленивым сервисом?
Ага, вот и все. Слушатели объектов, помеченные как «ленивые», не регистрируются как «экземпляры» в ContainerAwareEnityListenerResolver и не могут быть очищены таким образом.
На мой взгляд, это похоже на ошибку, но полезно знать, я не знал об этом, спасибо :)
Позвольте нам продолжить обсуждение в чате.
Поскольку $ metadata является объектом и из-за того, как объекты передаются по этой строке, $ em-> getMetadataFactory () -> setMetadataFor ($ entity, $ metadata); является избыточным. Большое спасибо за публикацию, это сэкономило мне кучу времени.