微信小程序商城构建全栈应用
- php+微信小程序全栈应用
软件/素材
- mac os 10.13.3
- PhpStorm 2018
- Postman
- XAMPP 7.0.2-1
- ThinkPHP 5.0.7
项目目录结构
1 | ├─application 应用目录 |
笔记
第八章
数据表关系分析 (写着写着就绕了)
- 数据表之间的关系: 1 对 1 1 对多 多对多
- 如何判断数据表之间的结构
- 首先确立是否是一个多对多的关系
- 查看表与表之间是否存在双方的外建均能被多个表调用,如果不是那就去除多对多关系
- 1 对 1 1 对多
- 在 thinkphp 中问题不大
- 如何去分析 1 对多或 1 对 1
- 1 对 1 的关系中, 两个表直接同时并且单次被执行,就是说一个关联请求中,表 1 一次只可以调用一个表 2 的元素,并且表 2 也只是被调用了一次
- 1 对多 的关系中, 表 1 通过一个外建,调用了多个表 2 的数据,并且表 2 的数据不能属于多个表 1,这样就是 1 对多的表现了
模型关联(我们确立了 er 关系再来做这么的一个关联)
模型关联查询
- 在我们的 model 是作为一个 ORM 模式的模型结构
- 在这之前我们就已经定义了模型了
- 我们有两个模型 Banner 与 BannerItem
- tp5 对我们提供了关联查询的方法 hasMany
定义关联查询
1
2
3
4
5
6
7// 在当前模型 Banner 新建类 类名自定义喜欢什么来什么
// 函数体要写在 Banner 这个主模型中,BannerItem是被关联模型
// 调用模型关联时要清晰的知道 外键 以及主建(某程度下是不用写后面两个,不建议)
public function items () {
// 关联查询方法hasMany 关联模型 外建 当前模型 banner id主建
return $this->hasMany('BannerItem','banner_id','id');
}调用关联查询
1
2// 在调用 模型的时候加上 with这么个方法 (括号内填写的就是刚才定义的函数名)
$banner = BannerModel::with('items')->find($id);
模型嵌套关联查询
- 在我们的 查询中 会存在被关联体中还关联着变得关联体,在 tp5 中就形成了嵌套查询
- 当然 tp5 也给我们提供了方法:belongsTo
- 嵌套关系 Banner -> BannerItem -> Image (这里就存在了多重的嵌套)
- 模型 Banner BannerItem Image
- 是 BannerItem 关联 Image 所以关联函数我们写在 BannerItem 中
- 定义嵌套查询
1
2
3
4public function img() {
// 处理方法名其他都是一样的,这里就不多说了
return $this->belongsTo('Image','img_id','id');
}- 调用查询 (这个比较关键,不过还是很简单的)
1
2
3
4
5// with 可以是字符串也可以是数组(嵌套关联时就会用数组)
// 为什么是items.img 而不是 直接img呢,因为是嵌套关系,在模型中可以嵌套这里也是可以的
// 但是在 嵌套时 是items 关联的 img ,这里就会用.来链接
// 这个解释比较绕但是,知道方法就是要这样去用的就好啦
$banner = BannerModel::with(['items','items.img'])->find($id);
隐藏模型字段 (模型自带)
- hidden 方法隐藏字段
1 | // 数据 方法 字段名 |
- visible 只显示的字段
1 | $banner->visible(['字段名例:id','update_time]) |
模型内部隐藏字段 (自定义模型的内部隐藏,把一些前端不需要的字段隐藏了)
- hidden 隐藏
- 直接在 model 定义的模型内添加方法 (以 Banner 为例)
1 | namespace app\api\model; |
自定义配置
- /application/extra (extra 自己新建的,凡是放在这里面的配置文件都会被自动加载)
- 手动配置一个本地的 img 图片路径
- 在 extra 下 新建 setting.php
1 | return [ |
- 使用自定义变量
- 因为是在 extra 内部定义的所以会自动调用,那么我们用 config 就可以去掉用到了
1
2// 配置文件名.变量名
config('setting.img_prefix');
- 因为是在 extra 内部定义的所以会自动调用,那么我们用 config 就可以去掉用到了
静态文件存放
- 静态的外部文件,例如图片啊文本啊等的文件,必须放在 public 这个公共目录下
- 并不是放在 application 的这个开发目录下,因为 tp5 的架构里面只有 public 这个目录是对外开放的
- 所以文件都必须是要放在 public 目录下
tp 模型读取器 (数据拼合)
- 为了获取数据/修改数据,tp5 给出了一个读取器的方法
- 用来给我们读取数据修改数据用的
- 那个模型要修改数据就在哪个模型定义
- 定义读取器(其实也是一个函数方法)
- 读取器命名规范 开头 get 必须有 + 读取数据的名称并且开头要大写例 Url + Attr 必须加的(利用驼峰命名法)
- getUrlAttr (完整的编写,除了中间的那个数据,其他都是必须有的,中间数据名开头必须大写)
- 传入一个值,名字自定义 (这个传入的数据其实就是我们要获取到要修改的数据)
- 每一次传入一个数据,有多个输出就会重复的执行读取器
- 因为在我们的业务逻辑中会调用到当前模型的其他数据,但是第一个参数只是获取到的是当前读取器的数据,并无法读取到其他的数据
- 所以添加了第二个参数 (这个参数会给我们返回一个这个模型的数据,就是所有的数据)
1 | public function getUrlAttr ($value,$data) { |
- 使用读取器 (做数据的修改然后返回)
1 | public function getUrlAttr ($value) { |
- 业务逻辑添加
1 | public function getUrlAttr ($value,$data) { |
自定义基类 (面向对象,提取模型读取器)
- 一开始这样做会觉得好像代码还多了啊,这么不就是做无用功吗,在业务不断增加的时候,后期修改就可以看出来好处了
- 集中业务逻辑
- 创建 BaseModel.php 作为模型基类
- 把让所有的模型都继承这个基类
把读取器提取到 模型基类 (这样做是一个面向对象的思想)
- 但是提取了模型基类后我们所有的子模型都会自动的去执行模型
- 这样可能会造成一些数据的变更和错误,比如说,两个命名一样但是代表的数据不同是就会出现错误
- 所以我们把它封装为一个自调用的方法
1
2
3
4
5
6
7
8
9// BaseModel
// 读取器
protected function prefixImgUrl ($value,$data) {
$finalUrl = $value;
if ($data['from'] === 1) {
$finalUrl = config('setting.img_prefix') . $value;
}
return $finalUrl;
}
子模型调用基类方法
- Image
1
2
3public function getUrlAttr ($value,$data) {
return $this->prefixImgUrl($value,$data);
}
- Image
定义 api 版本号
- 在互联网的项目中,我们会对项目版本对升级,以及业务逻辑改变和变更
- 同时也是需要去兼容旧版本,所以会保留旧版本的 api
- 开发开闭原则
- 代码对拓展开发,对修改封闭
- 添加功能直接以拓展的方式添加就可以,不需要去改变代码
- 修改是封闭的,业务变更上升版本
- 不可以修改原来的版本代码,会破坏了原版本的代码,和影响功能调用的风险
- 需要修改就要添加新的版本
- 多版本
- 版本的分离,新旧版本不发生冲突
- 新老版本的兼容问题
- 给用户缓冲时间,也不能兼容太多的版本,成本太高
- v1 做 v1 版本层
- v2 做 v2 版本层
路由 api 动态变更
1 | // 动态版本 实现传什么就调用什么版本的api,同时也是要修改版本指向接口 |
一对一关系选择关联方法
- belongsTo
- 在有外建的表内请求就用 belongsTo
- hasOne
- 在没有外建的表亲求就用 hasOne
多对多查询 (belongsToMany)
-
- 多对多的查询呢 就比一对多和 1 对 1 的查询要多了一个参数
- 在参数中第二个是放入第三个表也就是中间表
1 | public function products () { |
开启路由完整匹配模式
- 开我们开发的过程中难免会有 api 相同当是请求的方式以及传参的不同,但是又需要相同的 api 名称
- 在我们的 tp5 中,会自动追寻一个半路径的匹配,所以当匹配到了相关的路由时就会停止匹配
- 但是这样返回的结果肯定不是我们要的,所以就要开启这个完整的路由匹配模式
- 在 config.php 配置文件中,我们就可以来更改了
1 | // 只有找到这句话改变就可以了 false -> true |
合理利用数据冗余
- 在查询量上来的时候避免数据量大多表查询之间耗时
- 合理的利用数据冗余来减少联合表的查询减少查询时间
- 但不要太过多但使用,只是为了减少数据库压力
- 在数据库中做相关的优化
collection 字符集
- 我们使用获取到的数据是字符集更方便让我们来修改数据
- tp5 修改获取返回数据 (/application/database.php)
1 | // 找到这个吧 arr改为 collection |
使用字符集就可以轻松的临时隐藏字段
- 当我们在开发的过程中,不是所有业务逻辑都需要隐藏的字段,我们就不可以在关联模型中直接就隐藏字段
- 我们会使用临时隐藏字段
- 当然数组我们是不可以直接这样来隐藏的,但是使用字符集的话就可以直接的去使用函数进行数据的隐藏
1
2// 使用hidden进行隐藏
$products = $products->hidden(['summary']);
字符集判空
- isEmpty 内置函数
1 | // 判断空抛出异常 |
##第九章
service (建立在 model 上的,用来处理复制的业务)
- 在我们的 tp5 中,我们的 model 代表的一个很重要的位置
- 可以写业务逻辑,也访问数据库
- 但是 service 不可以用来访问数据库,因为上建立在 model 之上的
- 我们都会把复杂的业务逻辑放在 service 层中
公共应用文件 common.php
- 编写公共的 http 请求
1 | /* |
模型插入数据(create)
- 在 tp5 中如何向数据库插入数据
- tp5 模型给我们准备了 create 的方法
1 | // 模型名 create方法 数组传入要添加的字段和数据 |
动态传入数值随机生成字符串方法
1 | /* |
文件缓存 chache
- 使用 cache 写入缓存
- 使用文件存储的方式
- 缓存的地址在目录文件/runtime/cache 文件内
1 | $request = cache($key,$value,$expire_in); |
路由分组
- 由于我们 api 接口的不断增加
- 在一个分类中会有很多的相同的接口路由
- 这个时候如果我们业务的变更修改起来就会很麻烦
- 所以我们是用来路由分组来实现
- group 方法
- 第一个是公共的路由部分,第二个是一个闭包(也就是一个 function 的方法)
- 在里面还是安装路由一样去定义就可以了
- 也能提高路由的效率
1 |
|
关联模型下个关联数据排序(tp5 没有的,重点)
- 使用 模型+query 添加排序
1 | // 关联模型 imgs properties 查询 |
使用 关联模型 添加/更新数据
- 添加数据的方法有很多,我们来使用一下关联模型的方法
- 两个的区别在于 修改操作的 关联 不可以用括号
1 | // 调用 user 中的 address 关联 使用 save方法添加数据 |
第十章
前置操作
- 在我们编写 api 业务逻辑的时候,我们会想在调用 api 接口之前,需要满足某些条件
- 这样才可以去访问我们的接口中的业务逻辑
- 所以我们要在做一个前置操作,抵挡不满足条件的抛出异常
- tp5 中使用前置操作需要基础自带的一个基类 Controller
- 定义一个名为 \$beforeActionList 的数组
1 | use think\Controller |
重构前置验证操作 (实现面向对象)
- 提取验证业务逻辑到 service 的基类中
- 提取前置方法到 BaseController 的基类中
- 继承基类,执行前置方法
- 提取出一个前置的基类 BaseController (继承内置 Controller)
1 | use app\api\service\Token as TokenService; |
- 提取验证业务逻辑(因为是 token 相关的就归并到 token 的 service 业务层中)
1 | // 重构前置方法,验证权限 |
- 继承 BaseController 基类使用前置方法
1 | // 继承基类 |
验证器数据自定义子项验证
- 自定义子项验证,通过自定义的方法调用实现
- 当我们在验证时,传入的是一个二维数组,就可以使用来验证子项
- 我们就自定义一个验证的方法,通过基类的验证的调用
1 |
|
自动添加时间戳(TP5 内置添加时间戳)
- 在我们的操作中,我们的数据中会带有数据,tp5 为我们提供了自动添加时间戳
- 找到自己要添加的时间戳的模型 我是在 order 添加那我就去 orde 人的模型中
- \$autoWriteTimestamp 添加为 true,需要是模型的方式才可以使用的
- 创建 修改 删除
- 默认为 create_time update_time delete_time
- 修改方法名 在模型下修改
1 | // 自动写入时间戳 |
Tp5 事务应用
- 在我们的应用中可能会出现分步的操作,可能会本地与服务端出现不一致
- 所以我们使用事务来做处理
- 在中间出现错误就会把数据回滚保持数据的一致性
1 | // 开头加入开始 |
引入没有命名空间的文件与调用(Loader),手动引入微信支付 php
- 使用 loader 的 import 方法
- extend/WxPay/WePay.Api.php
1 | // 文件开头的第一个 文件路径 // 类的名称 |
TP5 模型实现数据减少 setDec
1 | // 前面是查询 第一个数是写要改变的字段 第二个是要减少的数量 |
数据库锁与事务锁的区别
- 数据库模型->lock(true)
- 事务锁 Db
- 事务锁是等待整个事务提交才会执行第二次事务,但是数据库模型锁只是单步的锁着了数据库查询语句
- 在后面的操作还没有执行时,数据库模型锁已经放开了
外部网址使用
- 要从根目录一直到 index.php
- 后面才是路由
- www.yhf7/zerg/public/index.php/api/v1/pay/notify
模型分页查询(paginate)
- 第一个参数是分类数
- 第二个数是否简洁模式
- 第三个是数组填入分页数
1 |
|
后记
- 这是学习微信小程序开发后端PHP时候的笔记,欢迎更多的同行大哥指导交流
- 欢迎进入我的博客:https://yhf7.github.io/
- 如果有什么侵权的话,请及时添加小编微信以及qq也可以来告诉小编(905477376微信qq通用),谢谢!