将SecurityContext注入到Symfony2中的侦听器prePersist或preUpdate中以获取createdBy或updatedBy中的用户导致循环引用错误

我设置了一个监听器类,我将在任何原理prePersist上设置ownerid列。 我的services.yml文件看起来像这样…

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

而我的class级看起来像这样

 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”检测到循环引用,path:“doctrine.orm.default_entity_manager – > doctrine.dbal.default_connection – > my.listener – > security.context – > security.authentication.manager – > fos_user .user_manager”。

我的假设是,安全上下文已经注入链中的某个地方,但我不知道如何访问它。 有任何想法吗?

我有类似的问题,唯一的解决方法是在构造函数中传递整个容器( 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注入到监听器中。 该服务将包含<= 2.5中由SecurityContext使用的令牌。 在3.0中,这个服务将完全replaceSecurityContext::getToken() 。 你可以在这里看到一个基本的更改列表: http : //symfony.com/blog/new-in-symfony-2-6-security-component-improvements#deprecated-the-security-context-service

2.6中的示例用法:

您的configuration:

 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中还有一个configuration

我使用doctrineconfiguration文件来设置preUpdateprePersist方法:

 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来保持这个方法,并扩展其他实体。 希望它有帮助!