Laravel SoftDeletes中restore方法为何同时在Scope与Trait中声明?
为什么Laravel的SoftDeletes中restore方法同时在SoftDeletingScope和SoftDeletes Trait里声明?
这个问题其实涉及Laravel软删除功能的两个不同使用场景和职责划分,我来给你拆解清楚:
1. 针对不同操作场景:实例恢复 vs 批量恢复
这两个restore()方法本质上是为了满足两种完全不同的使用需求:
- SoftDeletes Trait中的
restore():是给单个模型实例设计的。比如你先通过$post = Post::withTrashed()->find(1);拿到一个已软删除的模型对象,调用$post->restore()时,它会处理模型的完整生命周期:触发restoring事件(如果事件返回false会终止操作)、更新模型的deleted_at属性为null、保存模型到数据库,最后触发restored事件。这是面向单个模型的精细化操作。 - SoftDeletingScope中通过宏定义的
restore():是给查询构造器设计的,用于批量恢复数据。比如你执行Post::onlyTrashed()->where('category_id', 1)->restore(),它会直接执行数据库update语句:先通过withTrashed()移除软删除查询约束,然后批量将符合条件的记录的deleted_at设为null。这个操作不会触发单个模型的事件,效率更高,适合批量处理场景。
2. 遵循单一职责的设计原则
Laravel的这个设计是典型的职责分离:
- SoftDeletes Trait的核心职责是给模型类提供实例级别的软删除能力,比如单个模型的删除、恢复、判断是否已删除等实例方法,聚焦于模型自身的行为。
- SoftDeletingScope的核心职责是处理查询层面的软删除约束:它会给查询构造器添加全局约束(默认不返回已软删除的记录),同时扩展查询构造器的方法(比如
withTrashed()、onlyTrashed()),批量恢复的restore()也是查询层面的能力,所以放在Scope里维护,和查询逻辑归为一类。
结合代码片段看差异
你给出的代码也能直观体现这种区别:
- SoftDeletingScope中的
restore()宏:
$builder->macro('restore', function (Builder $builder) { $builder->withTrashed(); return $builder->update([$builder->getModel()->getDeletedAtColumn() => null]); });
完全是查询构造器的逻辑,直接执行批量update,没有模型实例的事件或属性处理。
- SoftDeletes Trait中的
restore():
public function restore() { // 如果restoring事件未返回false,我们将继续此恢复操作。否则... }
核心是围绕单个模型的事件触发和实例状态更新,是面向对象中模型行为的体现。
内容的提问来源于stack exchange,提问作者kitensei
相关产品推荐
相关产品推荐

