如何在Doctrine的postLoad事件中获取当前用户?
问题描述
尝试创建监听postLoad事件的监听器,需要在其中获取当前用户,但使用TokenStorageInterface或Security组件时返回值均为null。
配置文件(services.yaml)
entity_encryption_listener: class: 'App\EventListener\EntityEncryptionListener' arguments: - 'secret_key' tags: - { name: doctrine.event_subscriber }
监听器代码(EntityEncryptionListener)
class EntityEncryptionListener implements EventSubscriber { private $security; private $secret; public function __construct($secret, Security $security) { $this->secret = $secret; $this->security = $security; } public function getSubscribedEvents() { return [Events::prePersist, Events::preUpdate, Events::postLoad]; } public function prePersist(LifecycleEventArgs $args) { $this->getSecret(); $this->encryptEntity($args); } public function preUpdate(LifecycleEventArgs $args) { $this->getSecret(); $this->encryptEntity($args); } public function postLoad(LifecycleEventArgs $args) { $user = $this->security->getUser(); //dd($user); $this->getSecret(); $this->decryptEntity($args); } }
解决思路
修正服务作用域与注入方式
默认Doctrine事件订阅者是单例服务,初始化时无请求上下文,无法获取用户。需改用请求作用域的代理类并启用延迟加载:
修改services.yaml:entity_encryption_listener: class: 'App\EventListener\EntityEncryptionListener' arguments: - 'secret_key' - '@security.helper' tags: - { name: doctrine.event_subscriber } lazy: true监听器中替换注入类:
use Symfony\Component\Security\Core\SecurityHelper; class EntityEncryptionListener implements EventSubscriber { private $securityHelper; private $secret; public function __construct($secret, SecurityHelper $securityHelper) { $this->secret = $secret; $this->securityHelper = $securityHelper; } public function postLoad(LifecycleEventArgs $args) { $user = $this->securityHelper->getUser(); $this->getSecret(); $this->decryptEntity($args); } // 其他方法保持不变 }处理非请求场景
postLoad可能在命令行、消息队列等无用户上下文的场景触发,需做判断跳过逻辑:public function postLoad(LifecycleEventArgs $args) { $user = $this->securityHelper->getUser(); if (!$user) { return; } $this->getSecret(); $this->decryptEntity($args); }延迟获取TokenStorage(备选方案)
若坚持使用TokenStorageInterface,可通过容器延迟获取,避免初始化时注入:use Psr\Container\ContainerInterface; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; class EntityEncryptionListener implements EventSubscriber { private $container; private $secret; public function __construct($secret, ContainerInterface $container) { $this->secret = $secret; $this->container = $container; } public function postLoad(LifecycleEventArgs $args) { if (!$this->container->has(TokenStorageInterface::class)) { return; } $tokenStorage = $this->container->get(TokenStorageInterface::class); $user = $tokenStorage->getToken()?->getUser(); // 后续逻辑 } }
内容的提问来源于stack exchange,提问作者dragonkhanrider
相关产品推荐
相关产品推荐

