Global Scopes
有时您可能希望定义一个 scope 可以用于模型的所有查询中。本质上,这也是 Eloquent 的"软删除"功能的实现原理。Global scopes 是通过 PHP traits 的组合以及实现 Illuminate\Database\Eloquent\ScopeInterface
接口来定义的。
首先,我们需要定义一个 trait。 这里我们用 Laravel 的 SoftDeletes 举例:
trait SoftDeletes {
/**
* Boot the soft deleting trait for a model.
*
* @return void
*/
public static function bootSoftDeletes()
{
static::addGlobalScope(new SoftDeletingScope);
}
}
如果一个 Eloquent 模型引入了一个 trait ,而这个 trait 中带有符合 bootNameOfTrait 惯例命名的方法 ,那么这个方法会在 Eloquent 模型启动的时候调用, 您可以在此时注册 global scope ,或者做一些其他您想要的操作。定义的 scope 必须实现 ScopeInterface 接口,这个接口提供了两个方法:apply 和 remove。
apply 方法接受一个 Illuminate\Database\Eloquent\Builder 查询构造器对象以及它所应用的 Model,用来添加这个 scope 所需的额外的 where 子句。而remove 方法同样接受一个 Builder 对象以及 Model ,用来反向的执行 apply 操作。也就是说,remove 方法应该移除已经添加的 where 子句 (或者其他查询子句)。因此,我们的 SoftDeletingScope 的方法应该如下:
/**
* Apply the scope to a given Eloquent query builder.
*
* @param \Illuminate\Database\Eloquent\Builder $builder
* @param \Illuminate\Database\Eloquent\Model $model
* @return void
*/
public function apply(Builder $builder, Model $model)
{
$builder->whereNull($model->getQualifiedDeletedAtColumn());
$this->extend($builder);
}
/**
* Remove the scope from the given Eloquent query builder.
*
* @param \Illuminate\Database\Eloquent\Builder $builder
* @param \Illuminate\Database\Eloquent\Model $model
* @return void
*/
public function remove(Builder $builder, Model $model)
{
$column = $model->getQualifiedDeletedAtColumn();
$query = $builder->getQuery();
foreach ((array) $query->wheres as $key => $where)
{
// If the where clause is a soft delete date constraint, we will remove it from
// the query and reset the keys on the wheres. This allows this developer to
// include deleted model in a relationship result set that is lazy loaded.
if ($this->isSoftDeleteConstraint($where, $column))
{
unset($query->wheres[$key]);
$query->wheres = array_values($query->wheres);
}
}
}