框架开发-TP5

一. 初识佳人 (ThinkPHP 5.0 基本)

TP5 环境要求

PHP >= 5.4.0
PDO PHP Extension PDO类
MBstring PHP Extension 多字节字符串函数

查询文档手册中mb字符串函数

CURL PHP Extension 钩子/爬虫

目录结构

1).部署框架 目录结构

1
2
3
4
5
6
7
8
9
10
11
12
13
tp5
├─application 应用目录
├─extend 扩展类库目录(可定义)
├─public 网站对外访问目录
├─runtime 运行时目录(可定义)(linux777权限)
├─vendor 第三方类库目录(Composer)
├─thinkphp 框架核心目录
├─build.php 自动生成定义文件(参考)
├─composer.json Composer定义文件
├─LICENSE.txt 授权说明文件
├─README.md README 文件
└─think 命令行工具入口
!(如果在linux环境下面的话,需要给runtime目录755权限)
1
PS. 几个关键的路径:
1
2
3
4
5
6
目录            说明             常量
tp5 项目根目录 ROOT_PATH
tp5/application 应用目录 APP_PATH
tp5/thinkphp 框架核心目录 THINK_PATH
tp5/exend 应用扩展目录 EXTEND_PATH
tp5/vendor Composer扩展目录 VENDOR_PATH
1
2
3
-------

2).核心框架 目录的结构
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
├─thinkphp 框架系统目录(请只读)
│ ├─lang 语言包目录
│ ├─library 框架核心类库目录
│ │ ├─think think 类库包目录
│ │ └─traits 系统 traits 目录
│ ├─tpl 系统模板目录(修改请保留源文件)
│ │
│ ├─.htaccess 用于 apache 的重写
│ ├─.travis.yml CI 定义文件
│ ├─base.php 框架基础文件
│ ├─composer.json composer 定义文件
│ ├─console.php 控制台入口文件
│ ├─convention.php 惯例配置文件
│ ├─helper.php 助手函数文件(可选)
│ ├─LICENSE.txt 授权说明文件
│ ├─phpunit.xml 单元测试配置文件
│ ├─README.md README 文件
│ └─start.php 框架引导文件
1
2
3
-------

3).默认应用 目录结构:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
├─application            应用目录(可设置)
│ ├─index 模块目录(可更改)(可多模块)
│ │ ├─config.php 模块配置文件
│ │ ├─common.php 模块公共文件
│ │ ├─controller 控制器目录
│ │ ├─model 模型目录
│ │ └─view 视图目录
│ │
│ ├─command.php 命令行工具配置文件
│ ├─common.php 应用公共文件
│ ├─config.php 应用配置文件
│ ├─tags.php 应用行为扩展定义文件
│ ├─database.php 数据库配置文件
│ └─route.php 路由配置文件

架构总览

生命周期

入口文件 / 公共资源说明

public/static中的gitignore文件声明了所有该文件中的数据全部不会上传到git

方便采用本地调试 , 远程部署的设计结构(CDN服务/OSS)

URL访问

调试模式

配置: 编程过程中只需要关注应用配置和模块配置就够了

application/config.php中配置

​ 开发过程中开启app_debug, app_trace(配置位置为console台),

注意: 上线后必须将配置还原; 该配置打开可能会影响接口的调试和正常运行

phpstorm中可以完成git操作,并配合码云安装IDEA插件

控制器

新建模块
php think build --module admin
新建控制器
php think make:controller admin/User --plain

视图

PHPstorm快捷键:

​ 美化 :Ctrl+Alt+L

​ Ctrl+Alt+Shift+L

二. 尝试接近 (CURD 操作 Db类)

数据库配置

application/database.php

本地使用时使用服务器ip , 和服务器专用账号, 上传时修改为本地ip

3306

表前缀

查询数据

1
2
3
4
5
6
7
8
9
10
11
use think\Db;

//原生sql
$list = Db::query('select * from users');
$list = Db::query('select * from users where id=?', [3]);

//DB类
$list = Db::table('users')->order(['id'=>'desc'])->select();

//助手函数(无需use think\Db 也可以使用)
$list = db('users')->order(['id'=>'desc'])->select();

新增数据

