Laravel Eloquent 作用域与模型事件:软删除与审计字段的工程化
test12026-09-140 次阅读
作用域:把查询条件收敛到模型
查询条件如果散落在控制器各处,既重复又难维护。Eloquent 的局部作用域让你把“已支付”“有效”这类语义封装成可读的方法,全局作用域则能默认给所有查询加上过滤(例如排除已取消订单),从根源减少误查。
局部与全局作用域
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
class Order extends Model
{
protected $fillable = ["user_id", "amount", "status"];
// 局部作用域:只查已支付
public function scopePaid(Builder $query): Builder
{
return $query->where("status", "paid");
}
// 全局作用域:默认排除已取消订单
protected static function boot()
{
parent::boot();
static::addGlobalScope("notCancelled", function (Builder $query) {
$query->where("status", "<>", "cancelled");
});
}
}
软删除与全局作用域
SoftDeletes 本身就是一个全局作用域:它让所有查询默认忽略被删除的记录,需要时再用 withTrashed 显式拉回。和业务全局作用域叠加时互不冲突。
use Illuminate\Database\Eloquent\SoftDeletes;
class Order extends Model
{
use SoftDeletes;
protected $dates = ["deleted_at"];
}
// 恢复一条被软删除的订单
Order::withTrashed()->where("id", $id)->first()->restore();
模型事件与观察者:自动填充审计字段
created_by / updated_by 这类审计字段没必要在每个控制器里手填。放到模型的 creating / updating 事件里,配合全局登录态自动写入,既一致又防漏。
use Illuminate\Support\Facades\Auth;
class Order extends Model
{
protected static function boot()
{
parent::boot();
static::creating(function ($order) {
$order->created_by = Auth::id();
});
static::updating(function ($order) {
$order->updated_by = Auth::id();
});
}
}
在业务里组合使用
// 只返回“未取消 且 已支付 且 金额大于 100”的订单
$orders = Order::paid()
->where("amount", ">", 100)
->get();
经验清单
- 高频查询条件优先做成局部作用域,提升可读性也避免写错。
- 全局作用域要克制,只放“几乎总是成立”的约束,否则会悄悄改变查询结果。
- 审计字段、时间戳等横切逻辑放在模型事件里,比在控制器重复写更稳。
- 使用全局作用域后,记得在需要“看到被过滤数据”的地方用 withoutGlobalScope / withTrashed。
T
test1
文章作者
作用域:把查询条件收敛到模型 查询条件如果散落在控制器各处,既重复又难维护。Eloquent 的局部作用域让你把“已支...
- 分类
- 技术
- 发布时间
- 2026-09-14
- 字数
- 约 1871 字
- 阅读
- 0 次
