【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 ...
随机推荐
- js事件入门(1)
1.事件相关概念 1.1 什么是事件? 事件是用户在访问页面时执行的操作,也就是用户访问页面时的行为.当浏览器探测到一个事件时,比如鼠标点击或者按键.它可以触发与这个事件相关的JavaScript对象 ...
- Unity ugui Anchor锚点自动适配画布中的相对位置
本随笔参考了以下博客,在此基础上进行优化和改进: https://blog.csdn.net/qq_39640124/article/details/88284191 ugui中的Anchor预设如下 ...
- SQL语法LPAD和RPAD
一.[LPAD左侧补齐] LPAD(str,len,padstr) LPAD(str,len,padstr) 返回字符串 str, 其左边由字符串padstr 填补到len 字符长度.假如str 的长 ...
- Python 3.10 的首个 PEP 诞生,内置类型 zip() 迎来新特性
译者前言:相信凡是用过 zip() 内置函数的人,都会赞同它很有用,但是,它的最大问题是可能会产生出非预期的结果.PEP-618 提出给它增加一个参数,可以有效地解决大家的痛点. 这是 Python ...
- 阿里云Linux CentOS8.1 64位服务器安装LNMP(Linux+Nginx+MySQL+PHP) 并发调试之调试工具ab(apache bench)
ab 测试工具,全称是 apache bench ,是 Apache 提供的一款测试工具,具有简单易上手的特点,在测试 Web 服务时非常实用. ab 可以在 Windows 系统中使用,也可以在 L ...
- 01-springboot整合elasticsearch初识
1.elasticsearch 1.es简介 Elasticsearch 是一个分布式.高扩展.高实时的搜索与数据分析引擎.它能很方便的使大量数据具有搜索.分析和探索的能力.充分利用Elas ...
- MVC中model、dao、view、controlller、service之间的关系
Model:是事物的模型,如Person.java,定义人的属性行为.pojo,OR maping,持久层 Dao:是持久化操作代码编写处,与数据库对接,如对Person进行增删改查. Service ...
- call,apply,bind的内部原理实现
call call 方法使用一个函数执行的时候更改本身 this 指向,并传入一个或者多个参数. var obj = { name: '$call' } function _fun() { conso ...
- MyBatis和Spring整合的奥秘
本篇博客源码分析基于Spring 5.1.16.RELEASE,mybatis-spring 2.0.0,较高版本的mybatis-spring源码有较大区别. Spring之所以是目前Java最受欢 ...
- java 基本语法(十五)Lambda (二)函数式接口
1.函数式接口的使用说明> 如果一个接口中,只声明了一个抽象方法,则此接口就称为函数式接口.> 我们可以在一个接口上使用 @FunctionalInterface 注解,这样做可以检查它是 ...