1
2
3
4
5
6
7
8
9
10
11
12
//原生sql
$list = Db::execute("insert into users (id, name, age) values (null,'西格玛','22')");
$list = Db::execute('insert into users (id, name, age) values (:id, :name, :age)', ['id' => null, 'name' => 'tiger', 'age' => 13]);

//DB类
$list = Db::table('users')->data(['name'=>'cat','age'=>22])->insert();
$list = Db::table('users')->insert(['name'=>'cat','age'=>22]);
$list = Db::table('users')->insertGetId(['name'=>'cat1','age'=>12]);

//助手函数
$list = db('users')->insert(['name'=>'cat1','age'=>12]);
$list = db('users')->insertGetId(['name'=>'cat3','age'=>12]);

删除数据

1
2
3
4
5
6
7
8
9
10
//原生sql
$list = Db::execute('delete from users where name="cat1"');

//DB类
$list = Db::table('users')->delete(80); #主键才可以这么玩
$list = Db::table('users')->where(['name'=>'cat'])->delete();
$list = Db::table('users')->where('name','cat')->delete();

//助手函数
$list = db('users')->where('name','tiger')->delete();

更新数据

1
2
3
4
5
6
7
8
9
//原生sql
$list = Db::execute('update users set age=33 where name="西格玛"');

//DB类
$list = Db::table('users')->where(['id'=>'77'])>update(['name'=>'daboluo','age'=>'11']);
$list = Db::table('users')->where('id',77)->update(['name'=>'dalao','age'=>'11']);

//助手函数
$list = db('users')->where('id',77)->update(['name'=>'dalao01','age'=>'11']);

若设置了表前缀功能 , 将table替换为name即可正常使用

三. 探索深入 (路由)

1.默认的URL规则

2.路由文件

​ 1.配置文件目录

application/config.php

1
2
3
4
5
推荐使用强制路由模式,配置后不再使用pathinfo格式的路径模式
// 是否开启路由
'url_route_on' => true,
// 是否强制使用路由
'url_route_must' => true,

​ 2.路由设置目录

application/route.php

1
2
3
use think\Route
//设置路由格式
Route::get('/','index/index/index');

3.路由概念/规则

1
2
3
4
5
6
7
从规则上区分 路由分为: 动态路由 和 静态路由 两种
从设置方式上 路由分为: 动态注册 和 静态注册 两种

路由规则中 包含变量的 就是动态路由,没有包含任何变量的称为静态路由.
在路由文件中 return数组的 路由形式, 称之为 静态注册
使用Route类的方法 注册的路由 称之为 动态注册(5.0推荐)
以上两者 可同时使用.

3.定义路由

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
use think\Route
//设置路由格式
Route::get('/','index/index/index');
Route::post('ppp','index/index/ppp');
//无参数模式
Route::get('/user','index/index/user');
//必须传参数模式
Route::get('/user/:id','index/index/user');
//可有可无参数模式
Route::get('/user/[:id]','index/index/user');
//匹配参数(只能匹配指定的参数,多了报错)
Route::get('/user/[:id]$','index/index/user');
//闭包
Route::get('/user:id',function($id){
//执行体
});

4.闭包定义

5.路由参数

1
2
3
// 动态注册
// Route::rule('路由表达式','路由地址','请求类型','路由参数(数组)','变量规则(数组)');
Route::get('/userlist','admin/user/index',['ext'=>'html|shtml']); #限制后缀名

6.变量规则

php think make:controller index/Blog --plain

1
2
3
4
5
6
7
8
9
10
11
12
13
若使用非路由模式,真实访问路径为:
http://www.tp5.com/index/blog/index/id/123
http://www.tp5.com/index/blog/read/name/naxx
http://www.tp5.com/index/blog/article/year/2015/month/11/day/20

使用路由控制
Route::get('/blog/:id$','index/blog/index',[],['id'=>'\d+']);
Route::get('blog/:name$','index/blog/read',[],['name'=>'\w+']);
Route::get('/blog/:year/:month/:day','index/blog/article',[],['year'=>'\d{4}','month'=>'\d{2}','day'=>'\d{2}']);
之后的路由路径变为:
http://www.tp5.com/blog/22
http://www.tp5.com/blog/anna
http://www.tp5.com/blog/2015/12/12

