【Laravel】为Eloquent 模型设置全局作用域和局部作用域进行查询
全局作用域
所谓「全局作用域」,指的是预置过滤器在注册该「全局作用域」的模型类的所有查询中生效,不需要指定任何额外条件。
以 User
模型类为例,我们在系统中可能只想针对已经验证过邮箱的用户进行操作,在没有介绍「作用域」之前,可能你会在应用中到处编写这样的代码:
$users = User::whereNotNull('email_verified_at')->...
通过全局作用域类实现
要实现「全局作用域」,首先需要编写一个实现 Illuminate\Database\Eloquent\Scope
接口的全局作用域类,这里我们将其命名为 EmailVerifiedAtScope
,并将其放到 app/Scopes
目录下:
<?php
namespace App\Scopes; use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope; class EmailVerifiedAtScope implements Scope
{
public function apply(Builder $builder, Model $model)
{
return $builder->whereNotNull('email_verified_at');
}
}
在这个全局作用域类中,只需要实现 apply
方法即可,在该方法中,在查询构建器上应用过滤器方法并将其返回。
然后,我们需要将这个全局作用域类注册到 User
模型类上,这样,在 User
模型类上进行查询的时候才可以应用相应的过滤条件。这个工作可以通过在 User
模型类中重写父类的 boot
方法来完成:
protected static function boot()
{
parent::boot(); static::addGlobalScope(new EmailVerifiedAtScope());
}
注:boot
方法会在模型类实例化的时候调用。你可以在这里进行一些模型类的初始化操作。
通过匿名函数实现
如果你觉得编写一个「全局作用域」类很麻烦,过滤逻辑又很简单,还可以在模型类的 boot
方法中通过匿名函数实现全局作用域:
protected static function boot()
{
parent::boot(); //static::addGlobalScope(new EmailVerifiedAtScope());
static::addGlobalScope('email_verified_at_scope', function (Builder $builder) {
return $builder->whereNotNull('email_verified_at');
});
}
实现效果和上面通过全局作用域类完全一样。
移除全局作用域
在某些特定场景下,我们可能需要移全局作用域,比如在后台用户管理页,我们需要将未验证邮箱的用户页显示出来,这个时候我们可以借助模型类的 withoutGlobalScope
方法来实现,该方法支持多种传参格式,移除多种全局作用域及其组合:
User::withoutGlobalScope(EmailVerifiedAtScope::class)->get(); # 指定类
User::withoutGlobalScope('email_verified_at_scope')->get(); # 匿名函数
User::withoutGlobalScopes()->get(); # 移除所有全局作用域
User::withoutGlobalScopes([FirstScope::class, SecondScope::class])->get(); # 移除多个类/匿名函数
局部作用域
所谓「局部作用域」,指的是预置过滤器在对应模型类的指定查询中生效,与「全局作用域」不同,「局部作用域」需要额外指定才能生效,但是相应的,也更加灵活,可以适用于不同场景。
「局部作用域」的实现也比较简单,在需要应用它的模型类中定义一个过滤器方法即可。该方法需要以 scope
开头,然后附加该过滤器的名称,以文章列表页显示最流行文章为例(按照浏览数逆序),可以在 Post
模型类中编写一个 scopePopular
方法:
public function scopePopular(Builder $query)
{
return $query->where('views', '>', '0')->orderBy('views', 'desc');
}
而在文章详情页,我们希望展示的是已发布的文章详情,如果文章没有发布,返回 404,因此我们再定义一个「局部作用域」方法 scopeActive
:
public function scopeActive(Builder $query)
{
return $query->where('status', Post::ACTIVED);
}
在模型类上调用「局部作用域」过滤器方法只需调用 scope
之后的过滤器名称即可,Eloquent 底层会通过魔术方法自动调用对应完整方法:
$post = Post::active()->find(100);
$post = Post::active()->popular()->get();
动态作用域
此外,Eloquent 模型类还支持「动态作用域」,所谓动态作用域指的是在查询过程中动态设置预置过滤器的查询条件,动态作用域和局部作用域类似,过滤器方法名同样以 scope
开头,只不过可以通过额外参数指定查询条件,比如我要在文章中查询指定类型的文章,可以通过在 Post
模型类中定义如下方法:
public function scopeOfType(Builder $query, $type)
{
return $query->where('type', $type);
}
这样,在查询指定类型的文章时,就可以这么实现:
$posts = Post::active()->ofType(Post::Article)->get();
【Laravel】为Eloquent 模型设置全局作用域和局部作用域进行查询的更多相关文章
- 使用laravel的Eloquent模型获取数据库的指定列
使用laravel的Eloquent模型获取数据库的指定列 使用Laravel的ORM——Eloquent时,时常遇到的一个操作是取模型中的其中一些属性,对应的就是在数据库中取表的特定列. 如果使 ...
- JS 全局作用域和局部作用域
一.作用域 1.什么是作用域(Scope) 通常来说,一段程序代码中所用到的名字不总是有效和可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域. JS作用域:就是代码名字(变量)作用的范围 ...
- JavaScript基础&实战(4)js中的对象、函数、全局作用域和局部作用域
文章目录 1.对象的简介 2.对象的基本操作 2.1 代码 2.2 测试结果 3.属性和属性值 3.1 代码 3.2 测试结果 4.对象的方法 4.1 代码 4.2 测试结果 5.对象字面量 5.1 ...
- Laravel笔记--Eloquent 模型
Eloquent 模型 默认继承use Illuminate\Database\Eloquent\Model类. 数据表名称与模型名称约定: 数据库的表名一般使用“蛇形命名法”命名.蛇形命名法要求单词 ...
- 【laravel】Eloquent 模型事件和监听方式
所有支持的模型事件 在 Eloquent 模型类上进行查询.插入.更新.删除操作时,会触发相应的模型事件,不管你有没有监听它们.这些事件包括: retrieved 获取到模型实例后触发 creatin ...
- laravel 为Eloquent 模型添加replace 和insert ignore 查询功能
安装:composer require jdavidbakr/replaceable-model 在模型里引入: class model extends Model { ... use \jdavid ...
- eval全局作用域和局部作用域的坑!
1.eval 是个函数,他可以被赋值给变量,例如 var evalg = eval; evalg("alert(1)"); 2.eval被赋值时,也会把当前eval所处的变量 ...
- laravel Eloquent 模型(也就是我本时说的Model)
laravel的 Eloquent 模型其实就是我们平时说的MVC里Model,只是换了个名字而已~ 1)Eloquent 是啥? Eloquent 本质就一个查询构建器(laravel里叫查询构建器 ...
- Laravel 5.1 文档攻略 —— Eloquent:模型关系
简介 其实大家都知道,数据表之间都是可以关联的,前面讲过了,Eloquent ORM是数据模型操作代替表操作,那么表的关联查询,在Eloquent这里也就是模型间的关联查询,这就是本章的主要内容: E ...
随机推荐
- JDK8--09:全新的时间API
在JDK8之前,时间有各种问题,最大的问题就是,我们使用的时间格式化类SimpleDateFormat不是线程安全的 为了更准确的说明SimpleDateFormat非线程安全,演示一个并发做时间格式 ...
- 洛谷 P4017 【最大食物链计数】
看到这种明显的有向无环图,并且等级分明,自然而然就能想到拓补排序啦.对于这道题,我们就可以利用最短路计数的那种思想(不知道也没关系),设\(j\)是\(i\)的后继,\(dis_i\)表示以\(i\) ...
- 一个神奇的SQL语句
题目是这样的: 分别往这两张表中添加3条数据... 查询营业额最高商家的商品总价与营业额最低商家的商品总价差是多少(5分)CREATE VIEW vm2 AS SELECT price*limit_n ...
- 阿里云Linux CentOS8.1 64位服务器安装LNMP(Linux+Nginx+MySQL+PHP) 并发调试之php-fpm配置及其与Nginx的通信
一.php-fpm的配置 1. php-fpm的配置,首先要关注进程数量. php-fpm的进程管理方式有三种:static.dynamic.ondemand. static方式,开启固定数量(pm. ...
- Python3笔记022 - 5.1 字符串常用操作
第5章 字符串及正则表达式 5.1 字符串常用操作 5.1.1 拼接字符串 使用+运算符可完成多个字符串的拼接,产生一个新的字符串对象. str1 = "2020年07月06日是" ...
- ShuffleNetV1/V2简述 | 轻量级网络
ShuffleNet系列是轻量级网络中很重要的一个系列,ShuffleNetV1提出了channel shuffle操作,使得网络可以尽情地使用分组卷积来加速,而ShuffleNetV2则推倒V1的大 ...
- POJ3263 Tallest Cow 差分
题目描述 FJ's N (1 ≤ N ≤ 10,000) cows conveniently indexed 1..N are standing in a line. Each cow has a p ...
- 介绍python由来, 安装python3.8.3 及其变量的定义, 小整数池
介绍 python的创始人为吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,Guido开始写能够解释Python语言语法的解释器.Python这个名字,来自Guido所挚爱 ...
- 大话深度学习:B站Up主麦叔教你零代码实现图像分类神经网络
之前,我在B站发布了“大话神经网络,10行代码不调包,听不懂你打我!”的视频后,因为简单易懂受到了很多小伙伴的喜欢! 但也有小伙伴直呼不够过瘾,因为大话神经网络只有4个神经元. 也有小伙伴问不写代码, ...
- 我为什么不再推荐 RxJava
本文转自作者: W_BinaryTree 链接:juejin.im/post/5cd04b6e51882540e53fdfa2,如有侵权,可删除 距离上一次更新也有一段时间了,其实这篇文章我早就想写, ...