0
点赞
收藏
分享

微信扫一扫

【Laravel笔记】7. 模型的作用域



本文主要内容:


​​7.1 本地作用域​​​​7.2 全局作用域​​



很多情况下,我们在数据查找时,有一部分条件会被重复且大量使用,通过作用域,将常用的SQL封装,会简化操作。


7.1 本地作用域

1、在某个条件下,只是这个模型对应的数据表使用,别的表并不使用,那么可以使用 ​​本地作用域​​ 将常用的SQL封装起来。

2、比如,在用户模块中,需要大量查询 ​​状态为1​​ 的数据,然后在且其他条件:

$users = User::where('status', 1)
->where('price', '>', 90)
->get();

这时,我们就可以将 ​​状态为1​​ 的这个片段,封装成一个单独的方法:

class User extends Model
{
/**
* App\Models\Models\User
*
* 查找 状态为1 的条件
*
* 语法:scope 开头,后面名称尽可能包含语义
*
* @param $query
* @return mixed
*/
public function scopeStatusTrue($query)
{
return $query->where('status', 1);
}
}

然后在这个模型下调用:

$users = User::statusTrue()
->where('price', '>', 90)
->get();
return [$users];

3、上面这种方式是比较死板的。可以通过参数传递的方式,使本地作用域更灵活:

/**
* App\Models\Models\User
*
* 查找 状态为value1,性别为value2 的条件
*
* 语法:scope 开头,后面名称尽可能包含语义
*
* @param $query
* @param int $value1 状态
* @param string $value2 性别
* @return mixed
*/
public function scopeStatusTrue($query, $value1 = 1, $value2 = '男')
{
return $query->where('status', $value1)->where('gender', $value2);
}

然后再使用:

$users = User::statusTrue(1, '女')
->where('price', '>', 90)
->get();

return [$users];

7.2 全局作用域


全局作用域,顾名思义就是在任意地方都可以有效的封装条件;


1、比如有个需求,不管在哪里操作,总是显示status 为1 的用户;那么首先在 ​​app​​​ 目录下创建一个用于​​全局作用域的目录:Scopes​​​,然后创建一个类:​​StatusScope​​​,并让其实现Scope ​​implements Scope​​,如下:

【Laravel笔记】7. 模型的作用域_封装

这里,会报错,按 ​​Alt+Enter​​ ,根据提示添加代码即可。此时,完整的代码是这样的:

<?php
namespace App\Scopes;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;

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 void
*/
public function apply(Builder $builder, Model $model)
{
// TODO: Implement apply() method.

}
}

然后在上面的 ​​apply​​ 方法中写入内容:

public function apply(Builder $builder, Model $model)
{
// TODO: Implement apply() method.
return $builder->where('status', 1);
}

此时,还不能实现全局,因为需要在模型设置个开关,让其富有灵活性;

在 ​​User​​ 模型中,写入如下内容:

use App\Scopes\StatusScope;//这里会自动引入

class User extends Model
{
//输入:booted,根据提示添加即可
protected static function booted()
{
parent::booted(); // TODO: Change the autogenerated stub
//添加这行代码
static::addGlobalScope(new StatusScope());
}
}

然后,在控制层,不需要添加任何设置,即可自动为所有查询添加 ​​status=1​​ 的条件。

2、如果某个全局,只是针对某个模块,并不需要创建一个全局类,直接闭包即可实现:

use Illuminate\Database\Eloquent\Builder;//注意,引入的是这个Builder

class User extends Model
{
//输入:booted,根据提示添加即可
protected static function booted()
{
///parent::booted(); // TODO: Change the autogenerated stub
///static::addGlobalScope(new StatusScope());

//使用闭包实现,第一个参数是状态名,必须起名
static::addGlobalScope('status', function (Builder $builder) {
return $builder->where('status', 1);
});

//可以再创建一个:
static::addGlobalScope('gender', function (Builder $builder) {
return $builder->where('gender', '男');
});
}
}

3、如果某个查询,不需要这个全局条件,可以单独移出掉:

//取消名称为status 的全局
$users = User::withoutGlobalScope('status')->get();

///取消名为status,gender的两个全局:
$users = User::withoutGlobalScopes(['status', 'gender'])->toSql();

//取消所有的全局类的条件
$users = User::withoutGlobalScope(StatusScope::class)->get();

以上。



举报

相关推荐

0 条评论