解决路由拦截的方法有两种 , 一种是将拦截范围越大的路由越向后移, 一种是在路由路径后加 $ 截断

7.路由分组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 路由分组用来处理同一个模块下的不同路由
Route::group('blog', [
':id$' =>
[
'index/blog/index',
['get'],
['id' => '\d+']
],
':name$' =>
[
'index/blog/read',
['get'],
['name' => '\w+']
],
':year/:month/:day' =>
[
'index/blog/article',
['get'],
['year' => '\d{4}', 'month' => '\d{2}', 'day' => '\d{2}']
],
]);

8.生成URL地址

使用函数方法url()

或Url::bulid()

1
2
3
4
5
6
7
8
9
10
11
12
use think\Url;
echo Url::build('index/index/user','id=4444');
# /user/4444.html
echo Url::build('index/index/user',['id'=>'43']);
# /user/43.html
// 多参数模式
echo Url::build('index/blog/read',['name'=>'annakalina'],'xhtml',true);
# http://www.tp5.com/blog/annakalina.xhtml
echo Url::build('index/blog/read',['name'=>'annakalina'],'xhtml','www.hao123.com');
# http://www.hao123.com/blog/annakalina.xhtml
echo Url::build('index/blog/read@www.hao123.com',['name'=>'annakalina'],'xhtml');
# http://www.hao123.com/blog/annakalina.xhtml

第一个参数为pathinfo路径 , 第二个参数为参数 , 第三个参数为扩展名 , 第四个参数为域名(true表示当前域名 , 也可以写入其他域名)



四. 正式交往 (控制器)

控制器概念

  • 接收路由分配过来的请求
  • 接收各种的参数
  • 调用模型 取得数据
  • 调用模版 输出页面
  • 业务逻辑 流程控制/分支/循环.
  • 业务分层

控制器的定义

控制器初始化

__construct()可能覆盖掉继承的父类同名方法,

应使用tp5中的_initialize()方法

前置操作: $beforeActionList

1
2
3
4
5
6
7
8
// ['except' => '方法名,方法名'] #除了指定的方法之外都执行
// ['only' => '方法名,方法名'] #只有指定的方法可以执行
// 实例:
protected $beforeActionList = [
'first',
'second' => ['except'=>'hello'],
'third' => ['only'=>'hello,data'],
]

跳转和重定向

  1. 页面 跳转(存在缓冲时间)jump
1
2
3
use think\Controller;
return $this->success('程序执行成功','admin/user/index');
return $this->error('程序执行失败','admin/user/index');

第二个参数在路由表中包含指定路由的情况下可以直接写pathinfo路径

1
2
3
4
5
6
7
8
9
10
更改固有模板
模板路径: thinkphp/tpl/dispatch_jump.tpl
复制到模板所在目录,修改模板所在目录config.php文件
//配置文件
return [
'dispatch_error_tmpl' => APP_PATH . 'admin/view/index/jump.html',
//默认成功跳转对应的模板文件
'dispatch_success_tmpl' => APP_PATH . 'admin/view/index/jump.html',
];
即完成了更换模块模板文件的操作
  1. 重定向(直接转)redirect
1
2
3
use think\Controller;
return $this->redirect('index/index/user','id=5');
return $this->redirect('http://bilibili.com');

空操作

空控制器

对于混合路由有效 , 访问到不存在的方法和类时触发


五. 执子之手

(增删改查 用户管理实例 RESTful资源控制器)

生成 rest模块的 User资源控制器

php think build --module rest
php think make:controller rest/User

RESTful架构说明

www.ruanyifeng.com/blog/2011/09/restful.html
www.ruanyifeng.com/blog/2014/05/restful_api.html
www.ruanyifeng.com/blog/2018/10/restful-api-best-practices.html

1567586616147

注册资源路由

