3分钟短文:Laravel模型作用域,为你“节省”更多代码
引言
原则上代码写一次,处处是引用,不需要大量的冗余代码,这是一种趋势,也是提高代码健壮性的努力方向。
laravel模型为我们提供了一层数据库操作层,将数据交互独立出来。
但是久而久之,随着项目的需求不断扩大,最常用的查询操作,同样会有大量的冗余代码。
本文就来讲讲,连模型的自我瘦身,缩减模型的代码。
全局作用域
假设有些数据库查询操作,无论是在控制器内,或者在模板文件内,或者命令行方法内,都有重复的使用需求,要是在模型内有一个公用的方法,默认就加上这些筛选条件,就可以显著减少代码量了。
比如有一个查询条件:
$publishedEvents = Event::where('published', '=', 1)->get();
上述代码最后生成的SQL语句如下:
SELECT * FROM events WHERE `published` = 1;
如果条件 published = 1 在默认的情况下需要开启,我们可以使用laravel模型的 全局作用域 方式为所有查询追加上这个条件。
在模型文件 Event 内头部引入下述类:
use IlluminateDatabaseEloquentModel;
use IlluminateDatabaseEloquentBuilder;
在模型类内部,手动实现 boot 方法:
protected static function boot()
{
parent::boot();
static::addGlobalScope('published', function (Builder $builder) {
$builder->where('published', '=', 1);
});
}
这样SQL语句 where published = 1 就会追加到所有的模型查询方法内,只要是创建生成了 QueryBuilder 对象的,都会附加上此约束语句。
那有些读者可能要问了:“如果我不想要这个约束语句,岂不是连模型也永不了了?”
那哪儿能呢!不过就是QueryBuilder的一个属性数组的一个元素而已,手动移除就行了,这样特例问题就解决了。
$events = Event::withoutGlobalScopes()->get();
看到了吧,追加上很简单,移除更简单。
本地作用域
接上一节的 withoutGlobalScope 要每次手动屏蔽的方式不同,有时候使用有局限的作用域更能解决问题。所以,本地作用域 应运而生,专门用于某个模型文件的方法,手动调用的时候就起作用,不调用就不会主动追加。
而声明一个本地作用域,只要遵循laravel的语法规定即可,如下示例:
public function scopePublished($query)
{
return $query->where('published', 1);
}
只需要声明一个以 scope 为首的小驼峰命名的函数方法即可,并返回一个 QueryBuilder 对象实例。调用的时候要手动追加上:
$events = Event::published()->get();
其中 published()方法就是映射到 scopePublished 方法。
上面的演示代码,没有接收用户输入,下面演示一下带参的传递方式。比如有这样一个查询需求:
$events = Event::where('zip', $zipCode)->get();
使用本地作用域实现出来:
public function scopeZip($query, $zip)
{
return $query->where('zip', $zip);
}
按照位置传入即可。使用的使用,直接传入:
$zip = '43016';
$events = Event::zip($zip)->get();
这样就完成了本地作用域的使用,是不是很直观。
既然本地作用域返回的是 QueryBuilder 实例,那么自然就可以链式调用本地作用域的方法,和 QueryBuilder 的方法。我们再声明一个本地作用域方法:
public function scopeAttendees($query, $maximum)
{
return $query->where('max_attendees', $maximum);
}
现在把上述两个方法串联使用:
$events = Event::zip(43016)->attendees(2)->get();
生成的SQL语句也符合预期:
SELECT * FROM events WHERE zip = '43016' and max_attendees = '2';
写在最后
本期我们又旧事重提,把laravel模型的作用域设计方法拿出来温习了一下。讲述了两个方法:
- 全局作用域:全局起作用,需要手动移除;
- 本地作用域:只有手动调用起作用,可链式使用;
这样的设计模式可以很大程度上节约查询代码,但是对于维护,需要同等熟悉的开发者彼此遵循开发规范,写出可维护的代码。
Happy coding :-)
- 谈谈分布式事务之二:基于DTC的分布式事务管理模型[上篇]
- 学习SpringMVC——拦截器
- 学习SpringMVC——国际化+上传+下载
- 行业研究:大数据(一)
- 控制并发访问的三道屏障: WCF限流(Throttling)体系探秘[下篇]
- 如何通过VPC在本机搭建局域网
- 你常用的10个MySQL命令
- WCF技术剖析之三十一: WCF事务编程[下篇]
- WCF技术剖析之三十一:WCF事务编程[上篇]
- 学习SpringMVC——你们要的REST风格的CRUD来了
- 并发中的同步--WCF并发体系的同步机制实现
- WCF 技术剖析之三十三:你是否了解WCF事务框架体系内部的工作机制?[下篇]
- 学习SpringMVC——从HelloWorld开始
- 小程序年底重磅更新,小游戏上线,最强入口也来了!
- php概述
- php教程
- php环境搭建
- PHP书写格式
- php变量
- php常量
- PHP注释
- php数组
- php字符串 string
- PHP整型 integer
- PHP浮点型 float
- php布尔型
- php数据类型之数组
- php数据类型之对象
- php数据类型之null
- php数据类型之间的转换
- php运算符
- php表达式
- PHP循环控制
- PHP流程控制
- php函数
- php全局变量
- PHP魔术变量
- php命名空间
- php 日期
- PHP包含文件
- php文件
- PHP 文件上传
- php Cookies
- php Sessions
- php email
- php安全email
- php错误处理
- PHP异常处理
- php过滤器
- PHP 高级过滤器
- php json
- php 表单
- PHP MySQL 简介
- PHP 连接 MySQL
- php创建数据库
- php 创建表
- php mysq 插入数据
- PHP MySQL 插入多条数据
- PHP MySQL 预处理语句
- php mysql 读取数据
- php mysql where
- PHP MySQL Order By
- PHP MySQL Update
- PHP MySQL Delete
- php ODBC
- spring之操作数据库之使用NamedParameterJdbcTemplate(具名参数)
- 谷歌colab上安装百度paddlepaddle框架
- 谷歌colab运行paddlepaddle之手写数字识别
- 【python-leetcode112-树的深度遍历】路径总和
- spring之第一个spring程序
- 【python-leetcode437-树的深度遍历】路径总和Ⅲ
- 双指针--合并两个排序数组
- spring之事务的其它属性(隔离级别、回滚、只读、过期)(四)
- 二分查找
- 一文弄懂数组的和
- spring之基于xml文件来配置事务(五)
- hash算法的应用
- 树的遍历
- spring之事务的传播行为(三)
- 深度优先遍历--怎么抓住小偷