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
相关产品推荐
相关产品推荐

