laravel为Model设置全局作用域
如果一个项目中存在这么一个sql条件在任何情况下或大多数情况都会被使用,同时很容易被开发者遗忘,那么就非常适用于今天要提到的这个功能,Eloquent\Model的全局作用域。
首先看一个示例,有个数据表,结构如下:
现用Laravel写一个查询语句:
$post = PostModel::where('cate_id', 2)->toSql();
打印$post结果是:"select * from `news_post` where `cate_id` = ?"
现在就是只想查属于ID为001的学校的post数据,其他许多表都有这个school_id字段,都需要在查询时使用。这就是我们需要解决的简化的操作,实现自动在sql条件中添加"and school_id='ID001'"
结合官方文档和搜索引擎查询结果,找到一个实现方案就是设置全局作用域:
首先创建基础Model并 添加scope:
namespace App\Models;use App\Models\Scopes\MyScopes;
use Illuminate\Database\Eloquent\Model;class BaseModel extends Model
{public $school_id = '';public $alias = '';public function __construct(array $attributes = []){$this->bootIfNotBooted();$this->initializeTraits();$this->syncOriginal();$token = app()->get('mytoken');$user = getDataByToken($token); //根据token获取存储在redis里的用户数据if(!empty($user) && isset($user['school_id'])){$attributes['school_id'] = $this->school_id = $user['school_id'];}$this->fill($attributes);}protected static function boot(){parent::boot();static::addGlobalScope(new MyScopes());}}
在构造方法中通过登录token信息获取用户的基础信息包括所属学校ID,赋值给model属性,同时在boot中addGlobalScope全局添加自定义作用域,MyScopes如下:
namespace App\Models\Scopes;use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;class MyScopes implements Scope{public function apply(Builder $builder, Model $model){$from = $builder->getQuery()->from;//表 + 别名(如果有的话)if(is_string($from)){ //不考虑非字符串情况,如子查询$fromArr = explode(' ', str_ireplace(' as ', ' ', $from));$alias = isset($fromArr[1]) ? $fromArr[1] : '';//添加全局条件if(!empty($model->school_id)){$fieldName = $alias ? $alias . '.' . 'school_id' : 'school_id';$builder->where($fieldName, $model->school_id);}}}
}
根据model属性是否有值决定是否添加查询条件,$builder->getQuery()获取到的是Query\Builder实例:
同时依据from来判断是否存在别名的情况,附加别名,适配为表设置别名或联查情况。
最后在后续创建Model时都需要继承BaseModel即可。
这样重新执行最开始的sql查询语句,打印出来的结果就是:
"select * from `news_post` where `cate_id` = ? and `school_id` = ?"
这样就达到了预期的效果,自动添加查询条件了,下面再试试增删改
更新:
DB::enableQueryLog();
PostModel::where('cate_id', 2)->update(['is_hot' => 1]);
$log = DB::getQueryLog();
var_dump($log);exit;
打印结果:
array(1){
[
0
]=>array(3){
[
"query"
]=>string(75)"update `news_post` set `is_hot` = ? where `cate_id` = ? and `school_id` = ?"[
"bindings"
]=>array(3){
[
0
]=>int(1)[
1
]=>int(2)[
2
]=>string(5)"ID001"
}[
"time"
]=>float(310.23)
}
}
删除:
DB::enableQueryLog();
PostModel::where(['title' => '春天', 'is_hot' => 0])->delete();
$log = DB::getQueryLog();
var_dump($log);exit;
打印结果:
array(1){
[
0
]=>array(3){
[
"query"
]=>string(80)"delete from `news_post` where (`title` = ? and `is_hot` = ?) and `school_id` = ?"[
"bindings"
]=>array(3){
[
0
]=>string(6)"春天"[
1
]=>int(0)[
2
]=>string(5)"ID001"
}[
"time"
]=>float(217.09)
}
}
增:
DB::enableQueryLog();
$model = new PostModel();
$model->setAttribute('title', '冬天');
$model->setAttribute('content', '冬天,寒风彻骨!');
$model->setAttribute('uid', 1);
$model->setAttribute('cate_id', 2);
$model->setAttribute('createtime', time());
/* $model->title='冬天';
$model->content='冬天,寒风彻骨!';
$model->uid=1;
$model->cate_id=2;
$model->createtime=time();*/
$model->save();
$log = DB::getQueryLog();
var_dump($log);exit;
打印结果:
array(1){
[
0
]=>array(3){
[
"query"
]=>string(115)"insert into `news_post` (`school_id`, `title`, `content`, `uid`, `cate_id`, `createtime`) values (?, ?, ?,
?, ?, ?)"[
"bindings"
]=>array(6){
[
0
]=>string(5)"ID001"[
1
]=>string(6)"冬天"[
2
]=>string(22)"冬天,寒风彻骨!"[
3
]=>int(1)[
4
]=>int(2)[
5
]=>int(1721413065)
}[
"time"
]=>float(48.68)
}
}
插入时也自动加入了school_id的数据
插入有多重形式,试试其他的:
create方法:
DB::enableQueryLog();
$data = ['title' => '秋天','content' => '秋天,是收获的季节,也是思念的季节,它以一种宁静而深沉的美,让人沉醉!','uid' => 2,'cate_id' => 2,'createtime' => time(),
];
PostModel::create($data);
$log = DB::getQueryLog();
var_dump($log);exit;
打印结果:
array(1){
[
0
]=>array(3){
[
"query"
]=>string(115)"insert into `news_post` (`title`, `content`, `uid`, `cate_id`, `createtime`, `school_id`) values (?, ?, ?,
?, ?, ?)"[
"bindings"
]=>array(6){
[
0
]=>string(6)"秋天"[
1
]=>string(105)"秋天,是收获的季节,也是思念的季节,它以一种宁静而深沉的美,让人沉醉!"[
2
]=>int(2)[
3
]=>int(2)[
4
]=>int(1721413472)[
5
]=>string(5)"ID001"
}[
"time"
]=>float(142.4)
}
}
由上可知 create方法同样适用。
insert方法:
DB::enableQueryLog();
$data = ['title' => '秋天','content' => '秋风送爽,落叶轻舞,绘就一幅金色的画卷。','uid' => 2,'cate_id' => 2,'createtime' => time(),
];
PostModel::insert($data);
$log = DB::getQueryLog();
var_dump($log);exit;
打印结果:
array(1){
[
0
]=>array(3){
[
"query"
]=>string(99)"insert into `news_post` (`title`, `content`, `uid`, `cate_id`, `createtime`) values (?, ?, ?, ?, ?)"[
"bindings"
]=>array(5){
[
0
]=>string(6)"秋天"[
1
]=>string(60)"秋风送爽,落叶轻舞,绘就一幅金色的画卷。"[
2
]=>int(2)[
3
]=>int(2)[
4
]=>int(1721413774)
}[
"time"
]=>float(145.6)
}
}
由上可见insert方法似乎不适用。其实也可以从源码中看出端倪,Illuminate\Database\Eloquent\Builder中有一个属性:
表明了这些方法都是从query builder返回结果的。且在Eloquent\Builder中确实没有找到insert方法的定义,这也就导致基于Eloquent\Builder的一些操作没有生效。
同时使用Illuminate\Support\Facades\DB的操作也是基于query builder的亦无法使用作用域或model属性添加额外条件。
在Illuminate\Database\Query\Builder中找到了一个属性如下介绍:
感觉似乎可以在query执行前进行干预,查询相关资料,在provider中尝试注册了下但没有生效,若有成功的大佬希望能交流一下。
接下来尝试下连表查询:
$log = PostModel::from('post as p')->leftjoin('user as u', 'p.uid', '=', 'u.id')->where(['p.cate_id' => '2'])->toSql();
打印结果:
"select * from `news_post` as `news_p` left join `news_user` as `news_u` on `news_p`.`uid` = `news_u`.`id` where (`news_p`.`cate_id` = ?) and `news_p`.`school_id` = ?"
子表查询:
DB::enableQueryLog();
$subQuery = PostModel::where('is_hot', 1)->select(['uid', 'title','cate_id']);
$post = PostModel::fromSub($subQuery, 'p')->where('cate_id', 2)->select(['title'])->get();
$log = DB::getQueryLog();
var_dump($log);exit;
打印结果:
array(1){
[
0
]=>array(3){
[
"query"
]=>string(142)"select `title` from (select `uid`, `title`, `cate_id` from `news_post` where `is_hot` = ? and `school_id` =
?) as `news_p` where `cate_id` = ?"[
"bindings"
]=>array(3){
[
0
]=>int(1)[
1
]=>string(5)"ID001"[
2
]=>int(2)
}[
"time"
]=>float(23.76)
}
}
子表条件查询:
DB::enableQueryLog();
$subQuery = PostModel::where('is_hot', 1)->select([DB::raw('DISTINCT(uid)')]);
UserModel::whereIn('uid', $subQuery)->get(['username']);
$log = DB::getQueryLog();
var_dump($log);exit;
打印结果:
array(1){
[
0
]=>array(3){
[
"query"
]=>string(148)"select `username` from `news_user` where `uid` in (select DISTINCT(uid) from `news_post` where `is_hot` = ?
and `school_id` = ?) and `school_id` = ?"[
"bindings"
]=>array(3){
[
0
]=>int(1)[
1
]=>string(5)"ID001"[
2
]=>string(5)"ID001"
}[
"time"
]=>float(31.77)
}
}
测试的差不多了,综上除了insert方法,基于Model的增删改查操作,全局作用域基本都能生效,
且insert方法可以被save或create方法代替。
而基于Facades\DB的数据库操作如何全局添加条件还未找到可实现的方案,目前想到的是把Facades\DB进行封装,调用封装好的方法或对象,另外可以从Query\Builder的$beforeQueryCallbacks找突破口。希望有好的解决方案的大佬能分享出来,感谢!
相关文章:

