Laravel 中 scope 作用域
Posted 知其黑、受其白
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Laravel 中 scope 作用域相关的知识,希望对你有一定的参考价值。
阅读目录
一、查询作用域
1.1 全局作用域
全局作用域可以给模型的查询都添加上约束。
Laravel 的 软删除 功能就是利用此特性从数据库中获取 「未删除」的模型。
你可以编写你自己的全局作用域,很简单、方便的为每个模型查询都加上约束条件:
1 编写全局作用域
编写全局作用域很简单。
定义一个实现 Illuminate\\Database\\Eloquent\\Scope
接口的类,并实现 apply
这个方法。
根据你的需求,在 apply
方法中加入查询的 where
条件:
<?php
namespace App\\Scopes;
use Illuminate\\Database\\Eloquent\\Scope;
use Illuminate\\Database\\Eloquent\\Model;
use Illuminate\\Database\\Eloquent\\Builder;
class AgeScope implements Scope
/**
* 把约束加到 Eloquent 查询构造中。
*
* @param \\Illuminate\\Database\\Eloquent\\Builder $builder
* @param \\Illuminate\\Database\\Eloquent\\Model $model
* @return void
*/
public function apply(Builder $builder, Model $model)
$builder->where('age', '>', 200);
tip 如果需要在 select 语句里添加字段,应使用
addSelect
方法,而不是 select 方法。
这将有效防止无意中替换现有 select 语句的情况。
应用全局作用域
要将全局作用域分配给模型,需要重写模型的 boot
方法并使用 addGlobalScope
方法:
<?php
namespace App;
use App\\Scopes\\AgeScope;
use Illuminate\\Database\\Eloquent\\Model;
class User extends Model
/**
* 模型的 「启动」 方法.
* @return void
*/
protected static function boot()
parent::boot();
static::addGlobalScope(new AgeScope);
添加作用域后,对 User::all()
的查询会生成以下 SQL 查询语句:
select * from `users` where `age` > 200
2 匿名全局作用域
Eloquent 同样允许使用闭包定义全局作用域,这样就不需要为一个简单的作用域而编写一个单独的类:
<?php
namespace App;
use Illuminate\\Database\\Eloquent\\Model;
use Illuminate\\Database\\Eloquent\\Builder;
class User extends Model
/**
*模型的「启动」方法.
* @return void
*/
protected static function boot()
parent::boot();
static::addGlobalScope('age', function (Builder $builder)
$builder->where('age', '>', 200);
);
3 取消全局作用域
如果需要对当前查询取消全局作用域,需要使用 withoutGlobalScope
方法。
该方法仅接受全局作用域类名作为它唯一的参数:
User::withoutGlobalScope(AgeScope::class)->get();
或者,如果使用闭包定义全局作用域的话:
User::withoutGlobalScope('age')->get();
如果你需要取消部分或者全部的全局作用域的话,需要使用 withoutGlobalScopes 方法:
// 取消所有的全局作用域...
User::withoutGlobalScopes()->get();
// 取消部分全局作用域...
User::withoutGlobalScopes([
FirstScope::class, SecondScope::class
])->get();
1.2 本地作用域
本地作用域允许定义通用的约束集合以便在应用程序中重复使用。
例如,你可能经常需要获取所有 「流行」的用户。
1 编写本地作用域
要定义这样一个范围,只需要在对应的 Eloquent 模型方法前添加 scope 前缀:
作用域总是返回一个查询构造器实例:
<?php
namespace App;
use Illuminate\\Database\\Eloquent\\Model;
class User extends Model
/**
* 只查询受欢迎的用户的作用域.
*
* @param \\Illuminate\\Database\\Eloquent\\Builder $query
* @return \\Illuminate\\Database\\Eloquent\\Builder
*/
public function scopePopular($query)
return $query->where('votes', '>', 100);
/**
* 只查询 active 用户的作用域.
*
* @param \\Illuminate\\Database\\Eloquent\\Builder $query
* @return \\Illuminate\\Database\\Eloquent\\Builder
*/
public function scopeActive($query)
return $query->where('active', 1);
使用本地作用域
一旦定义了作用域,就可以在查询该模型时调用作用域方法。
不过,在调用这些方法时不必包含 scope 前缀。
甚至可以链式调用多个作用域,例如:
$users = App\\User::popular()->active()->orderBy('created_at')->get();
借助 or
查询运行符整合多个 Eloquent 模型,可能需要使用闭包回调:
$users = App\\User::popular()->orWhere(function (Builder $query)
$query->active();
)->get();
因为这样可能会有点麻烦,Laravel 提供了「高阶的」 orWhere 方法,它允许你在链式调用作用域时不使用闭包:
$users = App\\User::popular()->orWhere->active()->get();
2 动态作用域
有时可能地希望定义一个可以接受参数的作用域。
把额外参数传递给作用域就可以达到此目的。
作用域参数要放在 $query
参数之后:
<?php
namespace App;
use Illuminate\\Database\\Eloquent\\Model;
class User extends Model
/**
* 将查询作用域限制为仅包含给定类型的用户。
*
* @param \\Illuminate\\Database\\Eloquent\\Builder $query
* @param mixed $type
* @return \\Illuminate\\Database\\Eloquent\\Builder
*/
public function scopeOfType($query, $type)
return $query->where('type', $type);
这样就可以在调用作用域时传递参数了:
$users = App\\User::ofType('admin')->get();
二、应用示例
$user = new ChatUser();
$chat_user = $user::scopeNickName($user,"大金")->get();
dd($chat_user->toArray());
运行结果
rray:1 [
0 => array:35 [
"id" => 87
"mpid" => 1
"openid" => "oYxpK0RsvcwgS9DtmIOuyb_BgJbo"
"nickname" => "大金"
"headimgurl" => "https://img-home.csdnimg.cn/images/20210817021749.png"
"sex" => 1
"subscribe" => 1
"subscribe_time" => 1508920878
"unsubscribe_time" => null
"relname" => null
"signature" => null
"mobile" => null
"is_bind" => 0
"language" => "zh_CN"
"country" => "中国"
"province" => "河南"
"city" => "商丘"
"remark" => ""
"group_id" => 0
"groupid" => 0
"tagid_list" => "[]"
"score" => 0
"money" => "0.00"
"latitude" => null
"longitude" => null
"location_precision" => null
"type" => 0
"unionid" => null
"password" => null
"last_time" => 586969200
"parentid" => 1
"isfenxiao" => 0
"totle_earn" => "0.00"
"balance" => "0.00"
"fenxiao_leavel" => 2
]
]
以上是关于Laravel 中 scope 作用域的主要内容,如果未能解决你的问题,请参考以下文章