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