Внедрение SecurityContext в прослушиватель prePersist или preUpdate в Symfony2, чтобы получить пользователя в созданномBy или updatedBy вызывает ошибку круговой ссылки

Я настраиваю класс слушателя, где я установлю столбец ownerid в любой доктрине prePersist. Мой файл services.yml выглядит так …

services: my.listener: class: App\SharedBundle\Listener\EntityListener arguments: ["@security.context"] tags: - { name: doctrine.event_listener, event: prePersist } 

и мой класс выглядит так …

 use Doctrine\ORM\Event\LifecycleEventArgs; use Symfony\Component\Security\Core\SecurityContextInterface; class EntityListener { protected $securityContext; public function __construct(SecurityContextInterface $securityContext) { $this->securityContext = $securityContext; } /** * * @param LifecycleEventArgs $args */ public function prePersist(LifecycleEventArgs $args) { $entity = $args->getEntity(); $entityManager = $args->getEntityManager(); $entity->setCreatedby(); } } 

Результатом этого является следующая ошибка.

ServiceCircularReferenceException: Обнаружена циклическая ссылка для службы «doctrine.orm.default_entity_manager», путь: «doctrine.orm.default_entity_manager -> doctrine.dbal.default_connection -> my.listener -> security.context -> security.authentication.manager -> fos_user .user_manager».

Мое предположение состоит в том, что контекст безопасности уже был внедрен где-то в цепочке, но я не знаю, как получить к нему доступ. Есть идеи?

Related of "Внедрение SecurityContext в прослушиватель prePersist или preUpdate в Symfony2, чтобы получить пользователя в созданномBy или updatedBy вызывает ошибку круговой ссылки"

У меня были подобные проблемы, и единственным обходным решением было передать весь контейнер в конструкторе ( arguments: ['@service_container'] ).

 use Doctrine\ORM\Event\LifecycleEventArgs; use Symfony\Component\DependencyInjection\ContainerInterface; class MyListener { protected $container; public function __construct(ContainerInterface $container) { $this->container = $container; } // ... public function prePersist(LifeCycleEventArgs $args) { $securityContext = $this->container->get('security.context'); // ... } } 

Начиная с Symfony 2.6 эта проблема должна быть исправлена. Запрос на растяжение только что был принят в мастер. Ваша проблема описана здесь. https://github.com/symfony/symfony/pull/11690

Начиная с Symfony 2.6, вы можете ввести security.token_storage в свой прослушиватель. Эта служба будет содержать токен, используемый в SecurityContext в <= 2.5. В 3.0 эта служба полностью заменит SecurityContext::getToken() . Вы можете увидеть основной список изменений здесь: http://symfony.com/blog/new-in-symfony-2-6-security-component-improvements#deprecated-the-security-context-service

Пример использования в версии 2.6:

Ваша конфигурация:

 services: my.listener: class: App\SharedBundle\Listener\EntityListener arguments: - "@security.token_storage" tags: - { name: doctrine.event_listener, event: prePersist } 

Ваш слушатель

 namespace App\SharedBundle\Listener; use Doctrine\ORM\Event\LifecycleEventArgs; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; class EntityListener { private $token_storage; public function __construct(TokenStorageInterface $token_storage) { $this->token_storage = $token_storage; } public function prePersist(LifeCycleEventArgs $args) { $entity = $args->getEntity(); $entity->setCreatedBy($this->token_storage->getToken()->getUsername()); } } 

Для хорошего примера created_by вы можете использовать https://github.com/hostnet/entity-blamable-component/blob/master/src/Listener/BlamableListener.php для вдохновения. Он использует компонент hostnet / entity-tracker, который предоставляет специальное событие, которое запускается, когда объект изменяется во время вашего запроса. Также есть комплект для настройки в Symfony2

Я использую файлы конфигурации доктрины для установки preUpdate или prePersist :

 Project\MainBundle\Entity\YourEntity: type: entity table: yourentities repositoryClass: Project\MainBundle\Repository\YourEntitytRepository fields: id: type: integer id: true generator: strategy: AUTO lifecycleCallbacks: prePersist: [methodNameHere] preUpdate: [anotherMethodHere] 

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

В этом потоке есть большой ответ, но все меняется. Теперь в Doctrine есть классы слушателей сущностей: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/events.html#entity-listeners-class

Таким образом, вы можете добавить аннотацию к своей сущности, например:

 /** * @ORM\EntityListeners({"App\Entity\Listener\PhotoListener"}) * @ORM\Entity(repositoryClass="App\Repository\PhotoRepository") */ class Photo { // Entity code here... } 

И создайте класс следующим образом:

 class PhotoListener { private $container; function __construct(ContainerInterface $container) { $this->container = $container; } /** @ORM\PreRemove() */ public function preRemoveHandler(Photo $photo, LifecycleEventArgs $event): void { // Some code here... } } 

Также вы должны определить этого слушателя в services.yml следующим образом:

 photo_listener: class: App\Entity\Listener\PhotoListener public: false autowire: true tags: - {name: doctrine.orm.entity_listener}