laravel为Model设置全局作用域
如果一个项目中存在这么一个sql条件在任何情况下或大多数情况都会被使用,同时很容易被开发者遗忘,那么就非常适用于今天要提到的这个功能,Eloquent\Model的全局作用域。 首先看一个示例,有个数据表,结构如下࿱…...

Leetcode之string
目录 前言1. 字符串相加2. 仅仅反转字母3. 字符串中的第一个唯一字符4. 字符串最后一个单词的长度5. 验证回文串6. 反转字符串Ⅱ7. 反转字符串的单词Ⅲ8. 字符串相乘9. 打印日期 前言 本篇整理了一些关于string类题目的练习, 希望能够学以巩固. 博客主页: 酷酷学!!! 点击关注…...

OS:处理机进程调度
1.BackGround:为什么要进行进程调度? 在多进程环境下,内存中存在着多个进程,其数目往往多于处理机核心数目。这就要求系统可以按照某种算法,动态的将处理机CPU资源分配给处于就绪状态的进程。调度算法的实质其实是一种…...
【车辆轨迹处理】python实现轨迹点的聚类(一)——DBSCAN算法
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、单辆车轨迹的聚类与分析1.引入库2.聚类3.聚类评价 二、整个数据集多辆车聚类1.聚类2.整体评价 前言 空间聚类是基于一定的相似性度量对空间大数据集进行分组…...
Apache Kylin
Apache Kylin 是一个开源的分布式分析引擎,提供 SQL 查询接口及多维分析(OLAP)能力以支持超大规模数据集。它能在亚秒级的时间内提供 PB 级数据的查询能力,非常适合大数据分析和报表系统。 ### 入门指南 #### 1. 环境准备 首先…...

