当前位置: 首页 > news >正文

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的全局作用域。 首先看一个示例,有个数据表,结构如下&#xff1…...

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 编译模板时&#xff0c;动态节点做标记标记&#xff0c;分为不同的类型&#xff0c;如TEXT PROPSdiff算法时&#xff0c;可以区分静态节点&#xff0c;以及不同类型的动态节点 <div>Hello World</div> <span>{{ msg }}</span>…...

人工智能与社交变革:探索Facebook如何领导智能化社交平台

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

八股文之java基础

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

深度挖掘行情接口:股票市场中的关键金融数据API接口解析

在股票市场里&#xff0c;存在若干常见的股票行情数据接口&#xff0c;每一种接口皆具备独特的功能与用途。以下为一些常见的金融数据 API 接口&#xff0c;其涵盖了广泛的金融数据内容&#xff0c;其中就包含股票行情数据&#xff1a; 实时行情接口 实时行情接口&#xff1a…...

逆向破解 对汇编的 简单思考

逆向破解汇编非常之简单 只是一些反逆向技术非常让人难受 但网络里都有方法破解 申请变量 &#xff1a; int a 0; 00007FF645D617FB mov dword ptr [a],0 char b b; 00007FF645D61802 mov byte ptr [b],62h double c 0.345; 00007FF645D61…...

搜维尔科技:人机交互学术应用概览

人机交互学术应用概览 搜维尔科技&#xff1a;人机交互学术应用概览...

植物遗传转化相关介绍【卡梅德生物】

植物的遗传转化是指以植物器官、组织、细胞或原生质体作为受体&#xff0c;应用重组DNA技术&#xff0c;将外源基因导入植物基因组&#xff0c;以获得转基因植物的技术。目前应用最普遍的植物基因的遗传转化方法主要有农杆菌介导法和DNA直接转入法。 一&#xff0e;植物遗传转化…...

0711springNews新闻系统管理 实现多级评论

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

如何在Ubuntu上安装并启动SSH服务(Windows连接)

在日常的开发和管理工作中&#xff0c;通过SSH&#xff08;Secure Shell&#xff09;连接到远程服务器是一个非常常见的需求。如果你在尝试通过SSH连接到你的Ubuntu系统时遇到了问题&#xff0c;可能是因为SSH服务未安装或未正确配置。本文将介绍如何在Ubuntu上安装并启动SSH服…...

docker build时的网络问题

docker build时无法yum安装包&#xff0c;因为无法访问外网&#xff0c;无法ping通外网。 解决办法&#xff1a; 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进行数据分析&#xff0c;包括Python在数据分析中的应用场景、常用库和工具&#xff0c;以及实际案例分析。 一、Python在数据分析中的应用场景 数据清洗&#xff1a;处理缺失值、异常值&a…...

Python学习笔记40:游戏篇之外星人入侵(一)

前言 入门知识已经学完&#xff0c;常用标准库也了解了,pygame入门知识也学了&#xff0c;那么开始尝试小游戏的开发。 当然这个小游戏属于比较简单的小游戏&#xff0c;复杂的游戏需要长时间的编写累计开发经验&#xff0c;同时也需要一定的时间才能编写出来。现在的话还是嫩…...

R的数据集读取和利用,如何高效地直接复制黏贴数据到R

​​​​​​R语言自带了许多内部数据集,这些数据集不仅为初学者提供了丰富的练习资源,还为研究人员和数据分析师提供了方便的数据测试和模型验证工具。在这篇文章中,我们将详细探讨如何读取和使用数据集。 一、认识数据集 1、数据和数据集 数据(Data)是指以某种形式表示…...

AI IDE 开发(公司只能用codeArts)

1&#xff0c;概述 AI现在这么火&#xff0c;我想着用AI开发一个后台管理系统试试。看看整个AI IDE开发的流程&#xff0c;文档检查&#xff0c;文档执行等。 背景&#xff1a;我是一个开发了5年经验的 web前端开发 程序员。不会后端&#xff0c;只了解基础的一些业务、数据库…...

利用MT5进行文案润色:输入原始文案,AI输出优化后的多种版本

