什么是作用域
Eloquent 的作用域是将查询约束打包并可复用的机制。作用域分两类。本地作用域
定义
本地作用域通过给模型方法加上#[Scope] 属性来定义。
#[Scope] 属性位于 Illuminate\Database\Eloquent\Attributes 命名空间,是 PHP 8.0 之后的原生语法。使用
已定义的作用域可以像方法一样调用,也可以链式使用。传递参数
可以在作用域方法的第 2 个参数之后定义额外参数。与 orWhere 的组合
用 orWhere 连接作用域时,有时需要逻辑分组。
全局作用域
机制
全局作用域是实现了Illuminate\Database\Eloquent\Scope 接口的类。该接口仅要求实现 apply 一个方法。
apply 方法中给查询构造器附加约束。
创建全局作用域类
使用make:scope 命令生成模板。
app/Models/Scopes/ActiveScope.php。
应用到模型
1
使用 #[ScopedBy] 属性注册(推荐)
Laravel 13 中使用 可以将多个作用域以数组形式指定。
#[ScopedBy] 属性最简洁。2
在 booted() 方法中手动注册
也可以覆写
booted 方法并调用 addGlobalScope。User::all() 等所有查询都会自动附加 WHERE is_active = 1。
匿名闭包形式的全局作用域
对于不需要单独放在文件里的简单作用域,可以用闭包定义。移除全局作用域
在特定查询中你可能希望禁用作用域。框架内部:SoftDeletingScope
看看 Laravel 标准的SoftDeletes trait 如何使用全局作用域,就能了解实现模式。
SoftDeletingScope 实现了 Scope 接口。
看看 withTrashed() 的实现
看看 withTrashed() 的实现
withTrashed() 实际上是调用 withoutGlobalScope($this)。也就是说,通过移除 SoftDeletingScope 自身,让被删除的记录也能被取到。onlyTrashed() 同样先移除自身作用域,再附加 whereNotNull('deleted_at')。实战用例
多租户:按租户 ID 自动过滤
SaaS 应用中,对所有查询自动加上租户 ID 过滤非常重要。Post::all(),就能得到当前登录用户所在租户的数据。
公开/非公开筛选
管理后台希望显示未发布的文章,前台仅显示已发布文章的场景。withoutGlobalScope 移除作用域。
请使用 addSelect 而非 select
下一步
Eloquent 自定义类型转换
将属性转换逻辑实现为自定义 Cast,并结合 Value Object 模式使用。