为何Vue3比Vue2快
Proxy响应式 PatchFlag 编译模板时,动态节点做标记标记,分为不同的类型,如TEXT PROPSdiff算法时,可以区分静态节点,以及不同类型的动态节点 <div>Hello World</div> <span>{{ msg }}</span>…...

人工智能与社交变革:探索Facebook如何领导智能化社交平台
在过去十年中,人工智能(AI)技术迅猛发展,彻底改变了我们与数字世界互动的方式。Facebook作为全球最大的社交媒体平台之一,充分利用AI技术,不断推动社交平台的智能化,提升用户体验。本文将深入探…...

八股文之java基础
jdk9中对字符串进行了一个什么优化? jdk9之前 字符串的拼接通常都是使用进行拼接 但是的实现我们是基于stringbuilder进行的 这个过程通常比较低效 包含了创建stringbuilder对象 通过append方法去将stringbuilder对象进行拼接 最后使用tostring方法去转换成最终的…...

深度挖掘行情接口:股票市场中的关键金融数据API接口解析
在股票市场里,存在若干常见的股票行情数据接口,每一种接口皆具备独特的功能与用途。以下为一些常见的金融数据 API 接口,其涵盖了广泛的金融数据内容,其中就包含股票行情数据: 实时行情接口 实时行情接口:…...
逆向破解 对汇编的 简单思考
逆向破解汇编非常之简单 只是一些反逆向技术非常让人难受 但网络里都有方法破解 申请变量 : int a 0; 00007FF645D617FB mov dword ptr [a],0 char b b; 00007FF645D61802 mov byte ptr [b],62h double c 0.345; 00007FF645D61…...
搜维尔科技:人机交互学术应用概览
人机交互学术应用概览 搜维尔科技:人机交互学术应用概览...
植物遗传转化相关介绍【卡梅德生物】
植物的遗传转化是指以植物器官、组织、细胞或原生质体作为受体,应用重组DNA技术,将外源基因导入植物基因组,以获得转基因植物的技术。目前应用最普遍的植物基因的遗传转化方法主要有农杆菌介导法和DNA直接转入法。 一.植物遗传转化…...

0711springNews新闻系统管理 实现多级评论
0611springmvc新闻系统管理-CSDN博客 0711springNews新闻系统管理项目包 实现多级评论-CSDN博客 数据库字段 需要添加父节点id,通过该字段实现父评论和子评论的关联关系。 对象属性 实现链表,通过一个父评论可以找到它对应的所有子孙评论。 业务层 实现…...