1
2
在路由表中添加
Route::resource('users','rest/user');
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 动态注册
// Route::rule('路由表达式','路由地址','请求类型','路由参数(数组)','变量规则(数组)');
路由规则:URL访问规则(包括静态规则和动态规则),只有符合规则的路由才能正确访问;
路由地址:实际访问的地址(可以是控制器操作、类的方法或者闭包);
请求类型:表示当前路由生效使用的请求类型,包括GET/POST/PUT/DELETE等,如果希望任何请求都能访问使用*号(默认值)。
路由参数:路由匹配的条件约束或设置参数(用于检测或者解析);
路由变量:路由规则里面的动态变量以及PATH_INFO里面的参数都称之为路由变量;
变量规则:路由规则中的变量的匹配规则(正则表达式);

支持任意请求规则
Route::rule('new/:id','News/update');
定义GET请求路由规则
Route::get('new/:id','News/read');
定义POST请求路由规则
Route::post('new/:id','News/update');
定义PUT请求路由规则
Route::put('new/:id','News/update');
定义DELETE请求路由规则
Route::delete('new/:id','News/delete');
所有请求都支持的路由规则
Route::any('new/:id','News/read');

RESTful实例

  1. index 显示资源列表
  2. create 显示创建资源表单页
  3. save 保存新建的资源
  4. read 显示指定的资源
  5. edit 显示编辑资源表单页
  6. update 保存更新的资源
  7. delete 删除指定资源

使用实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 在User.php中获取数据,并使用模板
$list = Db::name('user')
->field(['id', 'name'])
->order('id', 'asc')
->select();

return view('user/index', [
'title' => '用户列表',
'list' => $list,
]);
// 在本模块view目录下创建模板(view/user/index.html)
// 引入css,js文件
{css href="./static/css/bootstrap.min.css"}
{css href="__INDEX__rest.css"}
{js href="__JS__jquery.min.js"}
{js href="__JS__bootstrap.min.js"}
1
2
3
4
5
6
7
8
	#引入文件时或在配置中定义常量
// 视图输出字符串内容替换
'view_replace_str' => [
'__INDEX__' => '/static/index/',
'__CSS__' => '/static/index/css/',
'__JS__' => '/static/index/js/',
],
则变为{css href="__CSS__bootstrap.min.css"}

注意: 在模板中使用PHP函数时需要在其前添加冒号

{:url()}

遍历 {volist name="list" key="k" id="v"}{/volist}

1
2
3
4
5
6
7
8
phpstorm快捷键
Alt+J 快速多选后面的选中元素
Ctrl+Alt+L 快速格式化代码
Ctrl+D 复制指定代码行
Ctrl+Shift+↑/↓ 上下移动代码位置

Alt+←/→ 切换代码窗口
Alt+↑/↓ 快速切换方法

六. 人造人计划 (数据库 Db类)

数据库使用的补充

使用框架开发应用,一般不需要 直接操作数据库,而是通过 框架封装好的 数据库中间层 对数据库进行操作。
这样的好处 主要有两个:
一是简化数据库操作,二是做到跨数据库的一致性。

这种设计的中间层 通常称之为 数据库访问抽象层,简称数据访问层(DAL),ThinkPHP5的数据访问层 是基于PHP内置的PDO对象实现。一般抽象层本身 并不直接操作数据库,而是通过 驱动来实现具体的数据库操作。

php think make:controller admin/Test –plain

查询相关

2.1. 快捷查询
2.2. 批量查询
2.3. 区间查询
2.4. 多表查询
1). 手动多表
2). JOIN
3). 视图
2.5. 聚合查询
2.6. 子查询
1.fetchSql 方式
2.buildSql 方式


七. 新生 (模型 Model)

ThinkPHP5.0的模型是一种对象-关系映射(Object/Relation Mapping,简称ORM)的封装,
并且提供了简洁的ActiveRecord实现。一般来说,每个数据表会和一个“模型”对应。

ORM的基本特性就是表映射到模型,记录映射到模型对象实例,字段映射到对象属性。

模型是一种对象化的操作封装,而不是简单的CURD操作,简单的CURD操作直接使用前面提过的Db类即可。

模型类和Db类的区别主要在于对象及业务逻辑的封装,Db类的查询默认返回的是数组(或者集合),而模型类返回的是当前的模型对象实例(或者集合),模型是比Db类更高级的数据封装,支持模型关联、模型事件和业务(逻辑)方法。

php think make:model rest/User