Symfony EasyAdminBundle pre_update事件触发两次致重复发邮件排查
easy_admin.pre_update事件重复触发导致重复邮件的问题 我之前在维护基于EasyAdmin 1.x的项目时,也碰到过一模一样的问题——pre_update事件莫名触发两次,导致重复发送通知邮件。结合你的代码和配置,大概率是这几个原因导致的,咱们一步步来排查解决:
1. 事件订阅者的标签使用错误
在EasyAdmin 1.x版本中,官方推荐使用专属的事件订阅标签,而不是通用的kernel.event_subscriber。后者可能会让事件被Symfony的事件分发器和EasyAdmin自身的事件系统同时处理,导致触发两次。
修改你的services.yml配置,把标签换成EasyAdmin的专属格式:
app.easy_admin.aprobar_publicacion: class: AppBundle\EventListener\AprobarPublicacionSubscriber arguments: ['@mailer','@service_container','@twig'] tags: - { name: easy_admin.event_subscriber } # 替换原来的kernel.event_subscriber
2. 手动调用computeChangeSets()引发的重复计算
你在代码里手动调用了$uow->computeChangeSets();,但EasyAdmin在触发pre_update事件前,已经自动调用过一次这个方法了。重复调用会让UnitOfWork重新计算实体的变更集,可能导致你的逻辑被误判为“状态再次变更”,进而触发两次邮件发送。
直接去掉这行代码,改用自动跟踪的变更集:
// 移除这行手动计算的代码 // $uow->computeChangeSets(); $changeset = $uow->getEntityChangeSet($entity);
3. 加个“防重复标记”作为兜底方案
如果上面的方法都没解决,可能是EasyAdmin 1.17.9版本的已知bug(这个版本确实有用户反馈过事件重复触发的问题)。可以给实体加一个临时的“已发送”标记,确保邮件只发一次:
第一步:在VestidoDeNovia实体中添加临时属性
// AppBundle/Entity/VestidoDeNovia.php private $emailSent = false; public function isEmailSent(): bool { return $this->emailSent; } public function setEmailSent(bool $emailSent): void { $this->emailSent = $emailSent; }
注意:这个属性不需要添加任何Doctrine映射注解,只是内存中的临时标记。
第二步:修改事件订阅者的逻辑
if (array_key_exists('estado', $changeset)) { $estadoActual = $changeset['estado'][0]->getId(); // 新增判断:邮件未发送过才执行 if ($estadoActual != 2 && $entity->getEstado()->getId() == 2 && !$entity->isEmailSent()) { // ... 你的邮件发送逻辑 ... // 标记为已发送,避免重复执行 $entity->setEmailSent(true); } }
4. 排查是否有重复注册的订阅者
最后检查一下你的配置文件,确保没有在其他地方(比如config.yml的easy_admin配置里、其他services文件里)重复注册了同一个AprobarPublicacionSubscriber类。重复注册会导致同一个事件被多个订阅者实例处理,自然会触发两次。
按照这个顺序排查下来,应该能解决你的重复邮件问题。
内容的提问来源于stack exchange,提问作者je134

