You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 08:40:23