- 本地作用域
- 很多情况下,我们在数据查找是有一部分条件会被重复且大量使用
- 而这个条件,可能只是在这个模型对应的数据包使用,别的表并不使用
- 那么这种情况,可以使用本地作用域的方式,将常用的SQL封装起来;
- 比如:用户模块中,我们大量查询性别为男,且其他条件的SQL
$users = User::where(‘gender’, ‘女’)
->where(‘price’,’>’,’90’)
->get();
PS: 我们可以将性别为男这个片段,封装成一个单独的方法,然后统一在这个模型下调用:
//App\Http\Models;
//本地作用域,搜索自动添加为”男”的条件
//语法:scope开头,后面名称尽可能包含语义
public function scopeGenderMale($query){
$query->where(‘gender’, ‘女’);
}
//当然,如果赶紧单词太长,直接gm()也行
$users = User::genderMale()
->where(‘price’, ‘>’, 90)
->get();
e. 上面的方法比较死板,适合简单粗暴,如果想要灵活多变,支持传递参数
//参数可以是1个或多个
$users = User::gender(‘女’, 0)
->where(‘price’,’>’,90)
->get();
//参数2和3,接受控制器传递过来的1,2
public function scopeGender($query, $value, $value2 = 1){
$query->where(‘gender’, $value)->where(‘status’, $value2);
}
- 全局作用域
- 全局作用域,顾名思义就是在任意地方都可以有效的封装条件:
- 比如有个需求,不管在哪里操作,总是显示status为1的用户
- 首先在app目录下创建一个用于全局作用域的目录:Scopes:
- 创建一个用于设置status为1的全局作用域的类,它需要实现scope接口
namespace App\Scopes;
//这里引用代码自动生成
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;
class StatusScope implements Scope{
public function apply(Builder $builder, Model $model){
$builder->where(‘status’, 1);
}
}
e. 此时,还不能实现全局,因为需要在模型设置开关,让其富有灵活性:
//启用全局作用域,如果发现路径报错,那就在模型代码开头添加:use App\Scopes\StatusScope;
protected static function booted(){
parent::booted();
static::addGlobalScope(new StatusScope());
}
Ps: 而在控制器端,并不需要做任何设置,即可自动添加status=1的条件
f. 当然,如果这个全局只是针对某个模块,并不需要创建一个全局类,直接闭包即可:
//这里如果不在模型中添加:use Illuminate\Database\Eloquent\Builder;这段也有可能会报错,报错点在下面的第一行
static::addGlobalScope(‘status’, function(Builder $builder){
$builder->where(‘status’,0);
});
Ps: 注意Builder引入的文件和全局类引入的文件一致,如果引入别的同名类会报错;
g. 如果某个查询,并不需要这个全局条件,可以单独移出掉:
//取消名称为status的全局
$users = User::withoutGlobalScope(‘status’)->get();
//取消全局类的条件,这个老壁灯如果使用不了的话那就是没用引入类use App\Scopes\StatusScope;
$users = User::withoutGlobalScope(StatusScope::class)->get();
PS:还有withoutGlobalScopes([])方法,传递参数取消多个全局