Hyperf 3.1中软删除不触发deleting/deleted事件,需改用SoftDeleting/SofDeleted事件或重写delete()方法显式触发;直接DB操作不走模型生命周期,事件永不触发。

在Hyperf 3.1中实现软删除后,模型的deleting、deleted事件不再触发,导致依赖事件的业务逻辑(如清理关联缓存、同步第三方状态)全部失效,必须立即修复。
确认软删除是否启用并影响事件
打开模型类(如 App\Model\User),检查是否实现了 SoftDeletes trait 且未手动禁用事件:若存在 protected $dispatchesEvents = []; 或显式清空了 deleting/deleted 键,则事件必然被屏蔽。
运行 php bin/hyperf.php db:model User 生成新模型对比,确认 use Hyperf\Database\Model\SoftDeletes; 已引入且未覆盖默认事件映射。
【关键前提】 软删除必须通过 $model->delete() 触发,直接执行 DB::table('users')->where('id', 1)->delete() 不经过模型生命周期,事件永不触发。
修复软删除下的事件触发机制
Hyperf 3.1 的 SoftDeletes trait 默认重写了 delete() 方法,但未调用父类 delete() 中的事件分发逻辑——这是根本原因。
方法一:重写模型的 delete() 方法,显式触发事件
在模型中添加:
public function delete($force = false){ if ($force) { return parent::delete($force); } $this->fireModelEvent('deleting', false); if ($this->fireModelEvent('deleting', false) === false) { return false; } $result = $this->performSoftDelete(); $this->fireModelEvent('deleted', false); return $result;}
注意:此写法需严格复刻父类 delete() 的事件返回值判断逻辑,否则中断链式调用。
方法二:改用 forceDelete() + 手动事件分发(仅限确定不走软删路径的场景)
若某处业务明确需要物理删除并保证事件触发,直接调用 $model->forceDelete() 即可——它继承自基类,原生支持事件。
方法三:监听 SoftDeleting 和 SoftDeleted 专属事件(推荐)
Hyperf 3.1 的 SoftDeletes trait 实际已内置两组专用事件:SoftDeleting 和 SoftDeleted。只需在监听器中注册它们:
执行命令生成监听器:php bin/hyperf.php gen:listener UserSoftDeletedListener
编辑 app/Listener/UserSoftDeletedListener.php,在 listen() 中返回:
return [ SoftDeleting::class, SoftDeleted::class,];
【不可逆操作】 删除原有监听 deleting/deleted 的代码,改用新事件名,否则事件永远不会被调度。
验证事件是否真实触发
第一步:在监听器 process() 方法开头插入 file_put_contents('/tmp/hyperf-event.log', date('Y-m-d H:i:s') . " SoftDeleted triggered\n", FILE_APPEND);
第二步:使用 tinker 执行 php bin/hyperf.php tinker,输入:
$u = App\Model\User::find(1); $u->delete();
第三步:立刻检查 /tmp/hyperf-event.log 是否新增时间戳行;若无,说明监听器未注册或事件名拼写错误。
第四步:确认 config/autoload/listeners.php 中该监听器已启用(默认生成时已自动注册,但需人工核对)。











