应用场景
SQL
语句需要加某些共同的条件,例如status > 0
,如果我们每条SQL
语句都加的话显然是很麻烦的,作为一个优雅的框架,当然有相应的解决办法编写作用域
Laravel 应用默认并没有为作用域预定义文件夹,所以你可以按照自己的喜好在 app 目录下创建 Scopes
目录并实现接口(Illuminate\Database\Eloquent\Scope
)的方法apply
。
<?php
namespace App\Scopes;
use Illuminate\Database\Eloquent\Scope;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
class StatusScope implements Scope
{
/**
* Apply the scope to a given Eloquent query builder.
*
* @param \Illuminate\Database\Eloquent\Builder $builder
* @param \Illuminate\Database\Eloquent\Model $model
* @return
*/
public function apply(Builder $builder, Model $model)
{
return $builder->where('status', '>', 0);
}
}
使用作用域
只需要在你需要使用的模型的"boot
启动"方法中使用static::addGlobalScope(new 你的作用域类);
<?php
namespace App\Models;
use App\Scopes\StatusScope;
use Illuminate\Database\Eloquent\Model;
class ScopeTest extends Model
{
protected static function boot()
{
parent::boot();
static::addGlobalScope(new StatusScope());
}
}
添加作用域后,如果使用 ScopeTest::all()
查询则会生成如下 SQL 语句:status>0
就是应用的效果
select * from `users` where `status` > 0
当然,假如你感觉到上面的方法比较麻,也可以使用匿名的全局作用域
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
class ScopeTest extends Model
{
protected static function boot()
{
parent::boot();
static::addGlobalScope('status', function (Builder $builder){
$builder->where('status','>', 1);
});
}
}
有些查询并不想使用作用域,可以通过调用以下方法移除作用域
ScopeTest::withoutGlobalScope(StatusScope::class)->get(); //移除指定作用域
ScopeTest::withoutGlobalScope('status')->get(); //移除闭包定义的作用域
ScopeTest::withoutGlobalScopes()->get(); //移除所有作用域
ScopeTest::withoutGlobalScopes([oneScope::class, twoScope::class])->get(); //移除某些作用域
Eloquent模型方法前加上一个 scope前缀来使用作用域
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class ScopeTest extends Model
{
public function scopeStatus($query){
return $query->where('status','>', 1);
}
public function scopeType($query){
return $query->where('type','>', 0);
}
}
调用时不需要加scope
前缀,类似于修改器/访问器,并且可以一次性调用多个方法。
$users = ScopeTest::status()->type()->get();
ScopeTest::status()->orWhere(function (Builder $query) {
$query->type();
})->get();