You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

API Platform 3.2/Symfony6.4中事件订阅者未触发问题

问题:Symfony事件订阅者未触发,密码创建后仍为明文

我编写了一个事件订阅者,用于在通过POST API请求创建用户时对密码进行哈希处理,但用户创建并持久化后,密码保持提交时的明文状态。添加日志后发现该订阅者根本没有被调用。

订阅者代码

readonly class PasswordHashSubscriber implements EventSubscriberInterface
{
    public function __construct(private UserPasswordHasherInterface $userPasswordHasher)
    {
    }
    
    /**
     * @inheritDoc
     */
    public static function getSubscribedEvents(): array
    {
        return [
             KernelEvents::VIEW => ['hashPassword', EventPriorities::PRE_WRITE
            ],
        ];
    }

    public function hashPassword(ViewEvent $event): void
    {
        $user = $event->getControllerResult();
        $method = $event->getRequest()->getMethod();

        if (!$user instanceof User || Request::METHOD_POST !== $method) {
            return;
        }

        $user->setPassword($this->userPasswordHasher->hashPassword($user, $user->getPassword()));
    }
}

调试信息

容器调试结果

bin/console debug:container PasswordHashSubscriber

Information for Service "App\EventSubscriber\PasswordHashSubscriber"
====================================================================

 ---------------- -------------------------------------------- 
  Option           Value                                       
 ---------------- -------------------------------------------- 
  Service ID       App\EventSubscriber\PasswordHashSubscriber  
  Class            App\EventSubscriber\PasswordHashSubscriber  
  Tags             kernel.event_subscriber                     
  Public           no                                          
  Synthetic        no                                          
  Lazy             no                                          
  Shared           yes                                         
  Abstract         no                                          
  Autowired        yes                                         
  Autoconfigured   yes                                         
  Usages           debug.event_dispatcher                      
 ---------------- -------------------------------------------- 

事件调度器调试结果

bin/console debug:event-dispatcher

 ------- ----------------------------------------------------------------------------- ---------- 
  Order   Callable                                                                      Priority  
 ------- ----------------------------------------------------------------------------- ---------- 
  #1      App\EventSubscriber\PasswordHashSubscriber::hashPassword()                    33         
  #2      Symfony\Bridge\Twig\EventListener\TemplateAttributeListener::onKernelView()   -128       
 ------- ----------------------------------------------------------------------------- ---------- 

我已经尝试设置event_listeners_backward_compatibility_layer: true,但没有效果。


可能的解决方案

1. 确认控制器是否触发KernelEvents::VIEW事件

KernelEvents::VIEW仅在控制器直接返回对象/数组且未手动创建响应时触发。如果你的控制器使用了return $this->json($user);或new JsonResponse($user),该事件不会被触发——因为响应已经生成,Symfony不会再调用VIEW事件的订阅者。

解决方法:将控制器返回值改为实体对象(return $user;),让Symfony自动处理响应生成,从而触发VIEW事件。

2. 换用Doctrine预持久化事件(更可靠)

如果API控制器必须返回响应对象,推荐使用Doctrine的prePersist事件,它会在实体即将被持久化时触发,不受控制器返回方式影响:

readonly class PasswordHashSubscriber implements EventSubscriberInterface
{
    public function __construct(private UserPasswordHasherInterface $userPasswordHasher)
    {
    }

    public static function getSubscribedEvents(): array
    {
        return [
            \Doctrine\ORM\Events::prePersist => ['hashPassword'],
        ];
    }

    public function hashPassword(\Doctrine\ORM\Event\PrePersistEventArgs $args): void
    {
        $entity = $args->getObject();
        if (!$entity instanceof User) {
            return;
        }

        // 避免更新用户时重复哈希已加密的密码
        if ($this->userPasswordHasher->isPasswordValid($entity, $entity->getPassword())) {
            return;
        }

        $entity->setPassword($this->userPasswordHasher->hashPassword($entity, $entity->getPassword()));
    }
}

3. 检查类型判断和命名空间

确保$user instanceof User中的User是正确的实体类(比如App\Entity\User),没有导入错误的命名空间。

4. 排查事件传播是否被终止

检查其他KernelEvents::VIEW订阅者是否调用了$event->stopPropagation(),如果有会导致后续订阅者无法执行。


内容的提问来源于stack exchange,提问作者user3174311

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 05:52:42