如何在Ubuntu上安装并启动SSH服务(Windows连接)
在日常的开发和管理工作中,通过SSH(Secure Shell)连接到远程服务器是一个非常常见的需求。如果你在尝试通过SSH连接到你的Ubuntu系统时遇到了问题,可能是因为SSH服务未安装或未正确配置。本文将介绍如何在Ubuntu上安装并启动SSH服…...
docker build时的网络问题
docker build时无法yum安装包,因为无法访问外网,无法ping通外网。 解决办法: systemctl stop NetworkManager.service firewall-cmd --permanent --zonetrusted --change-interfacedocker0 systemctl start NetworkManager.service systemct…...
Vue的安全性:防范XSS攻击与安全最佳实践
引言 随着Web应用的普及,前端安全问题日益受到重视。Vue作为当下流行的前端框架,其安全性也成为开发者关注的焦点。跨站脚本攻击(XSS)是常见的Web安全漏洞之一,本文将讨论如何在使用Vue时防范XSS攻击,并分享其他Vue中的安全最佳实践。 什么是XSS攻击? XSS攻击是一种将…...

ARM架构(一)—— ARMV8V9基础概念
目录 1.ARMCore的时间线2.ARM术语小结2.1 A64和arrch642.2ARM架构现在的5个系列2.3 微架构2.4 PE2.5 Banked2.6 ARM文档术语2.7 IMPLEMENTATION DEFINFD 和 DEPRECATED2.8 EL1t和EL1h 3 ARMv7的软件架构4 安全状态切换模型4.1 Secure state和Non-secure state介绍 5 Interproce…...

如何使用Python进行数据分析
Python是一种广泛应用于数据科学和机器学习领域的编程语言。本文将介绍如何使用Python进行数据分析,包括Python在数据分析中的应用场景、常用库和工具,以及实际案例分析。 一、Python在数据分析中的应用场景 数据清洗:处理缺失值、异常值&a…...

Python学习笔记40:游戏篇之外星人入侵(一)
前言 入门知识已经学完,常用标准库也了解了,pygame入门知识也学了,那么开始尝试小游戏的开发。 当然这个小游戏属于比较简单的小游戏,复杂的游戏需要长时间的编写累计开发经验,同时也需要一定的时间才能编写出来。现在的话还是嫩…...
R的数据集读取和利用,如何高效地直接复制黏贴数据到R
R语言自带了许多内部数据集,这些数据集不仅为初学者提供了丰富的练习资源,还为研究人员和数据分析师提供了方便的数据测试和模型验证工具。在这篇文章中,我们将详细探讨如何读取和使用数据集。 一、认识数据集 1、数据和数据集 数据(Data)是指以某种形式表示…...

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?
编辑:陈萍萍的公主一点人工一点智能 未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战,在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...

智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
智慧工地管理云平台系统,智慧工地全套源码,java版智慧工地源码,支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求,提供“平台网络终端”的整体解决方案,提供劳务管理、视频管理、智能监测、绿色施工、安全管…...

【2025年】解决Burpsuite抓不到https包的问题
环境:windows11 burpsuite:2025.5 在抓取https网站时,burpsuite抓取不到https数据包,只显示: 解决该问题只需如下三个步骤: 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...

C++ 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...

JVM虚拟机:内存结构、垃圾回收、性能优化
1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...

安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖
在Vuzix M400 AR智能眼镜的助力下,卢森堡罗伯特舒曼医院(the Robert Schuman Hospitals, HRS)凭借在无菌制剂生产流程中引入增强现实技术(AR)创新项目,荣获了2024年6月7日由卢森堡医院药剂师协会࿰…...

基于IDIG-GAN的小样本电机轴承故障诊断
目录 🔍 核心问题 一、IDIG-GAN模型原理 1. 整体架构 2. 核心创新点 (1) 梯度归一化(Gradient Normalization) (2) 判别器梯度间隙正则化(Discriminator Gradient Gap Regularization) (3) 自注意力机制(Self-Attention) 3. 完整损失函数 二…...

iview框架主题色的应用
1.下载 less要使用3.0.0以下的版本 npm install less2.7.3 npm install less-loader4.0.52./src/config/theme.js文件 module.exports {yellow: {theme-color: #FDCE04},blue: {theme-color: #547CE7} }在sass中使用theme配置的颜色主题,无需引入,直接可…...
Caliper 配置文件解析:fisco-bcos.json
config.yaml 文件 config.yaml 是 Caliper 的主配置文件,通常包含以下内容: test:name: fisco-bcos-test # 测试名称description: Performance test of FISCO-BCOS # 测试描述workers:type: local # 工作进程类型number: 5 # 工作进程数量monitor:type: - docker- pro…...
Oracle11g安装包
Oracle 11g安装包 适用于windows系统,64位 下载路径 oracle 11g 安装包...