利用MT5进行文案润色&#xff1a;输入原始文案&#xff0c;AI输出优化后的多种版本 1. 为什么需要文案自动润色工具 在日常工作中&#xff0c;我们经常遇到这样的场景&#xff1a; 写了一篇产品介绍&#xff0c;但总觉得表达方式单一&#xff0c;缺乏吸引力需要为同一内容生…...

SEER‘S EYE模型Dify平台集成指南:可视化AI应用搭建

SEERS EYE模型Dify平台集成指南&#xff1a;可视化AI应用搭建 你是不是觉得&#xff0c;把那些功能强大的AI模型用起来&#xff0c;总得写一堆代码&#xff0c;搞一堆复杂的配置&#xff0c;门槛太高了&#xff1f;特别是像SEERS EYE&#xff08;预言家之眼&#xff09;这样的…...

SolidWorks 2019 + Fusion 360:手把手教你搞定复杂机械臂模型的URDF导出(附开源模型)

SolidWorks与Fusion 360协同工作流&#xff1a;机械臂模型URDF导出实战指南 当你在GitHub上发现一个设计精良的六轴机械臂模型&#xff0c;却因为格式兼容性问题无法直接使用时&#xff0c;这种挫败感每个机器人开发者都深有体会。上周我就遇到了这样的情况——一个基于Gluon架…...

避坑指南:YOLOv8模型部署到小程序的5个常见错误及解决方案

YOLOv8模型部署到小程序的避坑实战手册 第一次把YOLOv8模型塞进小程序时&#xff0c;我盯着屏幕上那个"500 Internal Server Error"发呆了半小时。这已经是第三次部署失败了&#xff0c;Docker日志里那些红色错误信息像在嘲笑我的天真。后来才发现&#xff0c;原来只…...

OpenClaw学习助手:Phi-3-mini-128k-instruct自动生成技术问答集

OpenClaw学习助手&#xff1a;Phi-3-mini-128k-instruct自动生成技术问答集 1. 为什么需要自动化学习助手 作为一名技术文档的深度用户&#xff0c;我经常面临一个困境&#xff1a;阅读大量文档后&#xff0c;如何快速检验自己的理解是否正确&#xff1f;传统做法是手动整理问…...

mac下OpenClaw开发环境搭建:调试千问3.5-27B技能插件

mac下OpenClaw开发环境搭建&#xff1a;调试千问3.5-27B技能插件 1. 为什么需要本地开发环境 去年第一次接触OpenClaw时&#xff0c;我天真地以为所有技能开发都能在云端完成。直到尝试修改一个飞书会议纪要插件时&#xff0c;才发现每次测试都要经历"改代码→打包→上传…...

OpenClaw自动化写作:Qwen3.5-9B-AWQ-4bit实现图文内容生成

OpenClaw自动化写作&#xff1a;Qwen3.5-9B-AWQ-4bit实现图文内容生成 1. 为什么需要自动化图文创作 作为一个技术博主&#xff0c;我每周至少要产出3-4篇包含配图的技术文章。过去这个流程非常痛苦&#xff1a;先写完文章&#xff0c;再到Unsplash找配图&#xff0c;然后手动…...

OpenClaw硬件控制:Qwen3.5-9B通过串口操作物联网设备

OpenClaw硬件控制&#xff1a;Qwen3.5-9B通过串口操作物联网设备 1. 为什么选择OpenClaw控制物联网设备 去年我在搭建智能温室种植系统时&#xff0c;遇到了一个典型问题&#xff1a;市面上的物联网中台要么价格昂贵&#xff0c;要么灵活性不足。作为一个喜欢折腾的开发者&am…...

Mathcad Prime 7.0绘制Buck电路伯德图避坑指南(附完整公式设置)

Mathcad Prime 7.0绘制Buck电路伯德图避坑指南&#xff08;附完整公式设置&#xff09; 在电力电子设计领域&#xff0c;Buck电路的环路响应分析是确保电源稳定性的关键环节。Mathcad Prime 7.0作为工程计算利器&#xff0c;其伯德图绘制功能却暗藏多个"新手陷阱"——…...