如何在监听器/订阅器中捕获SonataAdmin批量操作事件?
如何在SonataAdmin中捕获批量操作事件并处理文件删除
你说得没错,sonata.admin.event.persistence.pre_batch这个事件默认并没有被SonataAdminBundle实现,所以直接监听它不会有效果。下面给你两种解决方案,分别对应快速在Admin类中落地需求和自定义事件实现订阅器监听两种场景:
方案一:直接在Admin类中处理批量操作
这是最直接的方案,毕竟SonataAdmin的批量操作逻辑本身就承载在Admin类中:
- 在你的实体Admin类里,重写
batchActionDelete方法(如果是自定义批量操作,就重写对应的方法):
use Sonata\AdminBundle\Datagrid\ProxyQueryInterface; use Sonata\AdminBundle\Admin\AbstractAdmin; class YourEntityAdmin extends AbstractAdmin { private $imageRemover; // 通过构造函数注入你的图片删除服务 public function __construct($code, $class, $baseControllerName, $imageRemover) { parent::__construct($code, $class, $baseControllerName); $this->imageRemover = $imageRemover; } public function batchActionDelete(ProxyQueryInterface $query) { // 先拉取要删除的所有实体 $entities = $query->execute(); // 遍历实体,删除关联的图片文件 foreach ($entities as $entity) { if ($image = $entity->getImage()) { // 假设实体有getImage()方法获取图片信息 $this->imageRemover->remove($image); } } // 调用父类的批量删除逻辑,完成数据库层面的删除 return parent::batchActionDelete($query); } }
- 别忘了在
services.yaml里给Admin类注入image.remover服务:
services: App\Admin\YourEntityAdmin: arguments: $imageRemover: '@image.remover' tags: - { name: sonata.admin, model_class: App\Entity\YourEntity, manager_type: orm, label: 'Your Entity' }
方案二:自定义批量操作事件并通过订阅器监听
如果更倾向于事件驱动的设计,想用订阅器统一处理逻辑,可以自己触发自定义事件:
步骤1:创建自定义事件类
namespace App\Event; use Sonata\AdminBundle\Datagrid\ProxyQueryInterface; use Symfony\Contracts\EventDispatcher\Event; class PreBatchDeleteEvent extends Event { // 定义事件名称常量 public const NAME = 'sonata.admin.event.persistence.pre_batch_delete'; private $query; public function __construct(ProxyQueryInterface $query) { $this->query = $query; } public function getQuery(): ProxyQueryInterface { return $this->query; } }
步骤2:在Admin类的批量操作中触发事件
修改Admin类的batchActionDelete方法,在实体删除前抛出我们的自定义事件:
use App\Event\PreBatchDeleteEvent; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Sonata\AdminBundle\Admin\AbstractAdmin; class YourEntityAdmin extends AbstractAdmin { private $eventDispatcher; public function __construct($code, $class, $baseControllerName, EventDispatcherInterface $eventDispatcher) { parent::__construct($code, $class, $baseControllerName); $this->eventDispatcher = $eventDispatcher; } public function batchActionDelete(ProxyQueryInterface $query) { // 触发预批量删除事件 $event = new PreBatchDeleteEvent($query); $this->eventDispatcher->dispatch($event, PreBatchDeleteEvent::NAME); // 执行父类的删除逻辑 return parent::batchActionDelete($query); } }
步骤3:在订阅器中监听自定义事件
更新你的ImageUploaderSubscriber,添加对自定义事件的处理:
namespace AdminBundle\EventListener; use App\Event\PreBatchDeleteEvent; use Symfony\Component\EventDispatcher\EventSubscriberInterface; class ImageUploaderSubscriber implements EventSubscriberInterface { private $imageRemover; private $imageUploader; public function __construct($imageRemover, $imageUploader) { $this->imageRemover = $imageRemover; $this->imageUploader = $imageUploader; } // 声明要订阅的事件 public static function getSubscribedEvents() { return [ PreBatchDeleteEvent::NAME => 'preBatchDelete', // 保留你原本的其他事件监听 'sonata.admin.event.persistence.pre_persist' => 'prePersist', 'sonata.admin.event.persistence.pre_update' => 'preUpdate', 'sonata.admin.event.persistence.pre_remove' => 'preRemove', ]; } // 批量删除前的文件清理逻辑 public function preBatchDelete(PreBatchDeleteEvent $event) { $entities = $event->getQuery()->execute(); foreach ($entities as $entity) { if ($image = $entity->getImage()) { $this->imageRemover->remove($image); } } } // 保留你原本的prePersist、preUpdate、preRemove方法 public function prePersist($event) { /* 你的原有逻辑 */ } public function preUpdate($event) { /* 你的原有逻辑 */ } public function preRemove($event) { /* 你的原有逻辑 */ } }
步骤4:更新服务配置
确认订阅器服务的标签配置(可以用event_subscriber标签,也可以继续用event_listener):
image.uploader.subscriber: class: AdminBundle\EventListener\ImageUploaderSubscriber arguments: - '@image.remover' - '@image.uploader' tags: - {name: kernel.event_subscriber} # 用这个标签的话,不需要单独声明每个事件 # 或者继续用event_listener标签: # - {name: kernel.event_listener, event: 'sonata.admin.event.persistence.pre_batch_delete', method: 'preBatchDelete'} - {name: kernel.event_listener, event: sonata.admin.event.persistence.pre_persist, method: prePersist} - {name: kernel.event_listener, event: sonata.admin.event.persistence.pre_update, method: preUpdate} - {name: kernel.event_listener, event: sonata.admin.event.persistence.pre_remove, method: preRemove}
补充说明
- 如果还有其他批量操作(比如批量更新),可以参照这个模式创建对应的自定义事件(如
PreBatchUpdateEvent),在对应的批量方法中触发即可。 - 方案一适合快速落地需求,代码更简洁;方案二更符合解耦设计,适合需要在多个Admin类中复用批量操作逻辑的场景。
内容的提问来源于stack exchange,提问作者revengeance
相关产品推荐
相关产品推荐

