Laravel 9查询作用域内模型updating/updated事件不触发问题求助
Laravel模型事件在查询作用域中不触发的问题解决
问题原因
你的scopeUpdateStore写法完全不符合Laravel查询作用域的设计逻辑:查询作用域是用来修改查询条件、过滤结果的,并非用于执行更新操作。另外,你在作用域里直接调用Store::find($id)创建了全新的查询实例,和传入的$query没有关联——虽然理论上这个update应该触发事件,但可能因为后续链式调用->first()的干扰,导致你误以为事件没触发,或者存在上下文冲突。
更关键的是你混淆了两种update的核心区别:
- 模型实例的
update()方法(如find($id)->update()):会触发updating/updated事件,因为Laravel会实例化模型并执行完整的生命周期钩子。 - 查询构建器的
update()方法(如where('id', $id)->update()):属于批量更新,直接执行SQL语句,不会加载模型实例,因此不会触发模型事件。
解决方案
方案1:用静态方法封装更新逻辑(推荐)
既然是更新操作,就别用查询作用域,直接封装成模型静态方法,和你控制器里的正常调用逻辑完全一致:
// App\Model\Store class Store extends Model { // ... public static function updateStore($id) { $store = static::find($id); return $store ? $store->update(['name' => 'foo']) : false; } }
调用方式:
Store::updateStore($id);
这种写法会正常触发模型事件,完全符合Laravel的设计规范。
方案2:坚持用查询作用域(不推荐)
如果一定要用查询作用域,必须利用传入的$query获取模型实例,再调用实例的update方法(不能直接用查询构建器的update):
// App\Model\Store class Store extends Model { // ... public function scopeUpdateStore($query, $id) { $store = $query->find($id); if ($store) { $store->update(['name' => 'foo']); } return $query; // 保持链式调用能力 } }
调用方式不变:
Store::updateStore($id)->first();
这里用传入的$query获取模型实例,既遵循了查询作用域的参数约定,又通过实例的update触发了模型事件。
内容的提问来源于stack exchange,提问作者KingNNT
相关产品推荐
相关产品推荐

