首页
归档
朋友
关于我
留言
Search
1
虚拟机无法ping不通百度,并无法访问浏览器
4,847 阅读
2
mysql使用or条件使索引失效
4,061 阅读
3
mysql如何在一对多查询时选取时间最近的一条记录
3,475 阅读
4
根据MySQL获取当天,昨天,本周,本月,上周,上月,本月的起始时间
2,927 阅读
5
熟悉mysql的共享锁、排它锁、悲观锁、乐观锁以及使用场景
1,766 阅读
PHP
面向对象
设计模式
知识汇总
常用函数
PHP框架知识
数据库
MySQL
服务器
Docker
虚拟机
Nginx
缓存相关
Redis
前端
中间件
RabbitMQ
网络编程
HTTP相关
Swoole
Workerman
工具软件
Git
Typecho
杂乱无章
面试指南
PHP相关
MySQL面试汇总
中间件相关
开发技巧 | 优化
登录
Search
标签搜索
php
mysql
代码片段
linux
Thinkphp
Redis
nginx
mysql优化
docker
面试指南
面向对象
git
Laravel框架
http协议
RabbitMQ
Redis性能优化
设计模式
linux命令
编译安装
PhpSpreadsheet
黎明强
累计撰写
70
篇文章
累计收到
59
条评论
首页
栏目
PHP
面向对象
设计模式
知识汇总
常用函数
PHP框架知识
数据库
MySQL
服务器
Docker
虚拟机
Nginx
缓存相关
Redis
前端
中间件
RabbitMQ
网络编程
HTTP相关
Swoole
Workerman
工具软件
Git
Typecho
杂乱无章
面试指南
PHP相关
MySQL面试汇总
中间件相关
开发技巧 | 优化
页面
归档
朋友
关于我
留言
搜索到
7
篇与
PHP框架知识
的结果
2022-10-15
ThinkPHP5源码分析(1) : 类的自动加载
前文Composer 下载ThinkPHP5.1的源码,每个框架它都必须都有一个“类的自动加载”机制 ,我们都知道PHP引入文件是需要require 、 include 才能使用别的类文件中的方法。比如我需要写一个公共文件 model.phpinclude "model.php" include "model2.php" class User { //code.. }但是!如何当公共类库文件很多的时候,每次都需要手动引入,就显得非常麻烦,不利于/不方便维护管理。所以PHP引入了一个spl_autoload_register() 的类自动加载,TP框架就是借助了 spl_autoload_register() 来完成类的自动加载。TP5框架入口加载机制学习框架源码的第一步,先找到入口文件 public/index.php ,然后一步步跟进流程,看下代码执行的过程。第一行:定义命名空间就不赘述了。。第二行:去加载基础文件 base.php ,是位于上一层目录的 think目录下打开Base.php ,第16行就会去加载 Loader.php 文件 (就是TP5自动加载的类库) ,Loader.php 是TP5封装的底层基础类库。再引用了核心文件 Loader.php 调用类库的 Loader::register() 的方法发现都用了spl_autoload_register()的系统函数,其他框架也是同理。 都是会在框架的第一步“入门文件”就进行类的自动加载机制,针对底层进行封装。TP5中的Loader::register() 其实做了2件事:内部自定义一个autoload() 去进行框架的底层深度封装为了支持 Composer 自动加载 安装第三方的类库插件(Vendor),都是遵循PSR-4的风格统一,那么加载composer类的 autoload_static.php 后,再去加载对应的插件类库。分析Loader::register的执行流程如下截图:分析TP5执行 Loader::register() 的注册自动加载方法 ,( 是调用不存在的类的时候才会执行spl_autoload_register())运用3元运算符,如果有参数就执行其他自定义类,没就 加载本类的autoload() 方法调用 self::gerRootPath() 获取项目的根目录这里就是走 Composer的加载机制,然后组织一个Vendor的决定路径 ,self::$composerPath判断是否有Vendor的目录,再判断是否有auto_static的文件 ,有就加载composer目录下的auto_static.php分析Composer自动加载——类文件在逻辑往下走,判断是否有Vendor的目录,再判断是否有auto_static的文件 ,有就加载composer目录下的auto_static.phpauto_static.php发现定义了2个属性分别是: $prefixLengthsPsr4 、$prefixDirsPsr4 ,这是什么意思呢?定义数组,有个key和value,比如 $prefixLengthsPsr4 (PSR4的长度)t key代表一个命名空间 ,代表think\composer\ 命名空间 ,首字母代表类,把某些类放进去来,15 代表字符的长度。a key也是代表一个命名空间,代表:app ,用首字母代表,把某些类放进去, 4是这个字符的长度。2个斜线是转义字符,比如 think\\composer\\ 等同于 think\composer\$prefixDirsPsr4 把每个命名空间的类对应的目录列出来比如think\composer 这个命名空间 在src下app\\ 这个命名空间就在根目录的application比如通过 Compsoe r安装 swoole、workermam、phpexcel 就把相应的规则追加数组上 填进来。总结: composer的统一加载机制的地方,每次composer新类库的时候,都会往这个属性追加 命名空间 以及类库的目录路径 。分析Composer自动加载——属性赋值回到Loader::register()方法。// Composer自动加载支持 if (is_dir(self::$composerPath)) { if (is_file(self::$composerPath . 'autoload_static.php')) { require self::$composerPath . 'autoload_static.php'; $declaredClass = get_declared_classes(); $composerClass = array_pop($declaredClass); foreach (['prefixLengthsPsr4', 'prefixDirsPsr4', 'fallbackDirsPsr4', 'prefixesPsr0', 'fallbackDirsPsr0', 'classMap', 'files'] as $attr) { if (property_exists($composerClass, $attr)) { self::${$attr} = $composerClass::${$attr}; } } } else { self::registerComposerLoader(self::$composerPath); } } // 注册命名空间定义 self::addNamespace([ 'think' => __DIR__, 'traits' => dirname(__DIR__) . DIRECTORY_SEPARATOR . 'traits', ]);再返回 Loader::register() 方法接着放下分析:如果存在Vendor目录,再判断是否有 composer_static.php ,有就执行如下:执行了 get_declared_classes 这个系统函数,返回由当前脚本中已定义类的名字组成的数组。我们打印这个get_declared_classes得到目前所有加载的类,最后require加载的是 composer类。所以,我们上面的 array_pop 弹出最后一个元素,赋值后的 $composerClass ,就是composer的类。这个命令空间那么长的其实就是 composer目录下的autoload_static.php再继续往下执行property_exists : 检查对象或类是否具有该属性我们知道autoload_static.php 存在有prefixLengthsPsr4$prefixDirsPsr4$classMap等一众的方法,composer的 stacis.php这些属性以及值 ,再赋值作为Loader类的某个属性再处理。上面的写法等同 :self::prefixLengthsPsr4 self::prefixDirsPsr4打印这些属性返回:为什么这样去做?后续要集合多个属性再Map,加载文件的时候用这些属性。总结: 把composere下的auto_static的PSR4的属性以及值赋值到Loader的PSR4属性中分析Composer自动加载——注册命名空间会调用当前Loader::addNamespace() 方法 ,把当前think 跟traits 核心注册进行。// 注册命名空间定义 self::addNamespace([ 'think' => __DIR__, 'traits' => dirname(__DIR__) . DIRECTORY_SEPARATOR . 'traits', ]);进去 addNamespace() 方法,我们打印这个 $namespace 参数。// 注册命名空间 public static function addNamespace($namespace, $path = '') { echo "<pre>"; print_r($namespace);exit; if (is_array($namespace)) { foreach ($namespace as $prefix => $paths) { self::addPsr4($prefix . '\\', rtrim($paths, DIRECTORY_SEPARATOR), true); } } else { self::addPsr4($namespace . '\\', rtrim($path, DIRECTORY_SEPARATOR), true); } }再接下来,无论是不是数组,都再把命名空间拼接组装好,再调用self::addPsr4()查看 addPsr4() 方法注册的时候走的是“296” 行 。因为之前 self::$prefixDirsPsr4 里的属性只是composer的autp_static.php 上的,只有 think\ 跟 app\ ,并没有think 跟traits 这2个属性。public static $prefixDirsPsr4 = array ( 'think\\composer\\' => array ( 0 => __DIR__ . '/..' . '/topthink/think-installer/src', ), 'app\\' => array ( 0 => __DIR__ . '/../..' . '/application', ), );这样就完成 think、traits下的命名空间注册到Loader类的PSR4属性中。加载类库映射文件再往下执行我们在根目录的runtime 并没有classmap.php的文件 ,我们可以通过命令生成这个文件php think optimize:autoload这时候runtime下就有classmap.php ,就是存放一些命名空间映射的文件<?php /** * 类库映射 */ return [ 'app\\index\\controller\\Index' => '/Users/limingqiang/project_php/localhost_pro/tp51_source_code/application/' . 'index/controller/Index.php', 'think\\App' => '/Users/limingqiang/project_php/localhost_pro/tp51_source_code/thinkphp/library/' . '/think/App.php', 'think\\Build' => '/Users/limingqiang/project_php/localhost_pro/tp51_source_code/thinkphp/library/' . '/think/Build.php', 'think\\Cache' => '/Users/limingqiang/project_php/localhost_pro/tp51_source_code/thinkphp/library/' . '/think/Cache.php', 'think\\Collection' => '/Users/limingqiang/project_php/localhost_pro/tp51_source_code/thinkphp/library/' . '/think/Collection.php', 'think\\Config' => '/Users/limingqiang/project_php/localhost_pro/tp51_source_code/thinkphp/library/' . '/think/Config.php', 'think\\Console' => '/Users/limingqiang/project_php/localhost_pro/tp51_source_code/thinkphp/library/' . '/think/Console.php', 'think\\Container' => '/Users/limingqiang/project_php/localhost_pro/tp51_source_code/thinkphp/library/' . '/think/Container.php', //code..... ]进入这个 self::addClassMap() 方法,看到把当前classmap.php的数组内容赋值到一个 Loader类的$classMap 属性中。总结: 把tp5的核心的 think 和 traits 命名空间注册到PSR4里,方便后续调用,实在属性多个数组统一自动加载。自动加载extend目录再往下执行进去 self::addAutoLoadDir() 方法: // 注册自动加载类库目录 public static function addAutoLoadDir($path) { self::$fallbackDirsPsr4[] = $path; }把当前extend的目录也加载到 Loader类 $fallbackDirsPsr4 的属性中。总结prefixDirsPsr4 (对应类的目录)prefixLengthsPsr4 (对应类的命名长度)fallbackDirsPsr4 (对应extend的目录)我们拿到很多变量成员、命令空间、目录路径等都赋值到 Loader类的多个PSR4的属性中。后续再拿这些属性做自动加载配置。
2022年10月15日
209 阅读
1 评论
0 点赞
2021-07-17
一文带你熟悉TP5.1的模型各种操作
前文带你熟悉TP5.1中的模型获取器、修改器、模型搜索器、模型数据集、模型自动时间戳、模型只读字段、模型转换器、模型范围搜索等..01. 模型获取器和修改器本节课我们来学习模型中操作比较方便的获取器和修改器。一. 模型获取器获取器的作用是对模型实例的数据做出自动处理;一个获取器对应模型的一个特殊方法,该方法为 public;方法名的命名规范为:getFieldAttr() ;举个例子,数据库表示状态 status 字段采用的是数值;而页面上,我们需要输出 status 字段希望是中文,就可以使用获取器;在 User 模型端,我创建一个对外的方法,如下:public function getStatusAttr($value) { $status = [-1=>'删除', 0=>'禁用', 1=>'正常', 2=>'待审核']; return $status[$value]; }然后,在控制器端,直接输出数据库字段的值即可得到获取器转换的对应值$user = UserModel::get(21); return $user->status;除了 getFieldAttr 中 Field 可以是字段值,也可以是自定义的虚拟字段;public function getNothingAttr($value, $data) { $myGet = [-1=>'删除', 0=>'禁用', 1=>'正常', 2=>'待审核']; return $myGet[$data['status']]; } return $user->nothing;Nothing 这个字段不存在,而此时参数$value 只是为了占位,并未使用;第二个参数$data 得到的是筛选到的数据,然后得到最终值;如果你定义了获取器,并且想获取原始值,可以使用 getData() 方法;return $user->getData('status');直接输出无参数的 getData(),可以得到原始值,而$user 输出是改变后的;dump($user->getData()); //获取原始值 dump($user); //获取改变后的值使用 WithAttr 在控制器端实现动态获取器,比如设置所有 email 为大写;$result = UserModel::WithAttr('email', function ($value) { return strtoupper($value); })->select(); return json($result);使用 WithAttr 在控制器端实现动态获取器,比如设置 status 翻译为中文;result = UserModel::WithAttr('status', function ($value) { $status = [-1=>'删除', 0=>'禁用', 1=>'正常', 2=>'待审核']; return $status[$value]; })->select(); return json($result);. 同时定义了模型获取器和动态获取器,那么模型修改器优先级更高二. 模型修改器模型修改器的作用,就是对模型设置对象的值进行处理;比如,我们要新增数据的时候,对数据就行格式化、过滤、转换等处理;模型修改器的命名规则为:setFieldAttr ;我们要设置一个新增,规定邮箱的英文都必须大写,修改器如下:public function setEmailAttr($value) { return strtoupper($value); }除了新增,会调用修改器,修改更新也会触发修改器;模型修改器只对模型方法有效,调用数据库的方法是无效的,比如->insert();02. 模型搜索器和数据集本节课我们来学习模型中的用于封装的搜索器和数据结果集的操作。一. 模型搜索器搜索器是用于封装字段(或搜索标识)的查询表达式;一个搜索器对应模型的一个特殊方法,该方法为 public;方法名的命名规范为:searchFieldNameAttr();举个例子,我们要封装一个邮箱字符模糊查询,然后封装一个时间限定查询;在 User 模型端,我创建两个对外的方法,如下://邮箱查询 public function searchEmailAttr($query, $value) { $query->where('email', 'like', $value.'%'); } //时间查询 public function searchCreateTimeAttr($query, $value) { $query->whereBetweenTime('create_time', $value[0], $value[1]); }然后,在控制器端,通过 withSearch() 静态方法实现模型搜索器的调用**;$result = UserModel::withSearch(['email', 'create_time'],[ 'email' => 'xiao', 'create_time' => ['2014-1-1', '2017-1-1'] ])->select();withSearch() 中第一个数组参数,限定搜索器的字段,第二个则是表达式值;如果想在搜索器查询的基础上再增加查询条件,直接使用链式查询即可;UserModel::withSearch(...)->where('gender', '女')->select()如果你想在搜索器添加一个可以排序的功能,具体如下://model层 public function searchEmailAttr($query, $value, $data) { $query->where('email', 'like', $value.'%'); if (isset($data['sort'])) { $query->order($data['sort']); } } //controller调用 $result = UserModel::withSearch(['email', 'create_time'],[ 'email' => 'xiao', 'create_time' => ['2014-1-1', '2017-1-1'], 'sort' => ['price'=>'desc'] ])->select();搜索器的第三个参数$data,可以得到 withSearch()方法第二参数的值;字段也可以设置别名:'create_time'=>'ctime'一. 模型数据集数据集由 all() 和 select() 方法返回数据集对象;数据集对象和数组操作方法一样,循环遍历、删除元素等;判断数据集是否为空,我们需要采用 isEmpty() 方法$resut = UserModel::where('id', 111)->select(); if ($resut->isEmpty()) { return '没有数据!'; }使用模型方法 hidden() 可以隐藏某个字段,使用 visible() 显示只某个字段使用 append() 可以添加某个获取器字段,使用 withAttr() 对字段进行函数处理;$result = UserModel::select(); $result->hidden(['password'])->append(['nothing'])->withAttr('email', function ($value) { return strtoupper($value); }); return json($result);使用模型方法 filter() 对筛选的数据进行过滤;$result = UserModel::select()->filter(function ($data) { return $data['price'] > 100; }); return json($result);也可以使用数据集之后链接 where()方法来代替 filter()方法;$result = UserModel::select()->where('price', '>', '100');数据集甚至还可以使用 order() 方法进行排序;$result = UserModel::select()->order('price', 'desc');使用 diff() 和 intersect()方法可以计算两个数据集的差集和交集;$result1 = UserModel::where('price', '>', '80')->select(); $result2 = UserModel::where('price', '<', '100')->select(); return json($result1->diff($result2)); return json($result2->intersect($result1)); 03. 模型自动时间戳和只读字段本节课我们来学习模型中用于记录时间的自动时间戳和不可更改只读字段。一. 模型自动时间戳系统自动创建和更新时间戳功能默认是关闭状态;如果你想全局开启,在 database.php 中,设置为 true;// 自动写入时间戳字段 'auto_timestamp' => true,如果你只想设置某一个模型开启,需要设置特有字段;class User extends Model { //开启自动时间戳 protected $autoWriteTimestamp = true; }当然,还有一种方法,就是全局开启,单独关闭某个或某几个模型为 false;自动时间戳开启后,会自动写入 create_time 和 update_time 两个字段;此时,它们的默认的类型是 int,如果是时间类型,可以更改如下:'auto_timestamp' => 'datetime', //或 protected $autoWriteTimestamp = 'datetime';都配置完毕后,当我们新增一条数据时,无须新增 create_time 会自动写入时间;同理,当我们修改一条数据时,无须修改 update_time 会自动更新时间;自动时间戳只能在模型下有效,数据库方法不可以使用;如果创建和修改时间戳不是默认定义的,也可以自定义;protected $createTime = 'create_at'; protected $updateTime = 'update_at';如果业务中只需要 create_time 而不需要 update_time,可以关闭它;protected $updateTime = false;也可以动态实现不修改 update_time,具体如下:$user->isAutoWriteTimestamp(false)->save();二. 模型只读字段模型中可以设置只读字段,就是无法被修改的字段设置;我们要设置 username 和 email 不允许被修改,如下:protected $readonly = ['username', 'email'];除了在模型端设置,也可以动态设置只读字段;$user->readonly(['username', 'email'])->save();同样,只读字段只支持模型方式不支持数据库方式;04. 模型类型转换和数据完成本节课我们来学习模型中字段的类型转换和数据操作的自动完成。一. 模型类型转换系统可以通过模型端设置写入或读取时对字段类型进行转换;我们这里,通过读取的方式来演示部分效果;在模型端设置你想要类型转换的字段属性,属性值为数组;protected $type = [ 'price' => 'integer', 'status' => 'boolean', 'create_time' => 'datetime:Y-m-d' ];数据库查询读取的字段很多都是字符串类型,我们可以转换成如下类型:integer(整型)、float(浮点型)、boolean(布尔型)、array(数组) object(对象)、se由于数据库没有那么多类型演示,常用度不显著,我们提供几个方便演示的;public function typeConversion() { $user = UserModel::get(21); var_dump($user->price); var_dump($user->status); var_dump($user->create_time); }需要注意的是: 类型转换还是会调用属性里的获取器等操作,编码时要注意这方面的问题;三. 模型数据完成模型中数据完成通过 auto、insert 和 update 三种形式完成;auto 表示新增和修改操作,insert 只表示新增,update 只表示修改;protected $auto = ['email']; protected $insert = ['uid'=>1]; protected $update = [];先理解insert,当我们新增一条数据时会触发新增数据完成;此时,并不需要自己去新增 uid,它会自动给 uid 赋值为 1;$user = new UserModel(); $user->username = '李白'; $user->password = '123'; $user->gender = '男'; $user->email = 'libai@163.com'; $user->price = 100; $user->details = '123'; $user->save();auto 表示新增和修改均要自动完成,而不给默认值的字段需要修改器提供;public function setEmailAttr($value) { return strtoupper($value); }新增时,邮箱字符串会被修改器自动完成大写,那数据完成的意义何在?修改时,如果你不去修改邮箱,在数据自动完成强制完成,会自动完成大写;也就是说,邮箱的大写,设置 update 更加合适,因为新增必填必然触发修改器;对于 update 自动完成,和 auto、insert 雷同,自行演示;05. 模型查询范围和输出本节课我们来学习模型中封装查询范围的方法以及模型对外输出的方式。一. 模型查询范围在模型端创建一个封装的查询或写入方法,方便控制器端等调用**;比如,封装一个筛选所有性别为男的查询,并且只显示部分字段 5 条;方法名规范:前缀 scope,后缀随意,调用时直接把后缀作为参数使用;public function scopeGenderMale($query) { $query->where('gender', '男')->field('id,username,gender,email')->limit(5); }在控制器端,我们我们直接调用并输出结果即可;public function queryScope() { $result = UserModel::scope('gendermale')->select(); //$result = UserModel::gendermale()->select(); return json($result); }也可以实现多个查询封装方法连缀调用,比如找出邮箱 xiao 并大于 80 分的;public function scopeEmailLike($query, $value) { $query->where('email', 'like', '%'.$value.'%'); } public function scopePriceGreater($query, $value) { $query->where('price', '>', 80); } //调用 $result = UserModel::emailLike('xiao')->priceGreater(80)->select();查询范围只能使用 find() 和 select()两种方法;全局范围查询,就是在此模型下不管怎么查询都会加上全局条件;//全局范围查询 protected function base($query) { $query->where('status', 1); }在定义了全局查询后,如果某些不需要全局查询可以使用 useGlobalScope 取消;UserModel::useGlobalScope(false)当然,设置为 true,则开启全局范围查询,注意:这个方法需要跟在::后面;UserModel::useGlobalScope(true)二. 模型输出方式通过模版进行数据输出;public function view() { $user = UserModel::get(21); $this->assign('user', $user); return $this->fetch(); }根据错误提示,可以创建相对应的模版,然后进行数据显示;{$user.username}. {$user.gender}. {$user.email}使用 toArray()方法,将对象按照数组的方式输出;$user = UserModel::get(21); print_r($user->toArray());和之前的数据集一样,它也支持 hidden、append、visible 等方法;print_r($user->hidden(['password,update_time'])->toArray());toArray() 方法也支持 all()和 select()等列表数据;print_r(UserModel::select()->toArray());使用 toJson() 方法将数据对象进行序列化操作,也支持 hidden 等方法;print_r($user->toJson());
2021年07月17日
1,085 阅读
1 评论
0 点赞
2021-07-17
ThinkPHP5.1中各种表达式查询
01. 查询表达式本节课我们要学习查询中的几种查询方式:比较查询、区间查询、其它查询等。一. 比较查询在查询数据进行筛选时,我们采用 where() 方法,比如 id=80;Db::name('user')->where('id', 80)->find(); //where(字段名,查询条件) Db::name('user')->where('id','=',80)->find(); //where(字段名,表达式,查询条件)其中,表达式不区分大小写,包括了比较、区间和时间三种类型的查询;使用<>、>、<、>=、<= 可以筛选出各种符合比较值的数据列表;Db::name('user')->where('id','<>',80)->select();二. 区间查询使用like 表达式进行模糊查询;Db::name('user')->where('email','like','xiao%')->select();like 表达式还可以支持数组传递进行模糊查询;Db::name('user')->where('email','like',['xiao%','wu%'], 'or')->select(); //SELECT * FROM `tp_user` WHERE (`email` LIKE 'xiao%' OR `email` LIKE 'wu%')like 表达式具有两个快捷方式 whereLike() 和 whereNoLike();Db::name('user')->whereLike('email','xiao%')->select(); Db::name('user')->whereNotLike('email','xiao%')->select();between 表达式具有两个快捷方式 whereBetween() 和 whereNotBetween() ;Db::name('user')->where('id','between','19,25')->select(); Db::name('user')->where('id','between',[19, 25])->select(); Db::name('user')->whereBetween('id',[19, 25])->select(); Db::name('user')->whereNotBetween('id',[19, 25])->select();in 表达式具有两个快捷方式 whereIn()和 whereNotIn();Db::name('user')->where('id','in', '19,21,29')->select(); Db::name('user')->whereIn('id','19,21,29')->select(); Db::name('user')->whereNotIn('id','19,21,29')->select();null 表达式具有两个快捷方式 whereNull()和 whereNotNull() ;Db::name('user')->where('uid','null')->select(); Db::name('user')->where('uid','not null')->select(); Db::name('user')->whereNull('uid')->select(); Db::name('user')->whereNotNull('uid')->select();三. 其他查询使用 exp 可以自定义字段后的 SQL 语句;Db::name('user')->where('id','exp','IN (19,21,25)')->select(); Db::name('user')->whereExp('id','IN (19,21,25)')->select();02. 时间查询本节课我们要单独学习一下时间的所有查询方式,包括传统式、快捷方式和固定查询等。一. 传统方式可以使用>、<、>=、<= 来筛选匹配时间的数据Db::name('user')->where('create_time', '> time', '2018-1-1')->select();可以使用 between 关键字来设置时间的区间;Db::name('user')->where('create_time', 'between time', ['2018-1-1','2019-12-31'])->select(); Db::name('user')->where('create_time', 'not between time', ['2018-1-1','2019-12-31'])->select();二. 快捷方式时间查询的快捷方法为 whereTime() ,直接使用>、<、>=、<=;Db::name('user')->whereTime('create_time', '>', '2018-1-1')->select();快捷方式也可以使用 between 和 not between;Db::name('user')->whereBetween('create_time', ['2018-1-1','2019-12-31'])->select();还有一种快捷方式为:whereBetweenTime() ,如果只有一个参数就表示一天;Db::name('user')->whereBetweenTime('create_time', '2018-1-1','2019-12-31')->select(). 默认的大于>,可以省略;Db::name('user')->whereTime('create_time', '2018-1-1')->select();三. 固定查询关键词说明today 或 d今天yesterday昨天week 或者 w本周last week上周month 或者 m本月last month 或者m上月year 或者 y今年last year去年Db::name('user')->whereTime('create_time','d')->select(); Db::name('user')->whereTime('create_time','y')->select();四. 其他查询查询指定时间的数据,比如两小时内的;Db::name('user')->whereTime('create_time', '-2 hour')->select();查询两个时间字段时间有效期的数据,比如会员开始到结束的期间;Db::name('user')->whereBetweenTimeField('start_time','end_time')->select();03. 聚合、原生和子查询本节课我们来学习三种查询方式:包括聚合查询、子查询和原生查询。一. 聚合查询使用 count() 方法,可以求出所查询数据的数量;Db::name('user')->count();count() 可设置指定 id,比如有空值(Null)的 uid,不会计算数量;Db::name('user')->count('uid');使用 max() 方法,求出所查询数据字段的最大值;Db::name('user')->max('price');如果 max() 方法,求出的值不是数值,则通过第二参数强制转换;Db::name('user')->max('price', false);使用 min() 方法,求出所查询数据字段的最小值,也可以强制转换;Db::name('user')->min('price');使用 avg() 方法,求出所查询数据字段的平均值Db::name('user')->avg('price');使用 sum() 方法,求出所查询数据字段的总和Db::name('user')->sum('price');二. 子查询使用 fetchSql() 方法,可以设置不执行 SQL,而返回 SQLDb::name('user')->fetchSql(true)->select();使用 buidSql() 方法,也是返回 SQL 语句,但不需要再执行 select(),且有括号;Db::name('user')->buildSql(true);结合以上方法,我们实现一个子查询;#one过滤找出所有男性的信息 $subQuery = Db::name('two')->field('uid')->where('gender','男')->buildSql(true); $result = Db::name('one')->where('id','exp','IN '.$subQuery)->select();使用闭包的方式执行子查询;$result = Db::name('one')->where('id', 'in', function ($query) { $query->name('two')->where('gender', '男')->field('uid'); })->select();三. 原生查询使用 query() 方法,进行原生 SQL 查询,适用于读取操作,SQL 错误返回 false;Db::query('select * from tp_user');使用 execute 方法,进行原生 SQL 更新写入等,SQL 错误返回 false;Db::execute('update tp_user set username="孙悟空" where id=29');
2021年07月17日
762 阅读
1 评论
0 点赞
2021-07-17
ThinkPHP5.1的模型中常用的CURD操作
01 模型定义本节课我们来学习模型篇章中的定义方法,设置以及一些基本的操作。一. 定义模型定义一个和数据库表向匹配的模型;class User extends Model模型会自动对应数据表,并且有一套自己的命名规则模型类需要去除表前缀(tp_),采用驼峰式命名,并且首字母大写tp_user(表名) => User tp_user_type(表名) => UserType如果担心设置的模型类名和 PHP 关键字冲突,可以开启应用类后缀;在 app.php 中,设置class_suffix 属性为 true 即可;// 应用类库后缀 'class_suffix' => true,设置完毕后,所有的控制器类名和模型类名需要加上 Controller 和 Model;class UserModel二. 设置模型默认主键为 id,你可以设置其它主键,比如 uid;protected $pk = 'uid';从控制器端调用模型操作,如果和控制器类名重复,可以设置别名use app\model\User as UserModel;在模型定义中,可以设置其它的数据表;protected $table = 'tp_one';模型和控制器一样,也有初始化,在这里必须设置 static 静态方法;//模型初始化 protected static function init() { //第一次实例化的时候执行 init echo '初始化 User 模型'; }三. 模型操作模型操作数据和数据库操作一样,只不过不需要指定表了;UserModel::select();数据库操作返回的列表是一个二维数组,而模型操作返回的是一个结果集;[[]] 和 [{}]02. 模型中的增删改查本节课我们来学习模型中的修改和查询、删除、添加操作。一. 数据添加使用实例化的方式添加一条数据,首先实例化方式如下,两种均可:$user = new UserModel(); $user = new \app\model\User();设置要新增的数据,然后用 save() 方法写入到数据库中,save()返回布尔值$user->username = '李白'; $user->password = '123'; $user->gender = '男'; $user->email = 'libai@163.com'; $user->price = 100; $user->details = '123'; $user->uid = 1011; $user->create_time = date('Y-m-d H:i:s'); $user->save();也可以通过 save() 传递数据数组的方式,来新增数据;$user = new UserModel(); $user->save([ 'username' => '李白', 'password' => '123', 'gender' => '男', 'email' => 'libai@163.com', 'price' => 100, 'details' => '123', 'uid' => 1011, 'create_time' => date('Y-m-d H:i:s') ]);模型新增也提供了 replace() 方法来实现 REPLACE into 新增;$user->replace()->save();当新增成功后,使用$user->id ,可以获得自增 ID(主键需是 id);echo $user->id;使用 saveAll() 方法,可以批量新增数据,返回批量新增的数组;$dataAll = [ [ 'username' => '李白 1', 'password' => '123', 'gender' => '男', 'email' => 'libai@163.com', 'price' => 100, 'details' => '123', 'uid' => 1011, 'create_time' => date('Y-m-d H:i:s') ], [ 'username' => '李白 2', 'password' => '123', 'gender' => '男', 'email' => 'libai@163.com', 'price' => 100, 'details' => '123', 'uid' => 1011, 'create_time' => date('Y-m-d H:i:s') ] ]; $user = new UserModel(); print_r($user->saveAll($dataAll));二. 数据删除使用 get() 方法,通过主键(id)查询到想要删除的数据$user = UserModel::get(93);然后再通过 delete() 方法,将数据删除,返回布尔值;$user->delete();也可以使用静态方法调用 destroy() 方法,通过主键(id)删除数据;UserModel::destroy(92)静态方法 destroy()方法,也可以批量删除数据UserModel::destroy('80, 90, 91'); UserModel::destroy([80, 90, 91]);通过数据库类的查询条件删除;UserModel::where('id', '>', 80)->delete();使用闭包的方式进行删除;UserModel::destroy(function ($query) { $query->where('id', '>', 80); });三. 数据修改使用 get() 方法通过主键获取数据,然后通过 save()方法保存修改,返回布尔值;$user = UserModel::get(118); $user->username = '李黑'; $user->email = 'lihei@163.com'; $user->save();通过 where() 方法结合 find() 方法的查询条件获取的数据,进行修改;$user = UserModel::where('username', '李黑')->find(); $user->username = '李白'; $user->email = 'libai@163.com'; $user->save();save()方法只会更新变化的数据,如果提交的修改数据没有变化,则不更新;但如果你想强制更新数据,即使数据一样,那么可以使用 force() 方法;$user->force()->save();Db::raw() 执行SQL 函数的方式,同样在这里有效;$user->price = Db::raw('price+1');如果只是单纯的增减数据修改,可以使用 inc/dec;$user->price = ['inc', 1];直接通过 save([],[]) 两个数组参数的方式更新数据;$user->save([ 'username' => '李黑', 'email' => 'lihei@163.com' ],['id'=>118]);通过saveAll() 方法,可以批量修改数据,返回被修改的数据集合;$list = [ ['id'=>118, 'username'=>'李白', 'email'=>'libai@163.com'], ['id'=>128, 'username'=>'李白', 'email'=>'libai@163.com'], ['id'=>129, 'username'=>'李白', 'email'=>'libai@163.com'] ]; $user->saveAll($list);批量更新 saveAll() 只能通过主键 id 进行更新使用静态方法结合 update() 方法来更新数据,这里返回的是影响行数UserModel::where('id', 118)->update([ 'username' => '李黑', 'email' => 'lihei@163.com' ]);另外一种静态方法 update(),返回的是对象实例;UserModel::update([ 'id' => 118, 'username' => '李黑', 'email' => 'lihei@163.com' ]);模型的新增和修改都是 save()进行执行的 ,它采用了自动识别体系来完成;实例化模型后调用 save()方法表示新增 ,查询数据后调用 save()表示修改;当然,如果在 save() 传入更新修改条件后也表示修改;再当然,如果编写的代码比较复杂的话,可以用 isUpdate() 方法显示操作;//显示更新 $user->isUpdate(true)->save(); //显示新增 $user->isUpdate(false)->save();四. 数据查询使用 get() 方法,通过主键(id)查询到想要的数据;$user = UserModel::get(129); return json($user);也可以使用 ·where()· 方法进行条件筛选查询数据$user = UserModel::where('username', '辉夜')->find(); return json($user);不管是get() 方法还是 find() 方法,如果数据不存在则返回 Null;和数据库查询一样,模型也有 getOrFail() 方法,数据不存在抛出异常;同上,还有 findOrEmpty() 方法,数据不存在返回空模型;通过模型->符号,可以得到单独的字段数据;return $user->username;如果在模型内部获取数据,请不要用$this->username,而用如下方法;public function getUserName() { return self::where('username', '辉夜')->find()->getAttr('username'); }通过 all() 方法,实现 IN 模式的多数据获取;$user = UserModel::all('79, 118, 128'); $user = UserModel::all([79, 118, 128]);使用链式查询得到想要的数据;UserModel::where('gender', '男')->order('id', 'asc')->limit(2)->select();获取某个字段或者某个列的值;UserModel::where('id', 79)->value('username'); //某个字段 UserModel::whereIn('id',[79,118,128])->column('username','id'); //某个列的值模型支持动态查询:getBy *,* 表示字段名UserModel::getByUsername('辉夜'); UserModel::getByEmail('huiye@163.com');模型支持聚合查询;UserModel::max('price');
2021年07月17日
701 阅读
2 评论
1 点赞
2021-07-17
ThinkPHP5.1的常用增删改查操作
增删改查的操作学习一下数据库 Db 类的查询语句,包含 table、name 以及助手函数 db。学习来源于李炎恢TP5讲义一. 新增数据使用 insert() 方法可以向数据表添加一条数据;$data = [ 'username' => '辉夜', 'password' => '123', 'gender' => '女', 'email' => 'huiye@163.com', 'price' => 90, 'details' => '123', 'create_time' => date('Y-m-d H:i:s') ]; Db::name('user')->insert($data);如果新增成功,insert() 方法会返回一个 1 值$flag = Db::name('user')->insert($data); if ($flag) return '新增成功!';你可以使用 data() 方法来设置添加的数据数组;Db::name('user')->data($data)->insert();如果你添加一个不存在的数据,会抛出一个异常 Exception;如果采用的是 mysql 数据库,支持 REPLACE 写入 ;Db::name('user')->insert($data, true);使用 insertGetId() 方法,可以在新增成功后返回当前数据 ID;Db::name('user')->insertGetId($data);使用 insertAll() 方法,可以批量新增数据,但要保持数组结构一致$data = [ [ 'username' => '辉夜 1', 'password' => '123', 'gender' => '女', 'email' => 'huiye@163.com', 'price' => 90, 'details' => 123, 'create_time' => date('Y-m-d H:i:s') ], [ 'username' => '辉夜 2', 'password' => '123', 'gender' => '女', 'email' => 'huiye@163.com', 'price' => 90, 'details' => 123, 'create_time' => date('Y-m-d H:i:s') ], ]; Db::name('user')->insertAll($data);批量新增也支持 data()方法,和单独新增类似;Db::name('user')->data($data)->insertAll()批量新增也支持 reaplce 写入,和单独新增类似;Db::name('user')->insertAll($data, true);二. 修改数据使用 update() 方法来修改数据,修改成功返回影响行数,没有修改返回0$data = [ 'username' => '李白' ]; $update = Db::name('user')->where('id', 38)->update($data); return $update;或者使用 data() 方法传入要修改的数组,如果两边都传入会合并;Db::name('user')->where('id', 38)->data($data)->update(['password'=>'456']);如果修改数组中包含主键,那么可以直接修改;(不需要写where()链式 )$data = [ 'username' => '李白', 'id' => 38 ]; Db::name('user')->update($data);使用 inc() 方法可以对字段增值, dec() 方法可以对字段减值;Db::name('user')->inc('price',3)->update($data); //price+3块, Db::name('user')->dec('price', 3)->update($data); //price减3块增值和减值如果同时对一个字段操作,前面一个会失效;Db::name('user')->inc('price')->dec('price', 3)->update($data); //只把price减3使用 exp() 方法可以在字段中使用 mysql 函数;Db::name('user')->exp('email', 'UPPER(email)')->update($data); //邮箱转大写使用 raw() 方法修改更新,更加容易方便$data = [ 'username' => '李白', 'email' => Db::raw('UPPER(email)'), 'price' => Db::raw('price - 3'), 'id' => 38 ]; Db::name('user')->update($data);使用 setField() 方法可以更新一个字段值;Db::name('user')->where('id', 38)->setField('username', '辉夜');增值 setInc() 和减值 setDec() 也有简单的做法,方便更新一个字段值Db::name('user')->where('id', 38)->setInc('price');增值和减值如果不指定第二个参数,则步长默认为 1;三. 删除数据极简删除delete() 可以根据主键直接删除,删除成功返回影响行数,否则 0;Db::name('user')->delete(51);根据主键,还可以删除多条记录;Db::name('user')->delete([48,49,50]);正常情况下,通过 where() 方法来删除;Db::name('user')->where('id', 47)->delete();通过 true 参数删除数据表所有数据,我还没测试,大家自行测试下;Db::name('user')->delete(true);四. 查询数据Db::table() 中 table 必须指定完整数据表(包括前缀);如果希望只查询一条数据,可以使用 find()方法;Db::table('tp_user')->find();Db::getLastSql() 方法,可以得到最近一条 SQL 查询的原生语句;SELECT * FROM `tp_user` LIMIT 1想指定数据查询,可以使用 where() 方法; 没有查询到任何值,则返回 null;Db::table('tp_user')->where('id', 27)->find() //SELECT * FROM `tp_user` WHERE `id` = 27 LIMIT 1使用 findOrFail() 方法同样可以查询一条数据,在没有数据时抛出一个异常;Db::table('tp_user')->where('id', 1)->findOrFail()使用 findOrEmpty() 方法也可以查询一条数据,但在没有数据时返回一个空数组;Db::table('tp_user')->where('id', 1)->findOrEmpty();想要获取多列数据,可以使用 select() 方法;Db::table('tp_user')->select(); //SELECT * FROM `tp_user`多列数据在查询不到任何数据时返回空数组,使用 selectOrFail() 抛出异常;Db::table('tp_user')->where('id', 1)->selectOrFail();当在数据库配置文件中设置了前缀,那么我们可以使用 name() 方法忽略前缀;Db::name('user')->selectOrFail();五. 更多方法ThinkPHP 提供了一个助手函数 db,可以更方便的查询;\db('user')->select();通过 value() 方法,可以查询指定字段的值(单个),没有数据返回 null;Db::name('user')->where('id', 27)->value('username');通过 colunm() 方法,可以查询指定列的值(多个),没有数据返回空数组;Db::name('user')->column('username'); //返回多行数据colunm() 方法 ,可以指定 id 作为列值的索引;Db::name('user')->column('username', 'id'); // array( array(1=>'小明') , array(2=>'小强'))数据分批处理、大批数据处理和 JSON 数据查询,当遇到具体问题再探讨;
2021年07月17日
378 阅读
0 评论
0 点赞
2021-06-22
Laravel中的模型(Eloquent ORM)的使用
1. 模型的定义一. 默认设置框架可以使用 Eloquent ORM 进行数据库交互,也就是关系对象模型;在数据库入门阶段,我们已经创建了一个 User.php 模型,如下:php artisan make:model Http/Models/User //默认在 app 目录而调用的时候,我们也知道表名要遵循它默认规则,修改为复数,或 特定;class User extends Model { protected $table = 'user'; }系统假定你的主键为 id,如果你要修改默认主键,可以特定;class User extends Model { protected $primaryKey = 'xid'; //主键 } 系统假定你的主键 id 为自增性,意味着是主键会自动转换 int 类型;如果你希望不是非自增,非数值类型主键,可以设置 $incrementing 取消;public $incrementing = false; //非数字整型主键如果你主键不是一个整数,那么需要$keyType 设置为 string;protected $keyType = 'string'系统默认情况下会接管 created_at 和 updated_at 两个时间戳列;如果不想让系统干涉这两个列,可以设置 false 取消;public $timestamps = false; //取消写入时间戳如果你想自定义时间戳的格式,可以设置;protected $dateFormat = 'U';可以更改创建时间 created_at 和更新时间 updated_at 字段名;const CREATED_AT = 'create_time'; const UPDATED_AT = 'update_time';默认读取 database.php 配置的数据库连接,也可以在模型端局部更改protected $connection = 'mysql';二. 模型定义之前在查询构造器部分,把常用的数据库操作基本讲完,模型大体相同;比如,我们要查询所有数据,直接使用模型::all()即可;//查询所有记录 $users = User::get(); //或 all() return [$users];也可以像查询构造器一样,添加各种各样的条件,写法一样;//查询性别为男,价格大于 90,限制显示 2 条 $users = User::where([ ['gender', '=', '男'], ['price', '>', 95] ])->limit(2)->get();虽然安装了插件,但模型还是没有代码提示,可以通过安装插件解决;composer require barryvdh/laravel-ide-helper php artisan ide-helper:generate // – 为 Facades 生成注释 php artisan ide-helper:models //– 为数据模型生成注释 php artisan ide-helper:meta //– 生成 PhpStorm Meta file其它查询方法基本和查询构造器一样,如果有不一样,参考错误提示;这里列出官网给出示例的方法,对照实验(结合详细文档,重复较多);关于更多 Eloquent ORM 操作, 看手册 ( https://learnku.com/docs/laravel/8.x/eloquent/9406 )(1) .find(1) //通过主键查找 (2) .first() //查找第一个 (3) .firstWhere() //找到查询中的首个 (4) .find([1,2,3]) //通过数组查找 (5) .firstOr() //查找首个返回,支持闭包 (6) .firstOrFail() //找不到时返回异常 (7) .count()、max()等集合 //集合操作 //PS:还有很多在查询构造器中的方法,比如排序、分组子查询等等都可以使用(并未一一验证)。 2. 模型的增删改一. 增操作新增方法如下,注意:默认模型接管 created_at 和 updated_at;$users = new User(); $users->username = '辉夜'; $users->password = '123'; $users->email = 'huiye@163.com'; $users->details = '123'; $users->save();使用 create() 方法实现新增,但需要在模型端设置批量赋值的许可;User::create([ 'username' => '辉夜', 'password' => '123', 'email' => 'huiye@163.com', 'details' => '123', ]); //许可批量赋值,默认不可 protected $fillable = [ 'username', 'password', 'email', 'details' ]; //不许可的批量赋值,不可和$fillable 同时使用 //protected $guarded = ['uid']; //如果取消批量赋值限制,直接如下 protected $guarded = []; //PS:必须在模型中定义批量赋值的可填充字段,否则无法生效;防止用户不小心设置新值;二. 改(更新)操作更新,只要是查找到一条数据的情况下使用 save()就是更新$users = User::find(321); //先查出,返回对象 $users->username = '夜辉'; $users->save();使用 update() 方法实现批量更新;User::where('username', '夜辉') ->update([ 'username' => '辉夜' ]);三. 删操作使用 delete() 方法,可以删除数据;$users = User::find(332); $users->delete(); //批量删除 $users = User::where('username', '夜辉'); //名字带 夜辉都删除掉 $users->delete();如果你是通过主键 id 删除,那使用 destroy(id) 方法,免去查询操作;//通过主键删除 User::destroy(328);3. 批量赋值和软删除一. 批量赋值上一节增删改中,新增中我们发现需要进行批量赋值的许可;一般情况下,是为了防止提交过来的字段在部分场景中不需要或不能;所以,我们需要通过黑白名单机制进行过滤掉必要的字段;//通过提交过来的数据一次性新增 User::create(\Request::all());二. 软删除什么叫软删除?它相对于真实的删除,而并非真正的删除,只是隐藏了;首先,需要在数据库创建一个字段 deleted_at(默认),用于判断是否被软删除;默认设置这个字段为空(null),如果写入数据,成为非空状态,则说明被删除;开启软删除的功能,需要在模型端设置一下://开启软删除功能 use SoftDeletes;当开启了软删除功能,之前的删除操作,都会变成更新操作,给 deleted_at 赋值;//删除一 $users = User::find(82); $users->delete(); //删除二 User::destroy(81);而当我们开启了软删除的功能后,此时通过正常的数据获取列表,会自动隐藏//软删除的数据不可见 $users = User::get(); return [$users]; //单独获取被软删除的数据不行 $users = User::find(82); return [$users];3. 模型的作用域一. 本地作用域(scope)很多情况下,我们在数据查找时有一部分条件会被重复且大量使用;而这个条件,可能只是在这个模型对应的数据表使用,别的表并不使用;那么这种情况,可以使用本地作用域的方式,将常用的 SQL 封装起来;参数用法格式: scope + 自定义方法名比如:用户模块中,我们大量查询需要查询性别为男,且其它条件的 SQL;$users = User::where('gender', '男') ->where('price', '>', 90) ->get(); //PS:我们可以将性别为男这个片段,封装成一个单独的方法,然后统一在这个模型下调用;//AppHttpModels; //本地作用域,搜索自动添加为“男”的条件 //语法:scope 开头,后面名称尽可能包含语义 public function scopeGenderMale($query) { return $query->where('gender', '男');}//当然,如果赶紧单词太长,直接 gm()也行 $users = User::genderMale() ->where('price', '>', 90) ->get();6. **上面的方法比较死板,适合简单粗暴**,如果想要灵活多变,**支持传递参数**; //参数可以是 1 个或多个 $users = User::gender('女', -3) ->where('price', '>', 90) ->get(); //参数 2 和 3,接受控制器传递过来的 1,2 public function scopeGender($query, $value, $value2) { return $query->where('gender', $value)->where('status', $value2);} ### 二. 全局作用域 1. 全局作用域,顾名思义就是在任意地方都可以有效的封装条件; 2. 比如有个需求,不管在哪里操作,总是显示 status 为 1 的用户; 3. 首先在 app 目录下**创建一个用于全局作用域的目录**:`Scopes` ; 4. 创建一个用于设置 status 为 1 的全局作用域的类,它需要实现 `scope 接口` namespace AppScopes; //这里引用代码自动生成 use IlluminateDatabaseEloquentBuilder; use IlluminateDatabaseEloquentModel; use IlluminateDatabaseEloquentScope;class StatusScope implements Scope { public function apply(Builder $builder, Model $model) { // TODO: Implement apply() method. return $builder->where('status', 1); }}5. 此时,还不能实现全局,因为**需要在模型设置个开关**,让其富有灵活性; //启用全局作用域 protected static function booted() { parent::booted(); // TODO: Change the autogenerated stub static::addGlobalScope(new StatusScope());}//PS:而在控制器端,并不需要做任何设置,即可自动添加 status=1 的条件;6. 当然,如果这个全局只是针对某个模块,并不需要创建一个全局类,直接闭包即可; static::addGlobalScope('status', function (Builder $builder) { return $builder->where('status', 1);});//PS:注意 Builder 引入的文件和全局类引入的文件一致,如果引入别的同名类会错;7. 如果某个查询,并**不需要这个全局条件**,可以**单独移出掉**; //取消名称为 status 的全局 $users = User::withoutGlobalScope('status')->get();//取消全局类的条件 $users = User::withoutGlobalScope(StatusScope::class)->get();//PS:还有 withoutGlobalScopes([])方法,传递参数取消多个全局; --- ## 4. 模型的访问和修改器 ### 一. 访问器 1. 访问器:就是在**获取数据列表时,拦截属性并对属性进行修改的过程**; 2. 用法参数格式: `get`+ **字段名** + `Attribute` 3. 比如,我们在输出性别时,在性别左右加上括号,或给邮件转换为大写; //访问器,前固定 get,后固定 Attribute,Gender 是字段名 //参数$value 是源字段值,可修改返回 public function getGenderAttribute($value) { return '【'.$value.'】';}//PS:如果字段名是两个单词中间是下划线:user_name,那么方法名:getUserNameAttribute()4. 我们也可以创建一个虚拟字段,**用已有的数据字段进行整合**,不过要进行数据追加; > 单条数据加上虚拟字段 > **model层** class User extends Model { $protected $table = 'user'; //创建一个虚拟字段 public function getInfoAttribute() { return $this->username.'-'.$this->gender; }} **controller层** $info = User::find(19)->info; //->info dump($info);//打印 名字-性别 > 列表数据加上info虚拟字段 > **注意:**一定要把虚拟字段加到`$appends` **model层** class User extends Model { $protected $table = 'user'; //将虚拟字段追加到数据对象列表里去 protected $appends = ['info']; //创建一个虚拟字段 public function getInfoAttribute() { return $this->username.'-'.$this->gender; }} **controller层** $list = User::all()->toArray();  **注意2** :如果 gender **之前已经有访问器修改过**,上面的方法会**得到修改过的结果**; 5. 如果要使用**源字段进行创建虚拟字段**,需要使用下面这种:`$this->attributes[xxxx]` class User extends Model { $protected $table = 'user'; //将虚拟字段追加到数据对象列表里去 protected $appends = ['info']; //创建一个虚拟字段 public function getInfoAttribute() { return $this->attributes['username'].'-'.$this->attributes['gender']; }}  ### 二. 修改器 1. 修改器,相对于访问器,**是在写入的时候拦截,进行修改再写入**; 2. 用法格式: `set` + **字段名** + `Attribute` //修改器,写入数据时,将邮箱转换为大写 public function setEmailAttribute($value) { $this->attributes['email'] = strtoupper($value);}3. 可以添加默认的日期列,默认 created_at 和 updated_at; //设置可以自动写入日期的列 protected $dates = [ 'details' //详情字段-转换日期格式];4. 可以设置字段输出的类型,比如设置一个布尔型,输出时就是 true 和 false; //设置字段类型 protected $casts = [ 'details' => 'boolean' //详情字段转换布尔类型];5. 注意的是。模型用`create()`方法写入走修改器, 用`insert()`方法不走修改器。
2021年06月22日
974 阅读
0 评论
0 点赞
2021-06-22
Laravel框架中常用的构造器使用
1. 构造器的查询表达式一. select 查询select() 方法可以制定你想要的列,而不是所有列;//设置显示的列,设置列别名 $users = DB::table('users')->select('username as name', 'email')->get(); //对象形式 $users = DB::table('users')->select('username as name', 'email')->get()->toArray(); //数组形式addSelect() 方法,可以在你基础的查询构造器上再增加想要显示的字段;//给已经构建好的查询添加更多字段 $base = DB::table('users')->select('username as name', 'email'); $users = $base->addSelect('gender')->get();DB::raw()方法可以在 select()内部实现原生表达式,否则解析错误;//结合原生 SQL 实现复杂查询 $users = DB::table('users')->select(DB::raw('COUNT(*) AS id, gender')) ->groupBy('gender') ->get();也可以直接使用 selectRaw()方法实现内部原生;//或者直接使用 selectRaw()方法实现原生 $users = DB::table('users')->selectRaw('COUNT(*) AS count, gender') ->groupBy('gender') ->get();还可以通过 havingRaw() 方法实现更精准的分组筛选;//使用 havingRaw 方法实现分组筛选 $users = DB::table('users')->selectRaw('COUNT(*) AS count, gender') ->groupBy('gender') ->havingRaw('count>5') ->get();二. where 查询where()查询,即条件查询,完整形式需要字段表达式和值三个;//where 查询完整形式 $users = DB::table('users')->where('id', '=', 19)->get();大部分情况下,是等于用的比较多,就可以省略掉=号参数;//where 查询完整形式 $users = DB::table('users')->where('id', 19)->get();3.当然,还有>、<、>=、<=、<>、like 等操作符;$users = DB::table('users')->where('price', '>=', 95)->get(); $users = DB::table('users')->where('username', 'like', '%小%')->get();如果条件较多,可以用数组来分别添加条件,具体如下://如果条件都是等于,查看 SQL 语句用->toSql()替换->get() $users = DB::table('users')->where([ 'price' => 90, 'gender' => '男' ])->get(); //如果条件非等于 $users = DB::table('users')->where([ ['price', '>=', 90], ['gender', '=', '男'] ])->get();2. 构造器的where派生查询一. where派生查询orWhere() 方法,可以通过连缀实现两个或以上的 or 条件查询;//where() + orWhere 实现 or 条件查询 $users = DB::table('users') ->where('price', '>', 95) ->orWhere('gender', '女') ->toSql(); //结果 select * from `laravel_users` where `price` > ? or `gender` = ?"通过闭包,我们还可以构建更加复杂的 orWhere 查询;//orWhere()结合闭包查询 $users = DB::table('users') ->where('price', '>', '95') ->orWhere(function ($query) { $query->where('gender', '女') ->where('username', 'like', '%小%'); })->toSql(); //select * from `laravel_users` where `price` > ? or (`gender` = ? and `username` like ?)whereBetween()可以实现区间查询,比如价格在一个区间内的用户;//whereBetween 查询区间价格 60~90 之间 $users = DB::table('users')->whereBetween('price', [60, 90])->toSql(); //PS:这里还支持相关三种:whereNotBetween/orWhereBetween/orWhereNotBetween;whereIn()可以实现数组匹配查询,比如匹配出数组里指定的数据;//whereIn 查询数组里匹配的数值 $users = DB::table('users')->whereIn('id', [20,30,50])->toSql(); //PS:这里还支持相关三种:whereNotIn/orWhereIn/orWhereNotIn;whereNull() 可以查询字段为 Null 的记录;//whereNull 查询字段值为 Null 的记录 $users = DB::table('users')->whereNull('uid')->toSql(); //PS:这里还支持相关三种:whereNotNull/orWhereNull/orWhereNotNull;3. 构造器的排序分组 /子查询一. 排序分组使用 whereColumn() 方法 实现两个字段相等的查询结果 ;//判断两个相等的字段,同样支持 orWhereColumn() //支持符号'create_time','>', 'update_time' //支持符号支持数组多个字段格式['create_time','>', 'update_time'] $users = DB::table('users') ->whereColumn('create_time', 'update_time') ->get();使用 orderBy() 方法实现 desc 或 asc 排序功能。//支持 orderByRaw 和 orderByDesc 倒序方法 $users = DB::table('users') ->orderBy('id', 'desc') ->get();使用 latest() 方法设置时间倒序来排,默认时间字段是 created_at;//按照创建时间倒序排,默认字段 created_at $users = DB::table('users')->latest('create_time')->toSql();使用 inRandomOrder() 方法来随机排序,得到一个随机列表;//随机排序 $users = DB::table('users')->inRandomOrder()->get();使用 skip() 和 take() 限制结果集,或使用 offset() 和 limit();take= limit , skip = offset//从第 3 条开始,显示 3 条 $users = DB::table('users')->skip(2)->take(3)->toSql(); $users = DB::table('users')->offset(2)->limit(3)->get();使用 when() 方法可以设置条件选择,执行相应的 SQL 语句;//when 实现条件选择 $users = DB::table('users')->when(true, function ($query) { $query->where('id', 19); }, function ($query) { $query->where('username', '辉夜'); })->get();如果 MySQL 在 5.7+,有支持 JSON 数据的新特性;$users = DB::table('users')->where('list->id', 19)->first();二. 子查询使用 whereExists() 方法实现一个子查询结果,返回相应的主查询;//通过 books 表数据,查询到 users 表关联的所有用户 $users = DB::table('users')->whereExists(function ($query) { $query->selectRaw(1) ->from('books') ->whereRaw('laravel_books.user_id = laravel_users.id'); })->toSql(); //whereRaw 这句也可以替代为:whereColumn('books.user_id','users.id'); //PS:select 1 from,一般用于子查询的手段,目的是减少开销,提升效率,深入请搜索;也可以使用 where(字段,function())闭包,来实现一个子查询;//id=子查询返回的 user_id $users = DB::table('users')->where('id', function ($query) { $query->select('user_id') ->from('books') ->whereColumn('books.user_id','users.id'); })->toSql();4.构造器的 join一. join查询使用 join 实现内联接的多表查询,比如三张表进行 inner join 查询;$users = DB::table('users') ->join('books', 'users.id', '=', 'books.user_id') ->join('profiles', 'users.id', '=', 'profiles.user_id') ->select('users.id', 'users.username', 'users.email','books.title', 'profiles.hobby') ->get();也可以使用 leftjoin 左连接或 rightjoin 右连接实现多表查询;$users = DB::table('users') ->leftJoin('books', 'users.id', '=', 'books.user_id') ->rightjoin('profiles', 'users.id', '=', 'profiles.user_id') ->get();使用 crossjoin 交叉连接查询,会生成笛卡尔积,再用 distinct()取消重复;$users = DB::table('users') ->crossJoin('books') ->select('username', 'email') ->distinct() ->get();如果你想要实现闭包查询,和 where 类似,只不过要用 on 和 orOn 方法;$users = DB::table('users') ->join('books', function ($join) { //支持 orOn 连缀 $join->on('users.id', '=', 'books.user_id'); })->toSql(); //PS:on()方法后面如果想要再增加筛选条件,可以追加 where();使用 joinSub 实现子连接查询,将对应的内容合并在一起输出;//子连接查询 $query = DB::table('books')->selectRaw('user_id,title'); $users = DB::table('users')->joinSub($query,'books', function ($join) { $join->on('users.id', '=', 'books.user_id'); })->get();使用 union() 或 unionAll() 方法实现两个查询的合并操作;//union 取消重复,unionAll 不取消重复 $query = DB::table('users'); $users = DB::table('users') ->union($query) ->get();5. 构造器的增删改一. 增操作使用 insert() 方法可以新增一条或多条记录;//新增一条记录 DB::table('users')->insert([ 'username' => '李白', 'password' => '123456', 'email' => 'libai@163.com', 'details' => '123' ]); //新增多条记录 (二维数组) DB::table('users')->insert([ [...], [...] ]);使用 insertOrIgnore() 方法,可以忽略重复插入数据的错误;//忽略重复新增数据的错误 DB::table('users')->insertOrIgnore([ 'id' => 304, 'username' => '李白', 'password' => '123456', 'email' => 'libai@163.com', 'details' => '123' ]);使用 insertGetId() 方法,获取新增后的自增 ID;//获取新增后返回的 ID $id = DB::table('users')->insertGetId([ 'username' => '李白', 'password' => '123456', 'email' => 'libai@163.com', 'details' => '123' ]); //返回自增id return $id;二. 改(更新)操作使用 update() 方法,可以通过条件更新一条数据内容;//更新修改一条数据 DB::table('users') ->where('id', 304) ->update([ 'username' => '李红', 'email' => 'lihong@163.com' ]);使用 updateOrInsert() 方法,可以先进行查找修改,如不存在,则新增;//参数 1:修改的条件 //参数 2:修改的内容(新增的内容) DB::table('users')->updateOrInsert( ['id'=>307], ['username'=>'李黑', 'password'=>'654321', 'details'=>'123'] );对于 json 数据,新增和修改的方法和正常数据类似;//新增时,转换为 json 数据 'list' => json_encode(['id'=>19]) //修改时,使用 list->id 指定 DB::table('users')->where('id', 306) ->update([ 'list->id' => 20 ]);更新数据时,可以使用自增 increment() 和自减 decrement() 方法;//默认自增/自减为 1,可设置 DB::table('users')->where('id', 306)->increment('price'); DB::table('users')->where('id', 306)->increment('price', 2);三. 删操作使用 delete() 删除数据,一般来说要加上 where 条件,否则清空;//删除一条数据 DB::table('users')->delete(307); DB::table('users')->where('id', 307)->delete(); //清空 DB::table('users')->delete(); DB::table('users')->truncate();
2021年06月22日
408 阅读
0 评论
0 点赞