应使用命令总线或自定义业务事件+监听器替代模型事件,定义可序列化批量事件类(如batchupdateuserstatusevent),服务中事务提交后异步分发,监听器脱敏记录操作类型、影响数、摘要、操作人等信息,并统一覆盖command场景。

在 Hyperf 框架中,记录批量修改操作日志的关键是:**不依赖模型事件(如 `saving`/`saved`),而改用命令总线(Command Bus)或自定义业务事件 + 事件监听器,结合上下文明确捕获“批量”动作的原始输入与影响范围**。
1. 定义批量操作业务事件
避免使用 Eloquent 风格的模型事件(Hyperf 的 DbEvent 不支持批量触发感知),而是主动在业务层抛出语义清晰的事件:
- 创建事件类,如 BatchUpdateUserStatusEvent,携带关键信息:
userIdList、updateFields、operatorId、reason - 事件应为可序列化对象(Hyperf 事件分发基于协程 Channel,需支持 JSON 序列化)
- 示例:app/Event/BatchUpdateUserStatusEvent.php
2. 在服务方法中触发事件
在执行批量更新的 Service 方法中,先完成 DB 操作,再同步或异步分发事件:
- 使用
$this->event->dispatch(new BatchUpdateUserStatusEvent(...)) - 推荐异步分发(
dispatchAfterResponse或配合Hyperf\AsyncQueue),避免日志写入拖慢主流程 - 确保事务已提交后再发事件(否则监听器查不到最新数据);若需强一致性,可在事务 commit 后手动 dispatch
3. 编写日志监听器并持久化
监听器负责解析事件、组装日志内容、写入数据库或日志服务:
- 监听器类实现
ListenerInterface,注入LoggerInterface或自定义日志仓储 - 日志内容建议包含:操作类型、影响记录数、ID 列表摘要(如前5个+总数)、变更字段、操作人、IP(从 Context 获取)、时间
- 敏感字段(如密码、手机号)需脱敏处理,避免全量记录原始数据
- 示例写入:
UserOperationLog::create([...]),表结构含action、affect_count、summary、operator_id等字段
4. 补充:兼容非 Service 场景(如命令行任务)
若批量操作来自 Command 类(如定时同步用户状态),同样应在逻辑末尾 dispatch 对应事件,保持日志采集路径统一:
- 命令类中调用
$this->event->dispatch(...) - 避免在 Command 中直接写日志——破坏关注点分离,也不利于后续审计扩展
- 可通过注解
@CommandAnnotation标记命令用途,辅助日志分类











