creating在insert前触发,可修改数据并中止保存;created在提交后触发,仅适合通知日志;批量插入需用createmany或手动dispatch事件。

模型创建时想自动设置字段,用 creating 而不是 created
前者在 INSERT 前触发,能修改待插入数据;后者在插入完成、事务已提交后才执行,改了也白改。常见错误是写成 created 却试图给 $model->uuid = Str::uuid(),结果数据库里还是 null。
-
creating:可修改属性、中止保存(返回false) -
created:适合发通知、记录日志,不能影响当前插入 - 事件监听必须在
booted()中注册,或在EventServiceProvider里全局绑定 - 如果模型用了
SoftDeletes,creating仍会触发,但deleting不等于forceDeleting
批量插入时 creating 事件不触发?那是你没用对方法
Eloquent 的 insert() 和 upsert() 是直接 SQL 执行,绕过模型实例化,自然不会触发任何模型事件。真正走生命周期的只有 save()、create()、firstOrCreate() 这类基于模型对象的操作。
- 要批量触发事件,得用
collect([...])->each(fn($data) => Model::create($data)),但性能差 - 更现实的做法是:用
insert()写入,再单独查出新记录 ID,手动 dispatch 相关事件 - 注意
createMany()是 Eloquent 10+ 新增方法,它会为每个数组项实例化模型并触发creating/created
saving 和 updating 同时监听,怎么区分是新增还是修改?
靠 $model->exists 最可靠。别用 !$model->id 或 is_null($model->id) —— 如果主键是字符串或自定义值(比如 UUID),这种判断会失效。
-
saving在save()前触发,不管新增还是更新都走这里 -
updating只在模型已存在($model->exists === true)且有变更字段时触发 - 想统一处理「保存前校验」,只监听
saving并用$model->exists分支即可 - 注意:
$model->isDirty('email')在saving里可用,但在updating里可能已重置为 false(取决于是否刚 reload)
事件里调用 $model->save() 导致无限循环?得加守卫
比如在 saving 里根据某个字段自动补全另一个字段,又不小心触发了第二次 save(),就会死循环报错 Maximum function nesting level reached。
- 最简单的守卫是加静态标记:
if (self::$savingGuard) return;+ 开头设为 true - 更好的方式是用
$model->isDirty()判断是否真有变化再决定是否 save - 避免在事件里做跨模型 save 操作;如果必须,用
DB::transaction()包裹,并确保子模型事件不反向触发父模型事件 - 测试时容易漏掉:命令行
php artisan tinker中手动 new 模型再 save,和 API 请求走的中间件/请求验证路径不同,行为可能不一致
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











