模型事件必须在模型内部用static::created等静态方法注册,外部Event门面监听完全无效;其为独立静态观察者机制,不走Laravel通用事件总线,仅单条Eloquent操作触发。

模型事件必须在模型类内部用 static::created 等静态方法注册,外部调用 Event 门面监听(比如 Event::listen('eloquent.created: App\Models\Post'))完全无效——不是“不推荐”,是根本不会触发。
模型事件只能在模型内部注册,不能靠 Event 门面监听
很多人试过在 EventServiceProvider 或控制器里用 Event::listen() 绑定模型事件,结果回调从不执行。这是因为 Eloquent 模型事件是静态观察者机制,和 Laravel 的通用事件系统(Event::dispatch())完全隔离。它不走事件总线,也不进 IOC 容器。
-
static::created()、static::updating()这类调用必须写在模型类的booted()或booting()静态方法里 - 别在 trait 外部、服务提供者、或模型实例方法中尝试注册——
$this->created是错的,self::created也不行,必须是static::created - 如果用了基类模型(如
BaseModel),子类要显式调用parent::boot(),否则父类里的booted()不会运行
creating 和 created 的核心区别:数据库是否已写入
名字只差一个后缀,但行为天差地别。搞混就等于在事务里改了不该改的东西,或者读不到刚生成的 ID。
-
creating:INSERT 语句还没执行,$model->id === null,可安全修改属性(如生成slug、校验必填字段)、return false中断保存 -
created:INSERT 已完成,$model->id有值,适合发通知、关联其他表、清理缓存;此时改$model->name不会写回数据库 -
saving是唯一能同时覆盖 create/update 的钩子,适合统一处理字段逻辑(比如所有保存前都重算updated_at)
软删除的 deleted 事件里读不到 deleted_at?
这是高频踩坑点。软删除触发的是 deleting → deleted,但 deleted 回调中的模型实例,$model->deleted_at 仍是 null —— 因为 Laravel 默认不刷新该字段。
- 正确做法是在
deleting钩子里取值:$model->deleted_at此时还是原始值(或null) - 非要等
deleted里读,得手动刷新:$model->refresh()->deleted_at - 注意:
trashed是另一个事件,需单独监听;forceDeleted才对应物理删除后的最终回调
批量操作(upsert、insert)根本不触发模型事件
写完 static::created() 却没反应?先查是不是用了 DB::table()、Model::upsert() 或 Model::insert()。这些绕过 Eloquent 实例化流程的操作,连 booting() 都不会跑。
- 只有单条模型调用
save()、create()、update()、delete()才会触发对应事件 - 如果业务强依赖事件且必须批量写入,要么循环
new Model()->fill()->save(),要么把逻辑抽到队列任务里手动 dispatch 自定义事件 - 别在
creating里做远程请求或耗时操作——它卡在事务里,失败会导致整个保存失败
最常被忽略的一点:模型事件里不能 resolve 服务,比如 app()->make(MyService::class) 或依赖注入。它没有容器上下文,硬写只会报错或返回空实例。跨模型、带 IO 的逻辑,一律抽成独立事件 + 监听器类,不然调试时连调用栈都找不到源头。


















