tp5

ThinkPHP5.0开发

一.架构

1.架构总览

MVC是一个设计模式,它强制性的使应用程序的输入,处理和输出分开。使用MVC应用程序被分成三个核心部件:模型,视图,控制器,他们各自处理自己的任务。

入口文件:用户请求的php文件,负责处理一个请求的声明周期,最常见的入口文件就是index.php.

应用:一个管理系统架构及生命周期的对象,有系统的\think\App类完成,应用通常在入口文件中被调用和执行,

具有相同的应用目录。应用具有自己独立的配置文件,公共文件。

模块:应用有多个模块组成的,这些模块通常都是应用目录下面的一个目录,每个模块都有自己独立的配置文件,公共文件和类库文件。

控制器:每个模块拥有独立的mvc类库及配置文件,一个模块下面有多个控制器负责响应请求。

控制器主要负责请求的接收,并调用相关的模型处理,并最终通过视图输出。

操作:一个控制器包含多个操作,操作方法是一个URL访问的最小单元。

模型:模型类并不一定要访问数据库,而且在5.0的架构设计中,只有进行实际的数据库查询操作的时候,才会进行数据库的连接,是真正的惰性连接。

视图:控制器调用模型类后返回的数据通过视图组装成不同格式的输出。视图根据不同的需求,来决定调用模版引擎进行内容解析后输出还是直接输出。

驱动:系统很多的组件都采用驱动式设计,从而可以更灵活的扩展。

行为:预先定义好的一个应用位置执行的一些操作。类似编程AOP编程(关注点功能,将功能和步骤分为一点)

2.生命周期

入口文件:

define('APP_PATH', __DIR__.'/../appllication/')

require __DIR__.'/../thinkphp/start.php';

引导文件:start.php

1.加载系统常量定义define(‘THINK_VERSION’, ‘5.0.3’);

define(‘THINK_START_TIME’, microtime(true));

define(‘THINK_START_MEM’, memory_get_usage());

define(‘EXT’, ‘.php’);

define(‘DS’, DIRECTORY_SEPARATOR);

defined(‘THINK_PATH’) or define(‘THINK_PATH’, DIR . DS);

define(‘LIB_PATH’, THINK_PATH . ‘library’ . DS);

define(‘CORE_PATH’, LIB_PATH . ‘think’ . DS);

define(‘TRAIT_PATH’, LIB_PATH . ‘traits’ . DS);

defined(‘APP_PATH’) or define(‘APP_PATH’, dirname($_SERVER[‘SCRIPT_FILENAME’]) . DS);

defined(‘ROOT_PATH’) or define(‘ROOT_PATH’, dirname(realpath(APP_PATH)) . DS);

defined(‘EXTEND_PATH’) or define(‘EXTEND_PATH’, ROOT_PATH . ‘extend’ . DS);

defined(‘VENDOR_PATH’) or define(‘VENDOR_PATH’, ROOT_PATH . ‘vendor’ . DS);

defined(‘RUNTIME_PATH’) or define(‘RUNTIME_PATH’, ROOT_PATH . ‘runtime’ . DS);

defined(‘LOG_PATH’) or define(‘LOG_PATH’, RUNTIME_PATH . ‘log’ . DS);

defined(‘CACHE_PATH’) or define(‘CACHE_PATH’, RUNTIME_PATH . ‘cache’ . DS);

defined(‘TEMP_PATH’) or define(‘TEMP_PATH’, RUNTIME_PATH . ‘temp’ . DS);

defined(‘CONF_PATH’) or define(‘CONF_PATH’, APP_PATH); // 配置文件目录

defined(‘CONF_EXT’) or define(‘CONF_EXT’, EXT); // 配置文件后缀

defined(‘ENV_PREFIX’) or define(‘ENV_PREFIX’, ‘PHP_’); // 环境变量的配置前缀

2.加载环境常量(环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数,如:临时文件夹位置和系统文件夹位置等。)

define(‘IS_CLI’, PHP_SAPI == ‘cli’ ? true : false);

define(‘IS_WIN’, strpos(PHP_OS, ‘WIN’) !== false);

3.注册自动加载机制:

\think\Loader::register();

4.注册错误和异常处理机制:

\think\Error::register();

5.加载惯例配置文件

\think\Config::set(include THINK_PATH . ‘convention’ . EXT);

6.执行应用

APP::run()->send();

3.注册自动加载

系统会调用Loader::register()方法注册自动加载,所有符合规范的类库都将自动加载。

1.注册系统的自动加载方法 \think\Loader::autoload;

2.注册系统命名空间定义

3.加载类库映射定义

4.如果存在Composer安装,则注册Composer自动加载

5.注册extend扩展目录

4.注册错误和异常机制

执行Error::register()注册撮合异常处理机制

5.应用初始化

1.加载应用配置

2.加载扩展配置文件

3.加载应用状态配置

4.加载别名定义

5.加载行为定义

6.加载公共文件;

7.注册应用命名空间

8.加载扩展函数文件

9.设置默认时区

10.加载系统语言 包

6.URL访问检测

没有启用路由的情况下

http://serverName/index.php(或者其他应用入口文件)/模块/控制器/操作/[参数名/参数值]; PATH_INFO访问地址方式

http://serverName/index.php?s=/模块/控制器/操作/[参数名/参数值] 兼容模式

URL不区分大小写 自动转换为小写

隐藏入口文件

1.httpd.conf配置中加载mod_rewrite.so模块

2.AllowOverride None将none改为All

3.在应用入口问加你同级目录添加.htaccess文件,内容如下:

7.路由检测(访问URL匹配规则)

1.路由到模块/控制器/操作

2.路由到外部重定向地址;

3.路由到控制器方法;

4.路由到闭包函数;

5.路由到类的方法;

8.分发请求

在完成了URL检测和路由检测之后,路由器分发请求到对应的路由地址,建议统一使用return返回数据!

1.模块/控制器/操作

2.外部重定向

3.闭包函数?

9.响应输出

控制器所有操作方法都是return返回而不是直接输出,系统会调用Response::send方法将最终的应用返回的数据输出到页面和客户端,并自动转换成default_return_type参数配置的格式。

10.应用结束

系统会在应用或者中断后进行日志保存写入操作

11.命名空间

ThinkPHP5采用命名空间方式定义和自动加载类库文件

特别注意的是,如果你需要调用php内置的类库,或者第三方没有使用命名空间的类库,记得在实例化类库的时候加上\

根命名空间是一个关键概念,think就是一个根命名空间

添加新的根命名空间:注册新的根命名空间或者放入Extend_Path目录(自动注册)

自动注册:把自己的类库包放入EXTEND_PATH目录
namespace my;

class Test

{

​ public function sayHello()

​ {

​ echo ‘hello’;

​ }

}

如果我们在应用入口文件中重新定义了EXTEND_PATH常量的话,还可以改变\my\Test类文件的位置

define(‘EXTEND_PATH’, ‘../vendor/’);

手动注册

在应用入口文件中添加下面的代码:

\think\Loader::addNamespace(‘my’, ‘../application/extend/my/’);

可以二维数组添加和入口文件 ROOT_name

12.自动加载

所以类库采用自动加载机制think\Loader类库:

1.类库映射检测

2.PSR-4自动加载检测

3.PSR-0自动加载检测

behavior 系统行为类库

think 核心基类库

traits 系统Traits类库

app 应用类库

13.Traits引入

trait功能来作为一种扩展机制,可以方便的实现一个类库的多继承问题。

trait是一种为类似PHP的单继承语言二准备的代码复用机制。trait为了减少单继承语言的限制,使开发人员能够自由地在不同层次结构内独立的类中复用方法集。

namespace app\index\controller;

load_trait(‘controller/Jump’);

class index

{

​ use \traits\controller\Jump;

​ public function index()

​ {

​ $this->assign(‘name’, ‘value’);

​ $this->show(‘index’);

​ }

}

二.配置

1.配置目录

系统默认的配置文件目录就是应用目录(APP_PAATH),也就是默认的application下面

在入口文件中定义独立的配置目录,添加CONF_PATH常量定义即可:

define(‘CONF_PATH’, DIR . ‘/../config/’);

2.配置格式

php数组定义, 其他配置格式支持, ini, xml, json

define(‘CONF_EXT’, ‘.ini’);

3.配置加载

惯例配置->应用配置->扩展配置->场景配置->模块配置->动态配置

1)惯例配置

thinkphp/convention.php

2)应用配置

application/config.php

3)扩展配置

由extra_config_list配置参数定义的额外的配置文件,默认会加载database和validate两个配置文件

4)场景配置 (公司和家里分别设置不同的数据库测试环境)

‘app_status’ =>’office’ 公司环境

‘app_status’=>’home’

5)模块配置

每个模块会自动加载自己的配置文件 application/当前模块名/config.php

6)加载配置文件

Config::load(‘配置文件名’);

完整目录名: Config::load(APP_PATH.’config/config.php’);

解析其他格式:

Config::parse(APP_PATH.’my_config.ini’, ‘ini’);

4.读取配置

dump(‘Config::get’);

5.动态配置

Config::set(‘配置参数’, ‘配置值’);

6.独立配置

只需要公共配置文件配置extra_config_list参数

‘extra_config_list’ => [‘database’] database.php自定义数据库配置

如果配置了extra_config_list参数,并同时在config.php和database.php文件中配置的话,则database.php文件的配置会覆盖config.php中的设置。

自动读取扩展配置

只需要将扩展配置文件放入application/extra目录

7.配置作用域

配置参数支持作用域的概念,默认情况下,所有参数都在同一个系统默认作用域下面,如果你的配置参数需要用于不同的项目或者项目隔离,那么久可以使用作用域功能,作用域的作用好比是配置参数的命名空间一样

Config::load(‘my_config.php’, ”, ‘user’);

导入my_config.php中的配置参数,并纳入user作用域

3.路由

1.路由模式

1)普通模式

关闭路由,完全使用默认的PATH_INFO方式URL:

‘url_route_on’ => false;

http://serverName/index.php/module/controller/action/param/value/

设置url_param_type配置参数来改便pathinfo模式下面的获取方式

‘url_param_type’ => 1;

2)混合模式

‘url_route_on’ =>true, url_route_must = > false

只需要对需要定义路由规则的访问地址定义路由规则,其他的仍让按照第一种普通模式PATH_INFO模式访问URL

3)强制模式

开启路由,并设置必须定义路由才能访问:

‘url_route_on’ => true,

‘url_route_must’ => true,

这种方式下面必须严格给每个访问地址定义路由规则(包括首页),否则将跑出异常!

2.路由定义

1)动态注册

路由定义采用\think\Route类的rule方法注册,通常是在应用的路由配置文件appplication/route.php进行注册

Route::rule(‘路由表达式’, ‘路由地址’,’请求类型’,’路由参数(数组)’,’变量规则(数组)’);

use think\Route;

Route::rule(‘new/:id’, ‘index/News/read’); (new代表index/News/read :id加上参数id)

http://serverName/new/5 http://serverName/index/news/read/id/5

Route::rule([‘new’, ‘new/:id’], ‘index/News/read’);

Route::get(‘new/;id’, ‘News/read’);

Route::post(‘new/:id’, ‘News/update’);

Route::rule(‘new/:id’, ‘News/read’, ‘GET|POST’);

2)可选定义

’blog/:year/[:month]‘ =>’Blog/archives’

3)完全匹配

’new/:cate$‘ => ‘News/category’

http://serverName/index.php/new/info ok http://serName/index.php/new/info/2 fail

route_complete_match => true;完全匹配

4)额外参数

在路由跳转的时候支持额外传入参数对(额外参数指的是不在URL里面的参数,饮食传入需要的操作中,又是后能够起到一定的安全防护作用。)

‘blog/:id’ =>’blog/read?status=1&app_id=5’

3.MISS路由

如果希望在没有匹配到所有的路由规则后执行一条设定的路由,可以使用MISS路由功能

___miss___’ => ‘public/miss’

Route::miss(‘public/miss’);

Route::group('blog',function(){    Route::rule(':id','blog/read',[],['id'=>'\d+']);    Route::rule(':name','blog/read',[],['name'=>'\w+']);    Route::miss('blog/miss');},['method'=>'get','ext'=>'html']);

4.URL生成

支持路由URL地址的同一生成,并且支持所有的路由方式,一级完美解决了卤藕地址的反转解析,无需再为路由定义和变化而改变URL生成。

Route::rule(‘blog/:id’, ‘index/blog/read’);

url(‘index/blog/read’, ‘id=5&name=thinkphp’);

5.绑定模型(路由参数)

路由规则和分组支持绑定模型数据,例如:

Route::rule(‘hello/:id’, ‘index/index/hello’, ‘GET’,

[‘ext’ => ‘html’, ‘bind_model’ =>[‘user’] => ‘/app/index/model/User’]);

Route::rul(‘hello/:id’, ‘index/index/hello’, ‘GET’,

[‘ext’ => ‘html’, ‘bind_model’ =>[‘user’ => function($param){

​ $model = new \app\index\model\User;

return $model->where($param)->find();

}]]);

6.闭包支持

使用闭包的方式定义一些特殊需求的路由,不需要执行控制器的操作方法

Route::get(‘hello’, function(){

​ return ‘helllo, world’;

});

参数传递:

Route::get(‘hello/:name’, function($name){

​ return ‘hello’.$name;

});

http://serverName/hello/thinkphp;

7.变量规则(路由变量规则动态)

支持在规则路由中为变量用正则的方式指定变量规则,弥补了动态变量无法限制具体的类型问题,并且支持全局规则设置。

全局变量规则

Route::pattern(‘name’, ‘\w+’);

Route::pattern([

​ ‘name’ => ‘\w+’,

​ ‘id’ => ‘\d+s’

]);

局部变量规则

Route::get(‘new/:name’, ‘News/read’, [], [‘name’ => ‘\w+’]);

8.快捷路由

允许你快速给控制器注册路由,并且针对不同的请求类型可以设置方法前缀

Route::controller(‘user’, ‘index/User’);

namespace app\index\controller;

class User {

​ public function getInfo(){}

​ public function getPhone(){}

​ public function postInfo(){}

​ public function pustInfo(){}

}

通过下面的URL访问

http://localhost/user/info get

http://localhost/user/phone get

htpp://localhost/user/info post

9.路由绑定

1绑定到模块/模块/控制器/操作

Route::bind(‘index/blogs’);

假如我们绑定了index模块的blog控制器

http://serverName/index/blog/read/id/5

可以简化成

http://serName/read/id/5

2定义路由

Route::get(‘index/blog/:id’, ‘index/blog/read’); ?

http://serverName/5

3绑定到命名空间

Route::bind(‘\app\index\controller’, ‘namespace’);

http://serverName/blog/read/id/5

4绑定到类

Route::bind(‘\app\index\controller\Blog’, ‘class’);

http://serverName/read/id/5

入口文件绑定

1常量定义

入口文件添加BIND_MODULE

define(‘BIND_MODULE’, ‘index’);

2自动入口绑定

你的入口文件都是对应实际的模块名,那么可以使用入口文件自动绑定模块的功能,只需要在应用配置文件中添加:

‘auto_bind_module’ => true;

重新添加一个public/demo.php入口文件,内容和public/index.php一样

define('APP_PATH', __DIR__ . '/../application/');// 加载框架引导文件require __DIR__ . '/../thinkphp/start.php';

访问1demo.php的时候,自动绑定到了demo模块

10路由别名

路由别名功能可以使用一条规则,批量定义一系列的路由规则

Route::alias(‘user’, ‘index/User’);

在路由配置文件route.php中定义的话,使用:

return [

'__alias__' => [

​ ‘user’ => ‘index/User’]

]

http://serverName/index.php/user/add

http://serverName/index.php/user/edit/id/5

路由别名不支持变量类型和路由条件判断,单纯只是为了缩短URL地址,并且在定义的时候需要注意避免和路由规则产生混淆。

Route::alias(‘user’, ‘index/user’, [‘ext’ => ‘html’]);

操作方法黑白名单

Route::alias(‘user’, ‘index/user’, [‘ext’ => ‘html’, ‘allow’ => ‘index, read, edit, delete’, ‘method’ => [‘index’ => ‘GET’, ‘save’ => ‘POST’]]);

Route::alias(‘user’, ‘index/user’, [‘ext’ => ‘html’, ‘except’ => ‘save, delete’]);

11.路由参数

method 请求类型检测,支持多个请求类型

ext URL后缀检测,支持匹配多个后缀

deny_ext URL禁止后缀检测,支持匹配多个后缀

https 检测是否https请求

domian 域名检测

before_behavior 前置行为

after_behavior 后置行为

callback 自定义检测方法

merge_extra_vars 合并额外参数

bind_model 绑定模型

cache 请求缓存

param_depr 路由参数分隔符

ajax Ajax检测

pjax Pjax检测

1请求类型

指定请求类型注册路由的话,无需设置method请求类型参数。如果使用了rule或者any方法注册路由,或者使用路由配置定义文件的话,可以单独使用method参数进行请求类型检测。

Route::any(‘new/:id’, ‘News/read’, [‘method’=>’get|post’]);

2URL后缀

Route::get(‘new/:id’, ‘News/read’, [‘ext’=>’html’]);

3域名检测

Route::get(‘new/:id’, ‘News/read’, [‘domain’=>’news.thinkphp.cn’]);

4HTTPS检测

Route::get(‘new/:id’, ‘News/read’, [‘https’=>true]);

5前置行为检测

支持使用行为对路由进行检测是否匹配,如果行为方法返回false表示当前路由规则无效

Route::get(‘user/id’, ‘index/User/read’, [‘before_behavior’=>’\app\index\behavior\UserCheck’]);

namespace app\index\behavior

class UserCheck

{

​ public function run()

​ {

​ if (‘user/0’ == request(0->url())){

​ return false;

​ }

​ }

}

6后置行为

可以为某个路由或者某个分组路由定义后置行为执行,表示当路由匹配成功后,执行的行为,例如:

​ Route::get(‘user/;id’, ‘User/read’, [after_behavior => ‘\app\index\behavior\ReadInfo’]);

namespace app\index\behavior

use app\index\model\User;

class ReadInfo

{

​ public function run(){

​ $id = request()->route(‘id’);

​ request()->user = User::get($id);

}

}

7Callback检测

支持使用函数检测路由,如果函数返回false表示当前路由规则无效

Route::get(‘new/:id’, ‘News/read’,[‘callback’=>’my_check_fun’]);

8合并额外参数

Route::get(‘new/:name$’, ‘News/read’, [‘merge_extra_vars’=>true]);

9配置文件中添加路由参数

return [‘blog/:id’=>[‘Blog/update’, [‘method’=>’post’, ‘ext’=>’html|shtml’]]];

10路由绑定模型

Route::get(‘new/:name$’, ‘News/read’, [‘bind_model’=>[‘user’, ‘name’]]);

11缓存路由请求

Route::get(‘new/:name$’, ‘News/read’, [‘cache’=>3600]);当前路由请求缓存3600秒

12.路由地址

方式1:路由到模块/控制器

方式2:路由到重定向地址 默认(301重定向)

方式3:路由到控制器 @[模块/控制器/操作]

方式4:路由到类的方法 \完整的命名空间类::静态方法

方式5:路由到闭包函数 闭包函数定义

路由到模块/控制器/操作

‘blog/:id’ =>’blog/read’,

‘blog/:id’ =>’index/blog/read’

‘blog/:id’ => ‘index/group.blog/read’

namespace app\index\controler\group;

class Blog

{

​ public function read($id)

​ {

​ return ‘read’.$id;

​ }

}

路由到操作方法

@[模块/控制器/]操作

‘blog/:id’ =>’@index/blog/read’;

Loader::action(‘index/blog/read’);

路由到类的方法

\类的命名空间\类名@方法名

\类的命名空间\类名::方法名

‘blog/:id’ => ‘\app\index\service\Blog@read’

路由到重定向地址

重定向的外部地址必须以’/’或者http开头的地址

如果路由地址以‘/’或者http开头则会认为是一个重定向地址或者外部地址

‘blog/:id’ =>’/blog/read/id/:id’

‘blog/:id’ =>’blog/read’

虽然都是路由到同一地址,但是前者采用的是301重定向的方式路由跳转,这种方式的好处是URL可以比较随意(包括可以在URL里面传入更多的非标准格式的参数)后者只是支持模块和操作地址

/member/avatar/id/123_small的话,只能使用:

’avator/:id‘ =>’/member/avator/id/:id_small’

路由地址采用重定向地址的话,如果要引用动态变量,直接使用动态变量

’blog/:id‘ =>’http://blog.thinkphp.cn/read/:id

13.路由分组

Route::group([‘method’=>’get’, ‘ext’=>’html’], function(){

​ Route::group(‘blog’, function(){

​ Route::rule(‘blog/:id’, ‘blog/read’, [],[‘id’=>’\d+’]);

​ Route::rule(‘blog/:name’, ‘blog/read’, [], [‘name’=>’\w+’]);

}

});

14.批量注册

1批量注册

Route::rule(['路由规则1'=>'路由地址和参数','路由规则2'=>['路由地址和参数','匹配参数(数组)','变量规则(数组)']...],'','请求类型','匹配参数(数组)','变量规则');

2定义路由配置文件

use think\Route;Route::rule('hello/:name','index/index/hello');return [    'new/:id'   => 'News/read',    'blog/:id'   => ['Blog/update',['method' => 'post|put'], ['id' => '\d+']],];

15.域名路由

thinkphp支持完整域名,子域名和IP部署的路由和绑定功能,简化URL

‘url_domain_deploy’ => true

1动态注册

Route::domain(‘blog’, ‘blog’);

Route::domain(‘admin.thinkphp.cn’, ‘admin’);

Route::domain(‘114.23.4.5’, ‘admin’);

1)blog子域名绑定后,URL访问规则变成

http://www.thinkphp.cn/blog/article/read/id/5 //原来的URL访问

http://blog.thinkphp.cn/article/read/id/5 //绑定到blog子域名访问

支持绑定的时候添加默认参数

Route::domain(‘blog’, ‘blog?var=thinkphp’);

2)支持直接绑定到控制器

Route::domain(‘blog’, ‘index/blog’);

http://www.thinkphp.cn/index/blog/read/id//5 //原来的URL访问

http://blog.thinkphp.cn/read/id/5 //绑定到blog子域名访问

如果域名后缀比较特殊,例如是com.cn后者是net.cn之类的域名,需要配置

‘url_domain_root’ => ‘thinkphp.com.cn’

泛域名部署

Route::domain('*', 'book?name=*');

http://hello.thinkphp.cn

http://quickstart.thinkphp.cn

直接通过$_GET[‘name’]获取当前的泛域名

Route::domain('*.user', 'user?name=*');

http://hello.user.thinkphp.cn

3)配置定义方式

return [

'__domain'=> [

​ ‘blog’ => ‘blog’,

​ ‘*.user’ => ‘user’,

​ ‘*’ => ‘book’

]

]

4)绑定到命名空间

Route::domain(‘blog’, ‘\app\blog\controller’);

5)绑定到类

Route::domain(‘blog’, ‘@\app\blog\controller\Article’);

6)绑定到闭包函数

Route::domain(‘blog’, function(){

​ echo ‘hello’;

​ return [‘bind’=>’module’, ‘module’ => ‘blog’]

});

16.资源路由

Route::resource(‘blog’, ‘index/blog’);

路由配置文件

return [

'__rest__' =>[

​ ‘blog’ => ‘index/blog’

],

​ ‘hello/:id’ => ‘index/hello’

]

设置后会自动注册7个路由规则

标识 请求类型 生成路由规则 对应操作方法

index GET blog index

create GET blog/create create

save POST blog save

read GET blog/:id read

edit GET blog/:id/edit edit

update PUT blog/:id update

delete DELETE blog/:id delete

namespace app\index\controller

class Blog{

​ public function index(){}

​ public function read($id){}

​ public function edit($id){}

}

Route::resource(‘blog’, ‘index/blog’, [‘var’=>[‘blog’=>’blog_id’]]); //改变默认的id参数名

namespace app\index\controller;

class Blog{

​ public function index(){}

​ public function read($blog_id){}

​ public function edit($blog_id){}

}

也可以定义资源路由的时候限定执行的方法

Route::resource(‘blog’, ‘index/blog’, [‘only’=>[‘index’, ‘read’, ‘edit’, ‘update’]]);

Route::resource(‘blog’, ‘index/blog’, [‘except’=>[‘index’, ‘delete’]]);

需要更改某个资源路由标识的对应操作

Route::rest(‘create’, [‘GET’, ‘/add’, ‘add’]);

http://serverName/blog/create 变成 http://serverName/blog/add

批量更改

Route::rest([

​ ‘save’ => [‘POST’, ”, ‘store’],

​ ‘update’ => [‘PUT’, ‘/:id’, ‘save’],

​ ‘delete’ => [‘DELETE’, ‘/:id’, ‘destory’]

]);

4.控制器

1控制器定义

ThinkPHP V5.0的控制器定义比较灵活,可以无需继承任何的基础类,继承官方封装的\think\Controller类

1)控制器定义

namespace app\index\controller;

class Index

{

​ public function index()

​ {

​ return ‘index’;

​ }

}

应用配置文件

‘app_namespace’ => ‘application’

2)控制器使用渲染模版

namespace app\index\controller; //方式1

user think\view;

class Index

{

​ public function index()

​ {

​ $view = new View();

​ return $view->fetch(‘index’);

​ }

}

namespace app\index\controller;

class Index

{

​ public function index()

​ {

​ return view(‘index’); //使用了view助手函数渲染模版, 不需要use think/View;

​ }

}

如果继承了think\Controller类,可以直接调用think\View及think\Request类方法

namespace app\index\controller;

use think\Controller;

class Index extends Controller

{

​ public function index()

​ {

$this->assign('domain', $$this->request->url(true));

​ return `$this->fetch('index');

​ }

}

渲染输出:输出采用return的方式

输出转换:配置文件’default_return_type’ => ‘json’;

2.控制器初始化

如果控制器类继承了\think\Controller类,可以定义控制器初始化方法_initialize

namespace app\index\controller;

use think\controller;

class Index extends Controller

{

​ public function _initialize()

​ {

​ echo ‘init’

​ }

​ public function hello(){}

}

3.前置操作

可以为某个或者某些操作指定前置执行的操作方法,设置beforeActionList属性

namespace app\index\controller;

use think\Controller;

class Index extends Controller

{

​ protected $beforeActionList = [

​ ‘first’,

​ ‘second’ => [‘except’ =>’hello’],

​ ‘threee’ => [‘only’ =>’hello, data’]

​ ];

​ protected function first()

​ {

​ echo ‘first’;

​ }

​ protected function second()

​ {

​ echo ‘second’;

​ }

​ protected function three()

​ {

​ echo ‘three’;

​ }

​ public function hello()

​ {

​ return ‘hello’;

​ }

​ public function data()

​ {

​ return ‘data’;

​ }

}

http://localhost/index.php/index/Index/hello; first three hello

http://localhost/index.php/index/index/data; first second three data

4.跳转和重定向

1页面跳转

操作成功或者操作错误页面

think\Controller success和error

namespace app\index\controller;

use think\Controller;

use app\index\model\User;

class Index extends Controller

{

​ public function index()

​ {

​ $user = new User;

$result = $User->save($data);

if($result) { $this->success('新增成功', 'User/list'); } //默认的返回页面是$_SERVER['HTTP_REFERER']

​ else {

​ $this->error(‘新增失败’); } //错误跳转页面是返回前一页

​ }

}

所在的模版

’dispatch_error_tmpl‘ => APP_PATH.’tpl/dispathch_jump.tpl’,

‘dispatch_success_tmpl’ => APP_PATH.’tp;/dispatch_jump.tpl’

使用项目内部的模版文件

‘dispatch_error_tmpl’ => ‘public/error’,

‘dispatch_success_tmpl’ =>’public/success’

模版文件可以使用模版标签,并且可以使用下面的模版变量

$data 要返回的数据

$msg 页面提示信息

$code 返回的code

$wait 跳转等待时间 单位为秒

$url 跳转页面地址

error方法会自动判断当前请求是否属于Ajax请求,如果属于Ajax请求则会自动转换为default_ajax_return配置的格式返回信息。success在Ajax请求下不返回信息,需要开发者自行处理

2重定向

\think\Controller’类redirect方法

$this->redirect(‘News/category’, [‘cate_id’ =>2]);

直接重定向到一个指定的外部URL地址

$this->redirect(‘http://thinkphp.cn/blog/2‘, 302);

4.空操作

系统在找不到指定的操作方法的时候,会定位到空操作(_empty)方法

实现错误页面和URL的优化

4.空控制器

当系统找不到指定的控制器名称的时候,系统会尝试定位空控制器(Error)

7.多级控制器

多级控制器在命名空间下玩法

namespace app\index\controller\one;

use think\Controller;

class Blog extends Controller

{

​ public function index()

​ {

​ return $this->fetch();

​ }

​ public function add()

​ {

​ return $this->fetch();

​ }

​ public function edit($id)

​ {

​ return $this->fetch();

​ }

}

http://serverName/index.php/index/one.blog/index

\think\Route::get(‘blog/add’, ‘index/one.blog/add’);

8.分层控制器

通过URL访问的控制器为访问控制器层或者主控制器,访问控制器是有\think\APP负责调用和实例化

定义其他分层控制器类,这些分层控制器是不能够被URL访问直接调用的,只能在访问控制器,模型类的内部或者视图模版文件中进行调用。

namespace app\index\event;

class Blog

{

​ public function insert()

​ {

​ return ‘insert’;

​ }

​ public function update($id)

​ {

​ return ‘update’.$id;

​ }

​ public function delete($id)

​ {

​ return ‘delete’.$id;

​ }

}

定义完成后,就可以用下面方式实例化并调用方法

$event = \think\Loader::controller(‘Blog’, ‘event’); //方式1

echo $event->update(5);

$event = controller(‘Blog’, ‘event’); //方式2 助手函数controller

echo $event->update(5);

$event = controller(‘Admin/Blog’, ‘event’); 扩模块调用

echo $event->update(5);

echo \think\Loader::action(‘Blog/update’, [‘id’=>5], ‘event’); //直接调用

echo action(‘Blog/update’, [‘id’=>5], ‘event’); 助手函数action

通过action等等方法来实习controller功能实习

9.自动地位控制器

如果你使用了多级控制器的话,可以设置controller_auto_search参数开启自动定位控制器,便于URL访问 (不用修改命名空间)

‘controller_auto_search’ =>true;

namespace app\index\controller\one;

use think\Controller;

class Blog extends Controller

{

​ public function index()

​ {

​ return $this->fetch();

​ }

​ public function add()

​ {

​ return $this->fetch();

​ }

​ public function edit($id)

​ {

return $this->fetch('edit'.$id);

​ }

}

http://serverName/index.php/index/one/Blog;

http://serverName/index.php/index/one.Blog;

10.Rest控制器

RESTFul方法和标准模式的操作方法主要区别在于,需要对请求类型和资源类型进行判断,通过路由定义可以把操作方法绑定到某个请求类型(get|post|delete)和资源类型(xml,json,html)

11.资源控制器

轻松的创建RESTFul资源控制器,通过命令行生成需要的资源控制器

php think make:controller index/Blog

php think make:controller app\index\controller\Blog

为资源控制器注册一个资源路由

Route::resource(‘blog’, ‘index/Blog’);

5.请求

1请求信息

获取当前的请求信息,可以使用\think\Request类

$request = Request::instance();

$request = request(); //使用助手函数

1)获取URL信息

$request = Request::instance();

echo ‘domain: ‘.$request->domain(); //获取当前域名 http://tp5.com

echo ‘file’.$request->baseFile(); //获取当前入口文件 /index.php

echo ‘url:’.$request->url(); ///获取当前URL地址

/index/index/hello.html?name = thinkphp

echo ‘url with domain’. $request->url(true); //获取包含域名的完整URL地址

http://tp5.com/index/index/hello.html?name=thinkphp

echo ‘url without query’. $request->baseUrl(); //获取当前URL地址,不含QUERY_STRING(查询参数)

/index/index/hello.html

echo ‘root’.$request->root(); //获取URL访问的ROOT地址 root:

echo ‘root with domain’.$request->root(true); //获取URL地址的root地址

http://tp5.com

echo ‘pathinfo’.$request->pathinfo(); //获取URL地址中的PATH_INFO信息

pathinfo: index/index/hello.html

echo ‘pathinfo:’.$request->path(); //获取URL地址的PATH_INFO信息 不含后缀

pathinfo: index/index/hello

echo ‘ext’. $request->ext(); //获取URL地址中的后缀信息

html

2)设置/获取 模块/控制器/操作名称

$request = Request::instance();

echo ‘当前模块名称是’.$request->module(); //index

echo ‘当前控制器名称是’.$request->controller(); //HelloWorld

echo ‘当前操作名称是:’.$request->action(); //index

设置模块名称需要向module方法中传入名称即可,同样适用于设置控制器名称和操作名称

Request::instance()->module(‘module_name’);

获取请求参数

$request = Request::instance();

echo ‘请求方法’.$request->method(); GET

echo ‘资源类型’.$request->type(); html

echo ‘访问地址’.$request->ip(); 127.0.0.1

echo ‘是否Ajax请求’.var_export($request->isAjax(), true); false

echo ‘请求参数:’

dump($request->param());

array (size = 2)

​ ‘test’ => string ‘ddd’ (length=3)

​ ‘name’=>string’thinkphp’ (length=8)

echo ‘请求参数:仅包含name’;

dump($request->only([‘name’]));

array (size = 1)

​ ‘name’ => string ‘thinkphp’(length=8)

echo ‘请求参数:排除name’

dump($request->except([‘name’]));

array(size = 1)

​ ‘test’ =>string’ddd’(length=3 )

3)获取路由和调度信息

$request = Request::instance();

echo ‘路由信息’

dump($request->route());

array(size = 4)

​ ‘rule’ =>string ‘hello/:name’ (length=11)

​ ‘route’ =>string ‘index/hello’ (length=11)

​ ‘parttern’ =>

​ array(size=1)

​ ‘name’ => string ‘\w+’(length=3)

​ ‘option’ => array(size=0)

​ empty

echo ‘调度信息’

dump($request->dispathch());

array

​ ‘type’ => string ‘module’(length=6)

​ ‘module’ => array(size=3)

​ 0 => null,

​ 1 => string ‘index’,

    2 => string 'hello'

路由定义为

return [

​ ‘hello/:name’ => [‘index/hello’], [], [‘name’ => ‘\w+’]

];

http://serverName/hello/thinkphp

设置请求信息

$request = Request::instance();

$request->root(‘index.php’);

$request->pathinfo(‘index/index/hello’);

2.输入变量

通过Request对象完成全局输入变量的检测,获取和安全过滤,支持包括

$_GET, $_POST, $REQUEST, $_SERVER, $_SESSION, $_COOKIE,$_ENV等系统变量

1)检测变量是否设置

Request::instance()->has(‘id’, ‘get’);

Request::instance()->has(‘name’, ‘post’);

input(‘?get.id’);

input(‘?post.name’);

2)变量获取

使用\think\Request类的如下方法及参数

变量类型方法(’变量名/变量修饰符’, ‘默认值’, ‘过滤方法’)

变量类型方法包括:

方法 描述

param 获取当前请求的变量

get 获取$_GET变量

post 获取$_POST变量

put 获取PUT变量

delete 获取DELETE变量

session 获取$_SESSION变量

cookie 获取$_COOKIE变量

request 获取$_REQUEST变量

server 获取$_SERVER变量

env 获取$_ENV变量

route 获取路由(PATHINFO)变量

file 获取$_FILES变量

获取PARAM变量

Request::instance()->param(‘name’);

Request::Instance()->param();

Request::instance()->param(false); //获取当前请求的所有变量(原始数据)

Request::instance()->param(true); //获取当前请求的所有变量(包含上传文件)

助手函数实现

input(‘param.name’);

input(‘param’);

或者

input(‘name’);

input(”);

获取GET变量,获取POST变量,获取PUT变量,获取REQUEST变量,获取SERVER变量

Request::instance()->get(‘id’);

input(‘get.id’);

input(‘post.name’);

input(‘put.name’);

input(‘request’);

input(‘server.PHP_SELF’);

获取SESSION变量,获取Cookie变量

input(‘session.user_id’);

input(‘cookie.user_id’);

变量过滤

框架默认没有设置任何过滤规则,配置文件中设置全局的过滤规则

‘default_filter’ => ‘htmlspecialchars’,

支持使用Request对象进行全局变量的获取过滤,过滤方式包括函数,方法过滤,

以及PHP内置的Types of filters,我们可以设置全局变量过滤方法

Request::instance()->filter(‘htmlspecialchars’);

Request::instance()->filter([‘strip_tags’, ‘htmlspecialchars’]);

可以在获取变量的时候添加过滤方法

Request::instance()->get(‘name’, ”, ‘htmlspecialchars’);

//获取get变量,并用htmlspecialchars函数过滤

Request::instance()->param(‘usename’, ”, ‘org\Filter::safeHtml’);

//获取post变量 并用org\Filter类的safeHtml方法过滤

Request::instance()->param(‘useraname’, ”, ‘strip_tags, strlower’);

获取部分变量

Request::instance()->only(‘id, name’);

排除部分变量

Request::instance()->except(‘id, name’);

变量修饰符

input(‘变量类型.变量名/修饰符’);

input(‘get.id/d’);

input(‘post.name/s’);

修饰符 作用

s 强制转换为字符串类型

d 强制转换为整形类型

b 强制转换为布尔类型

a 强制转换为数组类型

f 强制转换为浮点类型

3.更改变量

Request::instance()->get([‘id’=>10]); //更改GET变量

4.请求类型

需要判断当前操作类型GET,POST,PUT,DELETE,HEAD

if (Request::instance()->isGet()) //是否为GET请求

if (Request::instance()->isPost) //是否为post请求

if (request()->isGet()) //当前位GET请求

5.请求伪装

1)请求类型伪装

支持请求类型伪装,在POST表单里面提交_method变量,

​ ​ ​

修改应用配置文件

‘var_method’ => ‘_m’

AJAX或PJAX伪装

http://localhost/index?_ajax=1

http://localhost/index?_pjax=1

修改应用配置文件

‘var_ajax’ => ‘_a’,

‘var_pjax’ => ‘_p’

6.HTTP头信息

$info = Request::instance()->header();

echo $info[‘accept’]

echo $info[‘accept-encoding’]

echo $info[‘user-agent’]

获取某个请求头信息

$agent = Request::instance()->header(‘user-agent’);

7.伪静态

URL伪静态为了更好的SEO效果,thinkphp支持伪静态URL设置,通过设置url_html_suffix参数

‘url_html_suffix’ => ‘shtml’

$ext = Request::instance()->ext(); //获取伪静态后置

关闭伪静态

‘url_html_suffix’ =>false;

关闭伪静态访问后,不在支持伪静态方式的URL访问,并且伪静态后缀将会被解析为最后一个参数的值

http://serverName/index/blog/read/id/3.html;

8.方法注入

在Request请求对象中添加自己的方法,可以使用Request对象的方法

Request::hook(‘user’, ‘getUserInfo’);

function getUserInfo(Request $request, $userId)

​ return $info;

控制器中使用:

public function index()

{

$info = Request::instance()->user($userid);

}

9.属性注入

可以动态注入当前Request对象的属性:

Request::instance()->bind(‘user’, new User);

Request::instance()->user = new User;

Request::instance()->user;

如果控制器请求对象的话,也可以直接使用

$this->request->user;

request()->user;

10.参数绑定

方法参数绑定是把URL地址(或者路由地址)中的变量作为操作方法的参数直接传入。

1)参数绑定方式默认是按照变量名进行绑定

namespace app\index\Controller;

class Blog

{

​ public function read($id)

​ {

​ return ‘id=’.$id;

​ }

public function archive($year='2016', $moth='01');

​ {

return 'year='.$year.'$moth='.$month;

​ }

}

http://serverName/index.php/index/blog/read

添加默认参数减少错误

2)按顺序绑定

‘url_param_type’ =>1

http://serverName/index.php/index/blog/archive/06/2016;

id=5

year=06&month=2016

注意

按顺序绑定参数的话,操作方法的参数智能使用URL pathinfo变量,而不能使用get或者post变量

参数绑定有一个特例,如果你的操作方法中定义有Request对象作为参数的话,无论参数位置在哪里,都会自动注入,而不需要进行参数绑定

3)架构方法参数绑定

可以对架构函数进行参数绑定,当前请求的路由变量可以自动绑定到架构函数的参数

namespace app\index\Controller

class Blog

{

​ protected $name;

​ public function __construct($name = null)

​ {

​ $this->name = name

​ }

}

如果访问

http://localhost/index/index/index/name/thinkphp

当前请求的路由变量name的值thinkphp会自动传入架构方法的name变量

11.依赖注入

Thinkphp的依赖注入(控制反转)一种较为轻量的实现,无需任何的配置,并且主要针对访问控制器进行依赖注入。可以在控制器的构造函数或者操作方法(访问请求的方法)中类型声明任何(对象对象)依赖,这些依赖会被自动解析并注入到控制器实例或方法中。

1)在控制器的加过方法中会自动注入当前请求对象:

namespace app\index\controller;

use think\Request;

class Index

{

​ protected $request;

​ public function __construct(Request $request)

​ {

$this->request = $request;

​ }

}

2)操作方法注入

控制器的操作方法中如果需要调用请求对象Request的话,可以在方法中定义Request类型的参数

namespace app\index\controller;

use think\Request;

class Index

{

​ public function hello(Request $request)

​ {

​ return ‘hello’.$request->param(‘name’);

​ }

}

访问URL地址的时候无需传入Request参数,系统会自动注入当前的Request对象实例到该参数

如果继承了系统的Controller类的话,也可以直接调用request属性

12.请求缓存

1)路由参数:

可以在路由规则里面定义cache参数开启当前路由规则的请求缓存,例如:

Route::get(‘new/:id’, ‘News/read’, [‘cache’ => 3600]);

第二次访问相同的路由地址的时候,会自动获取请求缓存的数据响应输出,并发送304状态码

默认请求缓存的表示为当前访问的pathinfo地址,可以定义缓存的表示

Route::get(‘new/:id’, ‘News/read’, [

​ ‘cache’ => [‘new/:id/:page’, 3600]

]);

:id,:page表示使用当前请求的param参数进行动态表示替换,也就是根据id和page变量进行3600秒的请求缓存

2)动态设置

Request::instance()->cache(‘blog/:id’, 3600);

表示对blog/:id定义的动态访问地址进行3600秒的请求缓存

配置文件中开启

‘request_cache’ => true,

‘request_cache_expire’ => 3600

就会自动根据当前请求URL地址(只针对GET请求类型)进行请求缓存,全局缓存有效期为3600秒

6.数据库

1.连接数据库

Thinkphp内置了抽象数据库访问层,把不同的数据库操作封装起来,我们只需要使用公共DB类进行操作,而无需针对不同的数据库写不同的代码和底层实现,Db类会自动调用相应的数据库驱动来处理。采用PDO方式,目前包含了Mysql,SqlServer,pgSQL,Sqlite等数据库的支持

1)配置文件定义

在应用目录或模块目录下面的database.php

连接参数

针对不同的连接需要添加数据库的连接参数

PDO::ATTR_CASE =>PDO::CASE_NAURAL,

PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,

使用params参数的连接配置将会和内置的设置参数合并

‘params’ => [

​ \PDO::ATTR_PERSISTENT => true,

​ \PDO::ATTR_CASE => \PDO::LOWER

];

2)方法配置

调用Db类动态定义连接信息

Db::connect([

​ ‘type’ => ‘mysql’,

​ ‘dsn’ => ”,

​ ‘hostname’ => ‘127.0.0.1’,

​ …

]);

Db::connect(‘mysql://root:1234@127.0.0.1:3306/thinkphp#utf8’);

单一文件的应用配置文件

‘db_config1’ => [

​ ‘type’ => ‘mysql’,

​ ‘hostname’ => ‘127.0.0.1’,

​ …

]

Db::connect(‘db_config1’);

3)模型类定义

在某个模型类里面定义了connection属性的话,则该模型操作的时候会自动连接给定的数据库连接,而不是配置文件中设置的默认连接信息

namespace app\index\model;

use think\Model;

class User extends Model

{

​ protected $connection = [

​ ‘type’ => ‘mysql’,

​ ‘dsn’ => ”,

​ ‘hostname’ => ‘127.0.0.1’,

​ …

];

}

字符串定义

protected $connection = ‘mysql://root:1234@127.0.0.1:3306/thinkphp#utf8’

配置参数参考

type 数据库类型

hostname 数据库地址

database 数据库名称

username 数据库用户名

password 数据库密码

hostport 数据库端口号

dsn 数据库连接dsn信息

params 数据库连接参数

charset 数据库编码

prefix 数据库的表前缀

debug 是否调试模式

deploy 数据库部署方式:0集中式1分布式(主从服务器)

rw_separate 数据库读写是否分离

master_num 读写分离后 主服务器数量

slave_no 指定从服务器序号

fields_strice 是否严格检查字段是否存在

resultset_type 数据集放回类型

auto_timestamp 自动写入时间戳字段

sql_explain 是否需要进行SQL性能分析 开启调试有效

query 指定查询对象

builder 指定数据库Builder对象

如果是使用pgsql数据驱动的话,

请先导入thinkphp/library/think/db/connector/pgsql.sql

2.基本使用

配置了数据库连接信息后,使用数据库运行原生SQL操作,支持了query(查询操作)

execute(写入操作)

Db::query(‘select * from think_user where id=?’, [8]);

Db::excute(‘insert into think_user (id, name) values(?, ?)’, [9, ‘thinkphp’]);

命名占位符

Db::query(‘select * from think_user where id =:id’, [‘id’=>8]);

Db::execute(‘insert into think_user(id, name) values(:id, :name)’, [‘id’=>8, ‘name’=> ‘thinkphp’]);

3查询构造

1.查询方法

条件查询方法

where方法

Db::table(‘think_user’)

​ ->where(‘name’, ‘like’, ‘$thinkphp’)

​ ->where(‘status’, 1);

​ ->find();

多字段相同条件的AND查询

Db::table(‘think_user’)

​ ->where(‘name&title’, ‘like’, ‘$thinkphp’)

​ ->find();

whereOr方法进行OR查询

Db::table(‘think_user’)

​ ->whereor(‘title’, ‘like’, ‘%thinkphp’)

​ ->find();

多字段相同条件的or查询

Db::table(‘think_user’)

​ ->where(‘name|title’, ‘like’, ‘$thinkphp’)

​ ->find();

混合查询

$result = Db::table('think_user')->where(function($query){

$query->where(‘id’, 1)->whereor(‘id’, 2);

})->whereOr(function($query){

​ $query->where(‘name’, ‘like’, ‘think’)->whereOr(‘name’, ‘like’, ‘thinkphp’)

})->select();

生成语句:

select * from ‘think_user’ where (‘id’ = 1 OR ‘id’ = 2) OR (‘name’ like ‘think’ or ‘name’ like ‘thinkphp’)

getTableInfo方法

Db::getTableInfo(‘think_user’);

Db::getTableInfo(‘think_user’, ‘fields’);

Db::getTableInfo(‘think_user’, ‘type’);

Db::getTalbeInfo(‘think_user’, ‘pk’);

2.查询数据

基本查询

Db::table(‘think_user’)->where(‘id’, 1)->find(); //结果不存在,返回null

查询数据集

Db::table(‘think_user’)->where(‘status’, 1)->select();

如果设置了数据表前缀参数

Db::name(‘user’)->where(‘id’, 1)->find();

默认情况下,find和select方法返回的都是数组

助手函数

db(‘user’)->where(‘id’, 1)->find();

使用db助手函数默认每次都会重新连接数据库

而使用Db::name或者Db::table方法的话都是单例

使用Query对象和闭包查询

$query = new \think\db\Query();

$query->table(‘think_user’)->where(‘status’, 1);

Db::find($query);

Db::select($query);

闭包函数查询

Db::select(function($query){

​ $query->table(‘think_user’)->where(‘status’, 1);

});

值和列查询

查询某个字段的值 //查询结果不存在,返回null

DB::table(‘think_user’)->where(‘id’, 1)->value(‘name’); //返回某个字段的值

Db::table(‘think_user’)->where(‘status’, 1)->column(‘name’); //返回数组

Db::table(‘think_user’)->where(‘status’, 1)->column(‘name’, ‘id’); //指定索引

数据集分批处理

你需要处理成千上白条数据库记录,可以考虑使用chunk方法,方法一次获取结果集的一小块,然后填充每一小块数据到要处理的闭包。

我们可以全部用户表数据进行分批处理,每次处理100个用户记录:

Db::table(‘think_user’)->chunk(100, function($users){

foreach($users as $user)

} );

JSON类型数据查询

Db::table(‘think_user’)->where(‘info$.email’, ‘thinkphp@qq.com’)->find();

//查询JSON类型字段(info字段为json类型)

3.查询语法

查询表达式

where(‘字段’, ‘表达式’, ‘查询条件’);

表达式 含义

EQ, = 等于 where(‘id’, 100);

NEQ,<> 不等于 where(‘id’, ‘<>’, 100);

GT, > 大于 where(‘id’, ‘>’, 100);

EGT, >= 大于等于

LT, < 小于

ELT, <= 小于等于

LIKE 模糊查询 where(‘name’, ‘like’, ‘thinkphp%’);

BETWEEN 区间查询 where(‘id’, ‘between’, [1, 8]);

IN IN查询 where(‘id’, ‘not in’, [1, 5, 7]);

NULL 查询字段是否NULL

where(‘name’, null); where(‘name’, ‘not null’); //查询字段是否(不)是null

where(‘title’, ‘=’, ‘null’); //查询一个字段的值为字符串null或者not null

EXISTS EXISTS查询

EXP 表达式查询,支持SQL语法 where(‘id’, ‘exp’, ‘IN(1,3,8)’)

4.高级查询

1)快捷查询

一种多字段相同查询条件的简化写法,在多个字段之间用|分割表示or查询,

用&分割表示AND查询

DB::table(‘think_user’)

​ ->where(‘name|title’, ‘like’, ‘thinkphp%’);

​ ->where(‘create_time&update_time’, ‘>’, 0)

​ ->find();

Select * from ‘think_user’ where (‘name’ like ‘thinkphp%’ or ‘title’ like ‘thinkphp%’)

and (‘create_time’ > 0 and ‘update_time’ > 0) limit 1

2)区间查询

Db::table(‘think_user’)

​ ->where(‘name’, [‘like’, ‘thinkphp%’], [‘like’, ‘%thinkphp’])

​ ->where(‘id’, [‘>’, 0], [‘<>’, 10], ‘or’)

​ ->find();

select * from ‘think_user’ where (‘name’ like ‘thinkphp%’ and ‘name’ like ‘%thinkphp’) and (‘id’ > 0 or ‘id’ <> 10) limit 1

区间查询的查询条件必须使用数组定义方式

3)批量查询

Db::table(‘think_user’)

​ ->where([

​ ‘name’ => [‘like’, ‘thinkphp%’],

​ ‘title’ => [‘like’, ‘%thinkphp’],

​ ‘id’ => [‘>’, 0]

])->select();

4)闭包查询

Db::table(‘think_user’)->select(function($query){

​ $query->where(‘name’, ‘thinkphp’)

​ ->whereor(‘id’, ‘>’, 10)

});

5)使用Query对象查询

$query = new \think\db\Query;

$query->name(‘user’)

​ ->where(‘name’, ‘like’, ‘%think%’)

​ ->where(‘id’, ‘>’, 10)

​ ->limit(10);

Db::select($query);

5)字符串条件查询

Db::table(‘think_user’)

​ ->where(‘id > :id AND name like :name’, [‘id’=>0, ‘name’=>’thinkphp%’])

5.更新数据

1)更新数据表中的数据

Db::table(‘think_user’)

​ ->where(‘id’, 1)

​ ->update([‘name’=>’thinkphp’]);

如果数据中包含主键,可以直接使用

Db::table(‘think_user’)

​ ->update([‘name’=>’thinkphp’, ‘id’=>1]); //没有数据返回0

如果更新的数据需要使用SQL函数或者其他字段

Db::table(‘think_user’)

​ ->where(‘id’, 1)

​ ->update([

​ ‘login_time’ => [‘exp’, ‘now()’],

​ ‘login_times’ => [‘exp’, ‘login_times+1’]

]);

2)更新某个字段的值

Db::table(‘think_user’)

​ ->where(‘id’, 1)

​ ->setField(‘name’, ‘thinkphp’);

自增或自减一个字段的值 setInc/setDec

Db::table(‘think_user’)

​ ->where(‘id’, 1)

​ ->setInc(‘score’) //字段加1

Db::table(‘think_user’)

​ ->where(‘id’, 1)

​ ->setInc(‘score’, 5)

延迟更新

Db::table(‘think_user’)->where(‘id’, 1)->setInc(‘score’, 1, 10)

如果需要延时更新则传入第三个参数下例中延时10秒

助手函数

db(‘user’)->where(‘id’, 1)->update([‘name’=>’thinkphp’]);

6.聚合查询

方法 说明

count 统计数量

max 获取最大值

min 获取最小值

avg 获取平均数

sum 获取总分

Db::table(‘think_user’)->count();

db(‘user’)->count();

db(‘user’)->count(‘id’);

db(‘user’)->max(‘score’); //获取用户的最大积分

db(‘user’)->where(‘score>0’)->min(‘score’);

7.删除数据

Db::table(‘user’)->where(‘id’, 1)->delete();

8.时间查询

1)使用where方法

where(‘create_time’, ‘> time’, ‘2016-1-1’);

where(‘create_time’, ‘between time’, [‘2015-1-1’, ‘2018-1-1’]);

2)使用whereTIme

db(‘user’)

​ ->whereTime(‘birthday’, ‘>=’, ‘1970-1-1’)

​ ->select;

db(‘user’)

​ ->whereTime(‘birthday’, ‘between’, [‘1970-10-1’, ‘2000-18-1’])

3)时间表达式

db(‘blog’)

​ ->whereTime(‘create_time’, ‘today’) ‘yesterday’, ‘week’, ‘last week’, ‘month’, ‘year’

​ ->select();

9.视图查询

Db::view(‘user’, ‘id,name’)

​ ->view(‘profile’, ‘truename, phone, email’, ‘Profile.user_id = User.id’)

​ ->view(‘Score’, ‘score’, ‘Score.user_id=Profile.id’)

​ ->where(‘score’, ‘>’, 80)

​ ->select();

视图查询可以实现不依赖数据库视图的多表查询

10.添加数据

添加一条数据

$data = [‘foo’ => ‘bar’, ‘bar’=> ‘foo’];

Db::name(‘user’)->insert($data);

添加数据后如果需要返回新增数据的自增主键,使用getLastInsID

$userid = Db::name(‘user’)->getLastInsID();

添加多条数

$data =[

​ [‘foo’ => ‘bar’, ‘bar’ => ‘foo’],

​ [‘foo’ => ‘bar1’, ‘bar’ = ‘foo1’]

];

Db::name(‘user’)->insertAll($data);

11.原生查询

query方法

query方法用于执行SQl查询操作

Db::query(‘select * from think_user where status = 1’);

你当前采用了分布式数据库,并且设置了读写分离的话,

query方法始终是在读服务器执行,因此query方法对应的都是读操作

excute方法

excute用于更新和写入数据的sql操作

db::excute(‘update think_user set name = ‘thinkphp’ where status = 1 ‘);

参数绑定

Db::query(“select * from think_user where id=? AND status=?”,[8,1]);// 命名绑定Db::execute(“update think_user set name=:name where status=:status”,[‘name’=>’thinkphp’,’status’=>1]);

12.子查询

1)使用select方法

$subQuery = Db::table(‘user’)

​ ->field(‘id,name’)

​ ->where(‘id’, ‘>’, 10)

​ ->select(false);

当select方法的参数为false,表示不进行查询,只是返回构建SQl

2)使用fetchSql方法

fetchSql方法表示不进行,只是返回构建的SQL语句

$subQuery = DB::table(‘think_user’)

​ ->field(‘id, name’)

​ ->where(‘id’, ‘>’, 10)

​ ->fetchSql(true);

​ ->select();

3)使用buildSql构造子查询

$subQuery = Db::table(‘think_user’)

​ ->field(‘id, name’)

​ ->where(‘id’, ‘>’, 10)

​ ->buildSql();

13.链式操作

1.alias

用于设置当前数据表的别名,便于使用其他的连贯操作

Db::table('think_user')->alias('a')->join('__DEPT__ b', 'b.user_id = a.id')->select();

Db::table(‘think_user’)->alias([‘think_user’=>’user’, ‘think_dept’=>’dept’])

->join(‘think_dept’, ‘dept.user_id = user.id’)->select();

2.bind

bind方法用于手动擦书绑定:

// 用于查询Db::table('think_user')->where('id',':id')->where('name',':name')->bind(['id'=>[10,\PDO::PARAM_INT],'name'=>'thinkphp'])->select();// 用于写入Db::table('think_user')->bind(['id'=>[10,\PDO::PARAM_INT],'email'=>'thinkphp@qq.com','name'=>'thinkphp'])->where('id',':id')->update(['name'=>':name','email'=>':email');

3.cache

cache方法用于查询缓存操作,连贯操作方法

cache可以用于select, find, value和column方法

使用cache方法后,在缓存有效期之内不会再次进行数据库查询操作,

而是直接获取缓存中的数据,

Db::table(‘think_user’)->where(‘id=5’)->cache(true)->find();

第一次查询结果会被缓存,第二次查询相同的数据的时候就会直接放回缓存中内容,而不需要再次进行数据库查询操作

Db::table(think_user)->cache(true, 80)->find();

Db::table(‘think_user’)->cache(‘key’, 60)->find(); //添加缓存标识

$data = \think\Cache::get(‘key’);

1)缓存自动更新

这里的缓存自动更新是指一旦数据更新或者删除会自动清理缓存

当你删除或者更新数据的时候,可以使用cache方法手动更新缓存

Db::table(‘think_user’)->cache(‘user_data’)->select([1,4,6]);

4.comment

Comment方法用于在生成在SQL语句中添加注释内容

Db::table(‘think_score’)->comment(‘查询考试前十名分数’)

​ ->field(‘username, score’)

​ ->limit(10)

​ ->order(‘score desc’)

​ ->select();

5.distinct

distinct用于返回唯一不同的值

Db::table(‘think_user’)->distinct(true)->field(‘user_login’)->select();

6.failException

failException设置查询数据为空是否需要抛出异常,如果不传入任何参数

DB::name(‘blog’)->where([‘status’ => 1])->failException()->select();

7.fetchSql

返回SQL语句

$result = Db::table(‘think_user’)->fetch(true)->find(1);

8.field

标识要返回的操作的字段,用于查询和写入

1)指定字段

Db::table('think_user')->field('id,title,content')->select();

2)使用SQL函数

Db::table(‘think_user’)->field(‘id, SUM(score)’)->select();

Db::table('think_user')->field(['id','concat(name,"-",id)'=>'truename','LEFT(title,7)'=>'sub_title'])->select();
SELECT id,concat(name,'-',id) as truename,LEFT(title,7) as sub_title FROM table

3)获取所有字段

Db::table(‘think_user’)->field(true)->select();

4)字段排除

Db::table(‘think_user’)->field(‘user_id, content’, true)->select();

5)用于写入

Db::table('think_user')->field('title,email,content')->insert($data);

即表示表单中的合法字段只有title,emailcontent字段,无论用户通过什么手段更改或者添加了浏览器的提交字段,都会直接屏蔽。因为,其他是所有字段我们都不希望由用户提交来决定,你可以通过自动完成功能定义额外的字段写入。

9.force

force方法用于数据集的强制索引操作

Db::table(‘think_user’)->force(‘user’)->select();

对查询强制使用user索引,user必须是数据表实际创建的索引名称

10.group

用于结合合计函数,根据一个或多个列对结果集进行分组

Db::table('think_user')    ->field('user_id,username,max(score)')    ->group('user_id')    ->select();

11.having

用于配合group方法完成从分组的结果中筛选

Db::table('think_user')    ->field('username,max(score)')    ->group('user_id')    ->having('count(test_time)>3')    ->select(); 

12.join

inner join 等同于join,如果表中有至少一个匹配,则返回行

left join 即使右表中没有匹配,也从坐标返回所有行

right join

full join 只要其中一个表中存在匹配,就返回行

三种写法:

  1. [‘完整表名或者子查询’=>’别名’]
  2. ‘完整表名 别名’
  3. 不带数据表前缀的表名

条件

可以为字符串或数组

举例


Db::table('think_artist')->alias('a')->join('think_work w','a.id = w.artist_id')->join('think_card c','a.card_id = c.id')->select();

Db::table('think_artist')->alias('a')->join('__WORK__ w','a.id = w.artist_id')->join('__CARD__ c','a.card_id = c.id')->select();

$join = [    ['think_work w','a.id=w.artist_id'],    ['think_card c','a.card_id=c.id'],];Db::table('think_user')->alias('a')->join($join)->select();

13.limit

指定查询和操作的数量,分页查询的时候使用较多

1)限制结果数量

Db::table('think_user')    ->where('status=1')    ->field('id,name')    ->limit(10)    ->select();

2)分页查询

Db::table('think_article')->limit('10,25')->select();

表示查询文章数据,从第10行开始的25条数据

14.lock

Lock方法是用于数据库的锁机制,如果在查询或者执行操作的时候使用:

​ lock(true)

15.order

Db::table('think_user')->where('status=1')->order('id desc')->limit(5)->select();

如果没有指定desc或者asc排序规则,默认为asc升序。

16.page

Db::table('think_article')->limit(25)->page(3)->select();
Db::table('think_article')->page('1,10')->select(); 

分页查询

17partition

数据库水平分表

partition($dta, $field, $rule)

$data 分表字段的数据

$field 分表字段的名称

$rule 分表规则

// 用于写入
$data = [    'user_id'   => 110,    'user_name' => 'think'];
$rule = [    'type' => 'mod', // 分表方式    'num'  => 10     // 分表数量];
Db::name('log')    ->partition(['user_id' => 110], "user_id", $rule)    ->insert($data);

18.sequence

sequence方法用于pgsql数据库指定自增序列名,其它数据库不必使用,用法为:

Db::name('user')->sequence('id')->insert(['name'=>'thinkphp']);

19.strict

strict方法用于设置是否严格检查字段名

Db::name(‘user’)

​ ->strict(false)

​ ->insert($data);

系统默认值是有数据库配置参数fields_strice决定

‘field_strict’ = ‘false’

如果开启字段严格检查的话,在更新和写入数据库的时候,一旦存在非数据表字段的值,则会跑出异常

20.table

1)用法

1.切换操作的数据表

2.对多表进行操作

Db::table(‘think_user’)->where(‘status>1’)->select();;

指定数据库

Db::table(‘db_name.think_user’)->where(‘status>1’)->select();

21.union

用于合并两个或多个select语句的结果集

Db::field(‘name’)

​ ->table(‘think_user_0’)

​ ->union(‘select name from think_user_1’)

​ ->union(‘select name from think_user_2’)

​ ->select();

支持UNION ALL

Db::field(‘name’)

​ ->table(‘think_user_0’)

​ ->union(‘select name from think_user_1’, true)

​ ->union(‘select name from think_user_2’, true)

22.where

普通查询,表达式查询,快捷查询,区间查询,组合查询。

1)表达式查询

Db::table(‘think_user’)

​ ->where(‘id’, ‘>’, 1)

​ ->where(‘name’, ‘thinkphp’)

​ ->select();

2)普通查询

$map[‘name’] = ‘thinkphp’;

$map[‘status’] = 1;

Db::table(‘think_user’)->where($map)->select();

select * from think_user where ‘name’ = ‘thinkphp’ and ‘status’ = 1

3)表达式查询

$map[‘id’] = [‘>’, 1];

$map[‘mail’] = [‘like’, ‘%thinkphp@qq.com%’];

Db::table(‘think_user’)->where($map)->select(0;)

14.查询事件

事件 描述

before_select select查询前回调

before_find find查询前回调

after_insert insert操作成功后回调

after_update

after_delete

注册事件

Query::event(‘after_insert’, ‘callback’);

Query::event('before_select', function($options, $query){

​ return $result;

});

15.事务操作

使用InnoDb引擎

使用transaction方法操作数据库事务,当发生异常会自动回滚

1)自动控制事务处理

Db::transation(function{

​ Db::table(‘think_user’)->find(1);

​ Db::table(‘think_user’)->delete(1);

});

2)手动控制事务

Db::startTrans();

try

{

​ Db::table(‘think_user’)->find(1);

​ Db::table(‘think_user’)->delete(1);

​ Db::commit();

}catch(\Exception $e) {

​ Db::rollback;

}

16.监听SQL

开启数据库的调试模式,可以对数据库执行的任何Sql操作进行监听

Db::listen(function($sql, $time, $explain){

echo $sql. '['.$time.'s]'

​ dump($explain); // 查看性能分析结果

});

17.存储过程

$result = Db::query(‘call sp_query(8)’);

参数绑定

$result = Db::query(‘call sp_query’, [8]);

$result = Db::query(‘call sp_query(:id)’, [‘id’=>8]);

18.数据集

数据库的查询就是数据集,数据集的类型是一个二维数组。

配置成数据集,就可以支持对数据集更多个对象话操作

配置数据库resultset_type参数

‘resultset_type’ => ‘collection’

返回的数据集对象是think\Collection提供了和数组无差别用法

$users = Db::name(‘user’)->select();

$item = $users[0]

$count = count($user);

foreach($users as $user){

​ echo $user[‘name’];

​ echo $user[‘id’];

}

数据集对象的isEmpty方法判断

$user = Db::name(‘user’)->select();

if ($user->isEmpty()){

​ echo ‘数据集为空’;

}

使用数据集对象Collection类中下列方法

方法 描述

isEmpty

toArray 转换为数组

all 所有数据

merge 合并其他数据

diff 比较数组,返回差集

flip 交换数据中的键和值

intersect 比较数据,返回交集

keys 返回数据中的所有键名

pop 删除数据中的最后一个元素

shift 删除数据中的第一个元素

unshift 插入第一个元素

reduce 通过使用用户自定义函数,以字符串返回数组

reverse 数据倒序重排

chunk 数据分隔为多个数据块

each 给数据的每个元素执行回调

filter 用回调函数过滤数据中元素

column 返回数据中的指定列

sort 对数据排序

shuffle 将数据打乱

slice 截取数据中的一部分

19.分布式数据库

Thinkphp内置分布式数据库的支持

定义数据库配置信息

‘deploy’ => 1

设置分布式数据库的读写是否分离

‘rw_separate’ => true;

6模型

1.定义

1)模型定义

namespace app\index\model;

use think\Model;

class User extends Model

{

​ protected $pk = ‘uid’; //默认主键为自动识别,如果需要制定,可以设置属性;

}

模型会自动对应数据表,模型类的命名规则是出去表前缀的数据表名称,采用驼峰命名法

2)模型调用

//静态调用

$user = User::get(1);

$user->name = ‘thinkphp’;

$user->save();

//实例化模型

$user = new User;

$user->name = ‘thinkphp’;

//使用Loader类实例化(单例)

$user = Loader::model(‘User’);

//使用助手函数’model’

$user = model(‘User’);

2.模型初始化

1)模型初始化

重写Model的initialize

namespace app\index\model;

use think\Model;

class Index extends Model

{

​ protected function initialize() //自定义初始化

​ {

​ parent::initialize(); //需要调用model的initialize方法

​ }

}

使用静态init方法,init只在第一次实例化的时候执行

namespace app\index\model;

use think\Model;

class Index extends Model

{

​ protected static function init(){}

}

3.新增

1)添加一条数据

实例化模型对象后赋值并保存

$user = new User;

$user->name = ‘thinkphp’;

$user->save();

过滤非数据表字段的数据:

$user = new User($_POST);

$user->allowField(true)->save(); //过滤post数组中的非数据表字段数据

$user = new User($_POST);

指定某些字段写入

$user->allowField([‘name’, ‘email’])->save();

2)获取自增ID

$user = new User;

echo $user->id; //获取自增ID

echo $user->user_id;

3)两次新增数据

$user = new User;

$user->name = ‘thinkphp’;

$user->save();

$user->name = ‘onethink’;

$user->isUpdate(false)->save();

4)添加多条数据

$user = new User;

$list = [

​ [‘name’=>’thinkphp’, ‘email’=>’thinkphp@qq.com’],

​ [‘name’=>’onethink’, ‘email’=>’onethink@qq.com’]

]

`$user->saveALl($list); `

带主键批量添加数据

$user = new User;

$list = [

​ [‘id’=>1, ‘name’=>’thinkphp’, ‘email’=>’thinkphp@qq.com’],

​ [‘id’=>2, ‘name’=>’onethinkphp’, ‘email’=>’onethink@php.com’]

];

$user->saveAll($list, false);

5)静态方法创建

$user = User::create([

​ ‘name’ => ‘thinnkphp’,

​ ‘email’ => ‘thinkphp@qq.com’

]);

6)助手函数

$user = model(‘User’);

$user->data([

​ ‘name’ => ‘thinkphp’,

​ ‘email’ => ‘thinkphp@qq.com’

]);

4.更新

1)直接更新数据

$user = new User;

$user->save([

​ ‘name’ => ‘thinkphp’,

​ ‘email’ => ‘thinkphp@qq.com’

], [‘id’ => 1]);

需要过滤非数据表字段的数据,可以使用:

$user = new User();// 过滤post数组中的非数据表字段数据$user->allowField(true)->save($_POST,['id' => 1]);

如果你通过外部提交赋值给模型,并且希望指定某些字段写入,可以使用:

$user = new User();// post数组中只有nameemail字段会写入$user->allowField(['name','email'])->save($_POST, ['id' => 1]);

2)自动识别

模型的新增和更新方法都是save方法,系统有一套默认的规则来识别当前的数据需要更新还是新增

5.删除

1)实例调用delete方法

$user = User::get(1);

$user->delete();

2)根据主键删除

User::destory(1);

User::destory(1,2,3);

3)条件删除

User::destroy([‘status’=>0]);

6.查询

1)获取单个数据

$user = User::get(1); //取出主键为1

echo $user->name;

$user = User::get([‘name’=>’thinkphp’]); //使用数组查询

如果你是在模型内容,请不要使用$this->name的方式来获取数据,

请使用$this->getAttr(‘name’);

2)获取多个数据

$list = User::all(‘1,2,3’); //主键获取数据

foreach($list as $key=>$user)

​ echo $user->name;

$list = User::all([‘status’=>1]); //使用数组查询

$list = User::all(function($query){

​ $query->where(‘status’, 1)->limit(3)->order(‘id’, ‘asc’);

});

foreach($list as $key=>$user){

​ echo $user->name;

}

数组方式和闭包方式的数据查询区别:

数组方式智能定义查询方式,闭包方式可以支持更多的连贯操作,排序和数量限制

3)自定义数据集对象

支持在模型中单独设置查询数据集的返回对象的名称

namespace app\index\model;

use think\Model;

class User extends Model{

​ protected $resultSetType = ‘collection’;

}

resultSetType字段如果为空则使用数组作为数据集返回类型,如果设置collection则表示使用think\Collection作为返回对象名,也可以设置自定义的数据集对象名称。

4)获取某个字段或者某个列的值

User::where(‘id’, 10)->value(‘score’);

User::where(‘status’, 1)->column(‘name’);

User::where(‘status’, 1)->column(‘name’, ‘id’);

5)动态查询

$user = User::getByName(‘thinkphp’); //根据name字段查询用户

$user = User::getByEmail(‘thinkphp@qq.com’); //根据email字段查询用户

7.聚合

1)静态调用

User::count();

User::where(‘status’, ‘>’, 0)->count();

User::where(‘status’, 1)->avg(‘score’);

User::max(‘score’);

2)动态调用

$user = new User;

$user->count();

$user->where(‘status’, ‘>’, 0)->count();

$user->where(‘status’, 1)->avg(‘score’);

$user->max(‘score’);

8.获取器

1)获取器

获取数据的字段值后自动进行处理

class User extends Model

{

​ public function getStatusAttr($value)

​ {

​ $status = [-1=>’删除’, 0=>’禁用’,1=>’正常’,2=>’待审核’];

return $status[$value];

​ }

}

$user = User::get(1);

echo $user->status;

2)获取原始数据

$user = User::get(1);

echo $user->status; //通过获取器获取字段

echo $user->getData(‘status’); //获取原始字段数据

dump($user->getData());

9.修改器

1)修改器

在数据赋值的时候自动进行转换处理

class User extends Model

{

​ public function setNameAttr($value)

​ {

​ return strtolower($value);

​ }

}

如下代码实际保存到数据库中的时候会转为小写

$user = new User();

$user->name = ‘THinkphp’;

$user->save();

echo $user->name();

10.时间戳

系统支持自动写入创建和更新的时间戳字段

1)数据库配置文件添加全局设置

‘auto_timestamp’ =>true

2)直接在单独的模型类里面设置

protected $autoWriteTimestamp = true;

注:时间戳默认为int类型,如果使用datatime类型

‘auto_timestamp’=>’datatime’;

写入数据,系统会自动写入create_time和update_time字段,而不需要定义修改器

$user = new User();

$user->name = ‘Thinkphp’;

$user->save();

echo $user->create_time;

echo $user->update_time;

如果你的数据表字段不是默认值:

class User extends Model

{

​ protected $createTime = ‘create_at’;

​ protected $updateTime = ‘update_at’;

}

$user = new User();

$user->name = ‘Thinkphp’;

$user->save();

echo $user->create_at;

echo $user->update_at;

protected $updataTIme = false; //关闭自动写入updata_time字段

10.只读字段

要使用只读字段,在模型中定义readonlu1属性

namespace app\index\model;

use think\Model;

class User extends Model

{

​ protected $readonly = [‘name’, ‘email’];

}

11.软删除

在数据加上删除标记,需要的时候进行数据恢复

使用软删除功能,引入SoftDelete trait

namespace app\index\model;

use think\Model;

use traits\model\SoftDelete;

class User extends Model

{

​ use SoftDelete;

​ protected $deleteTime = ‘delete_time’;

}

使用:

User::destroy(1); //软删除

User::destory(1, true); 真实删除

$user = User::get(1);

$user->delete(); //软删除

$user->delete(true);

默认查询数据不包含软删除数据,如果需要包含软删除的数据:

User::withTrashed()->find();

User::withTrashed()->select();

仅仅需要查询软删除的数据

User::onlyTrashed()->find();

User::onlyTrashed()->select();

12.类型转换

支持给字段设置类型自动转换

class User extends Model

{

​ protected $type = [

​ ‘status’ => ‘integer’,

​ ‘score’ => ‘float’,

​ ‘birthday’=> ‘datatime’,

​ ‘info’ => ‘array’

​ ];

}

$user = new User;

$user->status = ‘1’;

$user->score = ‘90.60’;

$user->birthday = ‘2015/6/1’;

$user->save();

类型: integer, float, boolean, array, object, serialize//指定为序列化类型,数据会自动序列化写入

json, timestamp, datetime时间戳

class User extends Model

{

​ protected $type = [

​ ‘status’ => ‘interger’,

​ ‘score’ => ‘float’,

​ ‘birthday’ => ‘timestamp:Y/m/d’

​ ];

}

13.数据完成

数据自动完成不需要手动赋值

系统支持auto,insert, update三个属性,分别在写入,新增和更新的时候进行字段的自动完成机制

namespace app\index\model;

use think\model;

class User extends Model

{

​ protected $auto = [‘name’, ‘ip’];

​ protected $insert = [‘status’=>1];

​ protected $update = [];

​ protected function setNameAttr($value)

​ {

​ return strlower($value);

​ }

​ protected function setIpAttr()

​ {

​ return request()->ip();

​ }

}

$user = new User();

$user->name = ‘Thinkphp’;

$user->save();

14.查询范围

可以对模型的查询和写入操作进行封装

namespace app\index\model;

use think\model;

class User extends Model

{

​ protected function scopeThinkphp($query)

​ {

​ $query->where(‘name’, ‘thinkphp’)->field(‘id, name’);

​ }

​ protected function scopeAge($query)

​ {

​ $query->where(‘age’, ‘>’, 20)->limit(10);

​ }

}

User::scope(‘thinkphp’)->get();

User::scope(‘age’)->all();

闭包函数查询

User::scope(funtion($query){

​ $query->where(‘age’, ‘>’,20)->limit(10);

})

3)全局查询范围

所有的查询都要一个基础的查询范围,模型类里面定义一个静态的base方法

namespace app\index\model;

use think\Model;

class User extends Model

{

​ protected function base($query)

​ {

​ $query->where(‘status’, 1);

​ }

}

11模型分层

thinkphp支持模型分层

index模块的设计中需要区分数据层,逻辑层,服务层

创建model,logic和service目录

数据层:app\index\model\User用于定义数据相关的自动验证和自动完成

逻辑层:app\index\login\User用于定义用户相关的业务逻辑

服务增:app\index\service\User

app\index\model\User.php

namespace app\index\model;

use think\Model;

class User extends Model{}

实例化方法:\think\Loader::model(‘user’);

Logic类:app\index\login\User.php

namespace app\index\logic;

\think\Loader::model(‘user’, ‘logic’);

Service:app\index\service;

12.数组访问和转换

1)转换为数组

$user = User::find(1);

dump($user->toArray());

2)支持设置不输出的字段属性

$user = User::find(1);

dump($user->hidden([‘create_time, update_time’])->toArray());

3)支持追加其他的处理器定义

$user = User::find(1);

dump($user->append([‘status_text’])->toArray());

4)支持设置允许输出的属性

$user = User::find(1);

dumpe($user->visible([‘id’, ‘name’, ‘email’])->toArray());

13.JSON序列化

调用模型的toJson方法进行JSON序列化

$user = User::get(1);

echo $user->toJson();

1)无需输出的字段

$user = User::get(1);

$user->hidde([‘create_time’, ‘update_time’])->toJson();

2)追加其他的字段

$user = User::get(1);

$user->append([‘status_text’])->toJson();

3)允许输出的属性

$user = User::get(1);

$user->visible([‘id’, ‘name’, ‘email’])->toJson();

4)模型对象直接序列化

json_encode(User::get(1));

14.事件

模型类支持

beforeinsert

after_insert

before_update

after_update

before_write

after_write

before_delete

after_delete

使用方法

User::event(‘before_insert’, function ($user){

​ if ($user->status != 1){

​ return false;

​ }

});

支持一个位置注册多个回调方法

User::event(‘before_insert’, function($user){

​ if ($user->status != 1){

​ return false;

​ }

});

User::event(‘before_insert’, ‘beforeInsert’);

在模型类的init方法里面同一注册模型时间

namespace app\index\model;

use think\Model;

class User extends Model

{

​ protected static function init()

​ {

​ User::event(‘before_insert’, function($user)){

​ if ($user->status != 1){

​ return false;

​ }

​ }

​ //快捷注册

​ User::beforeInsert(function ($user){

​ if ($user->status != 1){

​ return false;

​ }

});

​ }

}

15.关联

1一对一关联

1)定义一对一关联,一个用户都有一个个人资料

namespace app\index\model;

use think\Model;

class User extends Model

{

​ public function profile()

​ {

​ return $this->hasOne(‘Profile’);

​ }

}

hasOne(‘关联模型名’,’外键名’,’主键名’,’[模型别名定义]’,’join模型’);

支持为关联模型定义需要查询的字段

namespace app\index\model;

use think\Model;

class User extends Model

{

​ public function profile()

​ {

​ return $this->hasOne(‘Porfile’)->field(‘id, name, email’);

​ }

}

2)关联查找

$user = User::find(1);

$user->profile->email; //输出Profile关联模型的email属性

3)设置别名

namespace app\index\model;

use think\Model;

class User extends Model

{

​ public function profile()

​ {

​ retrun $this->hasOne(‘Profile’, ‘uid’)->setAlias([‘user’=>’member’]);

​ }

}

4)关联新增

$user = User::find(1);

$user->profile()->save([‘email’=>’thinkphp’]);

5)关联更新

$user = User::find(1);

$user->profile->email = ‘thinkphp’;

$user->profile->save();

6)定义相对的关联

在Profile模型中定义一个相对的关联关系

namespace app\index\model;

use think\Model;

class Profile extends Model

{

​ public function user()

​ {

​ return $this->belongsTo(‘User’);

​ }

}

belongsTo(‘关联模型名’,’外键名’,’关联表主键名’,’[模型别名定义]’,’join模型’);

7)绑定属性到父模型

在定义关联的时候使用bind方法绑定属性到父模型

namespace app\index\model;

use think\Model;

class User extends Model

{

​ public function profile()

​ {

​ return $this->hasOne(‘Profile’, ‘uid’)->bind(‘nickname, email’);

​ }

}

2一对多关联

hasMany(‘关联模型名’,’外键名’,’主键名’,[‘模型别名定义’]);

namespace app\index\model;

use think\Model;

class Article extends Model

{

​ public function comments()

​ {

​ return $this->hasMany(Comment);

​ }

}

需要指定查询字段

namespace app\index\model;

use think\Model;

class Article extends Model

{

​ public function comments()

​ {

​ return $this->hasMany(‘Comment’)->field(‘id, author, content’);

​ }

}

1)关联查询

$article = Article::get(1);

dump($article->comments);

dump($aritcle->comments()->where(‘status’, 1)->select());

2)根据关联条件查询

$list = Article::has(‘comments’, ‘>’, 3)->select();

$list=Article::hasWhere(‘comments’,[‘status’=>1])->select();

3)关联新增

$article = Article::find(1);

$article->comments()->save([‘content’=>’test’]);

$article->comments()->saveAll([‘conent’=>’thinkphp’],[‘content’=>’onethink’]);

4)定义相对的关联

namespace app\index\model;

use think\Model;

class Comment extends Model

{

​ public function article()

​ {

​ return $this->belongsTo(‘article’);

​ }

}

3.远程一对多

用户定义有跨表的一对多关系

namespace app\index\model;

use think\Model;

class CIty extends Model

{

​ public funcion topics()

{

​ return $this->hasManyThrough(‘Topic’, ‘User’);

}

}

hasManyThrough(‘关联模型名’,“中间模型名’外键名’,’中间模型关联键名’,’当前模型主键名’,[‘模型别名定义’]);

1)关联查询

$city = City::get(1);

dump($city->topics);

dump($city->topics()->where(‘topic.status’, 1)->select());

4.多对多关联

namespace app\index\model;

use think\Model;

class User extends Model

{

​ public function roles()

​ {

​ return $this->belongsToMany(‘Role’);

​ }

}

belongsToMany(‘关联模型名’,’中间表名’,’外键名’,’当前模型关联键名”,[‘模型别名定义’]);

关联查询

我们可以通过下面的方式获取关联数据

$user = User::get(1);// 获取用户的所有角色dump($user->roles);

关联新增

$user = User::get(1);// 增加关联数据 会自动写入中间表数据$user->roles()->save(['name'=>'管理员']);// 批量增加关联数据$user->roles()->saveAll([    ['name'=>'管理员'],    ['name'=>'操作员'],]);

只新增中间表数据,可以使用

$user = User::get(1);// 仅增加关联的中间表数据$user->roles()->save(1);// 或者$role = Role::get(1);$user->roles()->save($role);// 批量增加关联数据$user->roles()->saveAll([1,2,3]);

单独更新中间表数据,可以使用:

$user = User::get(1);// 增加关联的中间表数据$user->roles()->attach(1);// 传入中间表的额外属性$user->roles()->attach(1,['remark'=>'test']);// 删除中间表数据$user->roles()->detach([1,2,3]);

定义相对的关联

我们可以在Role模型中定义一个相对的关联关系,例如:

namespace app\index\model;use think\Model;class Role extends Model {    public function users()    {        return $this->belongsToMany('User');    }}

5.多态一对多

多态关联允许一个模型在单个关联定义方法中从属一个以上其他模型,例如

用户可以评论书和文章

关联表的数据表结构

article    id - integer    title - string    content - text
book    id - integer    title - string
comment    id - integer    content - text    commentable_id - integer    commentable_type - string

1)多态关联定义

namespace app\index\model;

use think\Model;

class Article extends Model

{

​ public function comments()

​ {

​ return $this->morphMany(‘Comment’, ‘commentable’);

​ }

}

morphMany(‘关联模型名’,’多态字段信息’,’多态类型’);

关联模型名:使用模型名Comment

多态字段信息:多态前缀_type和多态前缀_id

多态类型:当前·模型对应的多态类型,使用模型名或者命名空间模型名.

书籍模型:

<?phpnamespace app\index\model;use think\Model;class Book extends Model{    /**     * 获取所有针对书籍的评论。     */    public function comments()    {        return $this->morphMany('Comment', 'commentable');    }}

书籍模型的设置方法同文章模型一致,区别在于多态类型不同,但由于多态类型默认会取当前模型名,因此不需要单独设置。

下面是评论模型的关联定义:

<?phpnamespace app\index\model;use think\Model;class Comment extends Model{    /**     * 获取评论对应的多态模型。     */    public function commentable()    {        return $this->morphTo();    }}

morphTo方法的参数如下:

morphTo(‘多态字段信息’,[‘多态类型别名’]);

多态字段信息(可选):支持两种方式定义 如果是字符串表示多态字段的前缀,多态字段使用 多态前缀_type多态前缀_id,如果是数组,表示使用[‘多态类型字段名’,’多态ID字段名’],默认为当前的关联方法名作为字段前缀
多态类型别名(可选):数组方式定义

获取多态关联

一旦你的数据表及模型被定义,则可以通过模型来访问关联。例如,若要访问某篇文章的所有评论,则可以简单的使用 comments 动态属性:

$article = Article::get(1);foreach ($article->comments as $comment) {    dump($comment);}

你也可以从多态模型的多态关联中,通过访问调用 morphTo 的方法名称来获取拥有者,也就是此例子中 Comment 模型的 commentable 方法。所以,我们可以使用动态属性来访问这个方法:

$comment = Comment::get(1);$commentable = $comment->commentable;

Comment 模型的 commentable 关联会返回 ArticleBook 模型的对象实例,这取决于评论所属模型的类型。

自定义多态关联的类型字段

默认情况下,ThinkPHP 会使用模型名作为多态表的类型区分,例如,Comment属于 Article 或者 Book , commentable_type 的默认值可以分别是 Article 或者 Book 。我们可以通过定义多态的时候传入参数来对数据库进行解耦。

    public function commentable()    {        return $this->morphTo('commentable',[            'book'  =>  'app\index\model\Book',            'post'  =>  'app\admin\model\Article',        ]);    }

6.动态属性

模型对象的关联属性可以直接作为当前模型对象的动态属性进行复制或者取值操作

namespace app\index\model;

use think\Model;

class User extends Model

{

​ public function profile()

​ {

​ return $this->hasOne(‘Profile’);

​ }

}

$user = User;:find(1);

dump($user->profile);

$user->profile->phone = ‘1234567890’;

$user->profile->save();

7.关联预载入

解决N+1次查询的问题

$list = User::all([1,2,3]);

foreach($list as $ser){

​ dump($user->profile); //执行4次查询

}

使用一对一关联查询,变成2次查询,提高性能

$list = User::with(‘profile’)->select([1,2,3]);

foreach($list as $user){

​ dump($user->profile);

}

多个关联

$list = User::with(‘profile, book’)->select([1,2,3]);

嵌套预载入

$list = User::with('profile.phone')->select([1,2,3]);foreach($list as $user){    // 获取用户关联的phone模型    dump($user->profile->phone);}

如果要指定属性查询,可以使用:

$list = User::field('id,name')->with(['profile'=>function($query){$query->withField('email,phone');}])->select([1,2,3]);foreach($list as $user){    // 获取用户关联的profile模型数据    dump($user->profile);}

16.聚合模型

一对一关联操作更加简化,把模型类继承think\model\Merge

自动完成关联查询,关联保存和关联删除

namespace app\index\model;
use think\model\Merge;
class User extends Merge{    // 定义关联模型列表    protected static $relationModel = ['Profile'];    // 定义关联外键    protected $fk = 'user_id';    protected $mapFields = [        // 为混淆字段定义映射        'id'        =>  'User.id',        'profile_id' =>  'Profile.id',    ];}

8.视图

1.视图实例化

视图功能由\think\VIew类配合视图驱动类一起完成

继承\think\Controller类,则无需自己实例化视图

return $this->fetch(‘hello’, [‘name’=>’thinkphp’]);

fetch 渲染模版输出

display 渲染内容输出

assign 模版变量赋值

engine 初始化模版引擎

view(['模版文件']['模版变量'][模版替换(数组)]);

2.模版引擎

1)配置文件

'template'               => [    // 模板引擎类型 支持 php think 支持扩展    'type'         => 'Think',   
// 模板路径    'view_path'    => './template/',   
// 模板后缀    'view_suffix'  => 'html',    
// 模板文件名分隔符    'view_depr'    => DS,   
// 模板引擎普通标签开始标记    'tpl_begin'    => '{',  
// 模板引擎普通标签结束标记    'tpl_end'      => '}', 
// 标签库标签开始标记    'taglib_begin' => '{',   
// 标签库标签结束标记    'taglib_end'   => '}',],

2)视图根目录

根目录默认情况位于模块的view目录

实例化视图

$view = new View([    'type'               => 'think',   
'view_path'          => './template/',  
'view_suffix'        => 'php',   
'view_depr'          => DS,   
'tpl_begin'          => '{', // 模板引擎普通标签开始标记    'tpl_end'            => '}', 
// 模板引擎普通标签结束标记    'strip_space'        => true, 
// 去除模板文件里面的html空格与换行    'tpl_cache'          => true, 
// 开启模板编译缓存    'taglib_pre_load'    => '', 
// 需要额外加载的标签库(须指定标签库名称),多个以逗号分隔    'tpl_replace_string' => [],
// 模板过滤输出(与输出替换章节不同,前者对模版进行过滤)]);

3)调用engine方法初始化

$view = new View();

return $view->engine(‘php’)->fetch();

4)设置模版引擎参数

$view = new View();

return $view->config(‘view_path’, ‘./template’)->fetch();

3.模版赋值

namespace index\app\controller;
class Index extends \think\Controller{  
public function index()    {        // 模板变量赋值        $this->assign('name','ThinkPHP');   
$this->assign('email','thinkphp@qq.com');       
// 或者批量赋值      
$this->assign([            'name'  => 'ThinkPHP',            'email' => 'thinkphp@qq.com'        ]);  
// 模板输出        return $this->fetch('index');    }}

1)传入参数方法

namespace app\index\controller;class Index extends \think\Controller{    public function index()    {        return $this->fetch('index', [            'name'  => 'ThinkPHP',            'email' => 'thinkphp@qq.com'        ]);    }}
class Index extends \think\Controller{    public function index()    {        $content = '{$name}-{$email}';        return $this->display($content, [            'name'  => 'ThinkPHP',            'email' => 'thinkphp@qq.com'        ]);    }}

2)对象赋值

class Index extends \think\Controller{    public function index()    {        $view = $this->view;        $view->name     = 'ThinkPHP';        $view->email    = 'thinkphp@qq.com';        // 模板输出        return $view->fetch('index');    }}

4.模版渲染

fetch([‘模版文件’],[‘模版变量’])

不带任何参数 自动定位当前操作的模版文件

[模块@][控制器/][操作] 常用写法,支持跨模块

完整的模版文件名 直接使用完整模版文件名

// 指定模板输出return $view->fetch('edit'); 

表示调用当前控制器下面的edit模板

return $view->fetch('member/read');

表示调用Member控制器下面的read模板。

跨模块渲染模板

return $view->fetch('admin@member/edit');
$view->fetch('/menu');

表示读取的模板是

当前模块/默认视图目录/menu.html

渲染内容

如果希望直接解析内容而不通过模板文件的话,可以使用display方法:

$view = new View();return $view->display($content,$vars);

渲染的内容中一样可以使用模板引擎的相关标签。

5.输出替换

对视图输出的内容进行字符替换

namespace index\app\controller;

class Index extends \think\Controller

{

​ public function index()

​ {

​ $this->assign(‘name’, ‘thinkphp’);

return $this->fetch('index',[],['__PUBLIC__'=>'/public/']);

​ }

}

全局替换

'view_replace_str'  => 
[    '__PUBLIC__'=>'/public/',    '__ROOT__' => '/',]

9模版

1模版定位

1)模版文件定义

视图目录/控制器名/操作名 + 模版后缀

2)模版渲染规则

\think\View类的fetch方法

渲染规则为模块@控制器/操作

模版文件目录默认位于模块的view目录下,视图类的fetch方法中模版文件的定位规则如下:

return $view->fetch();

定位模版文件到

[模版文件目录]/当前控制器名(小写+下划线)/当前操作名

指定操作

return $view->fetch(‘add’);

[模版文件目录]/当前控制器名(小写+下划线)/add.html

调用控制器的某个模版文件使用

return $view->fetch(‘user/add’);

[模版文件目录]/user/add.html;

跨模块调用模版

return $view->fetch(‘admin@user/add’);

2模块标签

1)普通标签

{}用于变量输出和模版注释

2)标签库标签

用于模版变量输出,文件包含,条件控制,循环输出。、

观察配置文件

3.变量输出

1)模版输出变量

$view = new View();

$view->name = ‘thinkphp’;

return $view->fetch();

Hello,{$name}!

2)数组变量

$data[‘name’] = ‘Thinkphp’;

$data[‘email’] = ‘thinkphp@qq.com’;

$view->assgin('data', $data);

Name:{$data.name}; Name:{$data['name']}

Email:{$data.email};Email:{$data['email']}

3)对象变量

Name:{$data->name};

Email:{$data->email};

4.系统变量

1)系统变量输出

{$Think.server.script_name}

{$Think.session.user_id}

{$Think.get.pageNumber} $_GET['pageNumber']

2)常量输出

{$Think.const.APP_PATH}

3)配置输出

{$Think.config.default_module}

{$Think.config.default_controller}

4)语言变量

{$Think.lang.page_error}

5.请求变量

模版支持直接输出Request请求对象的方法

$Request.方法名.参数

{$Request.get.id}

{$Request.param.name}

// 调用Request对象的get方法 传入参数为id{$Request.get.id}// 调用Request对象的param方法 传入参数为name{$Request.param.name}// 调用Request对象的param方法 传入参数为user.nickname{$Request.param.user.nickname}// 调用Request对象的root方法{$Request.root}// 调用Request对象的root方法,并且传入参数true{$Request.root.true}// 调用Request对象的path方法{$Request.path}// 调用Request对象的module方法{$Request.module}// 调用Request对象的controller方法{$Request.controller}// 调用Request对象的action方法{$Request.action}// 调用Request对象的ext方法{$Request.ext}// 调用Request对象的host方法{$Request.host}// 调用Request对象的ip方法{$Request.ip}// 调用Request对象的header方法{$Request.header.accept-encoding}

6.使用函数

对模版输出变量使用函数

{$data.name|md5}

函数多个参数调用

{$create_time|data=’y-m-d’, ###}

表示date闯入两个参数,第一个参数y-m-d,第二个参数是输出的create_time变量

前面输出的变量在后面定义的函数的第一个参数,则可以直接使用

{$data.name|substr=0, 3}

7.使用默认值

变量提供默认值

{$user.nickname|default = ‘这家伙很懒,什么也没有留下’}

8.使用运算符

运算符使用示例
+{ a+ b}
-{ a b}
*{ a b}
/{ a/ b}
%{ a b}
++{a++} 或 {++a}
{a--} 或 {--a}
综合运算{ a+ b*10+$c}

9.三元运算

{$status?’正常’:’错误’}

{$info['status']?$info['msg']:$info['error']}

10原样输出

{literal}

​ Hello,{$name}!

{/literal}

11.模版注释

单行注释

{/注释内容/}或{//注释内容}

多行注释

{/*这是模版注释内容*/}

12.模版布局

1)全局配置方式

‘template’ => [

​ ‘layout_on’ => true,

​ ‘layout_name’ => ‘layout’

]

在不开启layout_on布局模版之前,会直接渲染application/index/view/user/add.html

开启之后,会渲染application/index/view/layout.html模版

区别在于有一个特定的输出替换变量{–CONTENT——}

layout.html写法

{include file=”public/header”}

{__CONTENT__}

{include file=”public/footer”}

改变特定的替换字符创

‘template’ => [

​ ‘layout_on’ => true,

​ ‘layout_name’ => ‘layout’, layout_name =>’layout/layoutname’

​ //采用application/index/view/layout/layoutname.html模版

​ ‘layout_item’ =>'{__REPLACE__}'

]

2)模版标签方式

关闭layout_on设置

在user/add.html开头添加布局标签{layout name=”layout”}

3)使用layout控制模版布局

namespace app\index\controller;

use think\Controller;

class User extends Controller

{

​ public function add()

​ {

​ $this->view->engine->layout(true);

​ return $this->fetch(‘add’);

​ }

}

13.模版继承

模板继承


模板继承是一项更加灵活的模板布局方式,模板继承不同于模板布局,甚至来说,应该在模板布局的上层。模板继承其实并不难理解,就好比类的继承一样,模板也可以定义一个基础模板(或者是布局),并且其中定义相关的区块(block),然后继承(extend)该基础模板的子模板中就可以对基础模板中定义的区块进行重载。

因此,模板继承的优势其实是设计基础模板中的区块(block)和子模板中替换这些区块。

每个区块由{block} {/block}标签组成。 下面就是基础模板中的一个典型的区块设计(用于设计网站标题):

{block name="title"}<title>网站标题</title>{/block}

block标签必须指定name属性来标识当前区块的名称,这个标识在当前模板中应该是唯一的,block标签中可以包含任何模板内容,包括其他标签和变量,例如:

{block name="title"}<title>{$web_title}</title>{/block}

你甚至还可以在区块中加载外部文件:

{block name="include"}{include file="Public:header" /}{/block}

一个模板中可以定义任意多个名称标识不重复的区块,例如下面定义了一个base.html基础模板:

<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>{block name="title"}标题{/block}</title></head><body>{block name="menu"}菜单{/block}{block name="left"}左边分栏{/block}{block name="main"}主内容{/block}{block name="right"}右边分栏{/block}{block name="footer"}底部{/block}</body></html>

然后我们在子模板(其实是当前操作的入口模板)中使用继承:

{extend name="base" /}{block name="title"}{$title}{/block}{block name="menu"}<a href="/" >首页</a><a href="/info/" >资讯</a><a href="/bbs/" >论坛</a>{/block}{block name="left"}{/block}{block name="main"}{volist name="list" id="vo"}<a href="/new/{$vo.id}">{$vo.title}</a><br/> {$vo.content}{/volist}{/block}{block name="right"} 最新资讯:{volist name="news" id="new"}<a href="/new/{$new.id}">{$new.title}</a><br/>{/volist}{/block}{block name="footer"}{__block__} @ThinkPHP 版权所有{/block}

上例中,我们可以看到在子模板中使用了extend标签来继承了base模板。
在子模板中,可以对基础模板中的区块进行重载定义,如果没有重新定义的话,则表示沿用基础模板中的区块定义,如果定义了一个空的区块,则表示删除基础模板中的该区块内容。 上面的例子,我们就把left区块的内容删除了,其他的区块都进行了重载。而

{block name="footer"}{__block__}@ThinkPHP 版权所有{/block}

这一区块中有{_*block_*}这个标签,当区块中有这个标记时,就不只是直接重载这个区块,它表示引用所继承模板对应区块的内容到这个位置,最终这个区块是合并后的内容。所以这里footer区块最后的内容是: 底部@ThinkPHP 版权所有

extend标签的用法和include标签一样,你也可以加载其他模板:

{extend name="Public:base" /}

或者使用绝对文件路径加载

{extend name="./Template/Public/base.html" /}

在当前子模板中,只能定义区块而不能定义其他的模板内容,否则将会直接忽略,并且只能定义基础模板中已经定义的区块。

例如,如果采用下面的定义:

{block name="title"}<title>{$title}</title>{/block}<a href="/" >首页</a><a href="/info/" >资讯</a><a href="/bbs/" >论坛</a>

导航部分将是无效的,不会显示在模板中。

模板可以多级继承,比如B继承了A,而C又继承了B,最终C中的区块会覆盖B和A中的同名区块,但C和B中的区块必须是A中已定义过的。

子模板中的区块定义顺序是随意的,模板继承的用法关键在于基础模板如何布局和设计规划了,如果结合原来的布局功能,则会更加灵活。

14.包含文件

{include file=’模版文件1,模版文件2’}

1)使用模版表达式

{include file=”public/header”}

{include file=”blue/public/menu”}

2)传入参数

{include file=”public/header” title=”$title” keywords=”开源web开发框架”}

​ [title]

15.标签库

1)导入标签库

{taglib name=”html, article”/}

使用article标签库

{article::read name=”hello” id=”data”}

{$data.id}:{$data.title}

{/article:read}

2)内置标签

{eq name=”status” value=”1”}

{/eq}

3)标签库预加载

‘taglib_pre_load’ => ‘article,html’

16.内置标签

1循环输出标签

1)volist标签

用于查询数据集输出,

{volist name=”list” id=”vo”}

{$vo.id}:{$vo.name}

{/volist}

支持输出查询结果中的部分数据

{volist name=”list” id=”vo” offset=”5” length=”10”}

{$vo.name}

{/volist}

输出偶数记录

{volist name=”list” id=”vo” mod=”2”}

{eq name=”mod” value=”1”}{$vo.name}{/eq}

{/volist}

为空的时候输出提示

{volist name=”list” id=”vo” empty=”暂时没有数据”}

{$vo.id}|{$vo.name}

{/volist}

输出循环变量

{volist name=”list” id=”vo” key=”k”}

{$k}{$vo.name}

{/volist}

如果没有指定key属性,默认使用循环变量i

{volist name="list" id="vo"  }{$i}.{$vo.name}{/volist}

如果要输出数组的索引,可以直接使用key变量,和循环变量不同的是,这个key是由数据本身决定,而不是循环控制的,例如:

{volist name="list" id="vo"  }{$key}.{$vo.name}{/volist}

2)foreach标签

{foreach $list as $vo}     {$vo.id}:{$vo.name}{/foreach}
{foreach name="list" item="vo"}    {$vo.id}:{$vo.name}{/foreach}
{foreach name="list" item="vo" key="k" }   {$k}|{$vo}{/foreach}

3)for标签

{for start="开始值" end="结束值" comparison="" step="步进值" name="循环变量名" }{/for}
{for start="1" end="100"}{$i}{/for}
for ($i=1;$i<100;$i+=1){    echo $i;} 

开始值、结束值、步进值和循环变量都可以支持变量,开始值和结束值是必须,其他是可选。comparison 的默认值是lt,name的默认值是i,步进值的默认值是1,举例如下:

3比较标签

标签含义
eq或者 equal等于
neq 或者notequal不等于
gt大于
egt大于等于
lt小于
elt小于等于
heq恒等于
nheq不恒等于
{比较标签 name="变量" value="值"}内容{/比较标签}

​ 要求name变量的值等于value输出

​ {eq name=”name” value=”value”}value{/eq}

当name变量的值大于5就输出

{gt name=”name” value=”5”}value{/gt}

当name变量的值不小于5就输出

{egt name=”name” value=”5”}value{egt}

{eq name=”vo.name” value=”5”}

{$vo.name}

{/eq}

使用函数

{eq name=”vo:name|strlen” value=”5”}

{$vo.name}

{/eq}

3条件判断

1)switch标签

{switch name="变量" }    {case value="值1" break="0或1"}输出内容1{/case}    {case value="值2"}输出内容2{/case}    {default /}默认情况{/switch}
{switch name="User.level"}    {case value="1"}value1{/case}    {case value="2"}value2{/case}    {default /}default{/switch}

多个条件的判断

{switch name="Think.get.type"}    {case value="gif|png|jpg"}图像格式{/case}    {default /}其他格式{/switch}

case标签还有一个break属性,表示是否需要break,默认是会自动添加break,如果不要break,可以使用

{switch name=”Think.get.userId|abs”}

​ {case value=”1” break=”0”}admin{/case}

{/switch}

2)if标签

{if condition="($name == 1) OR ($name > 100)"} value 1

{else if condition=”$name eq 2”/}value2

{else / }value3

{/if}

使用php代码

{if condition=”strtoupper($user[‘name’]) neq ‘THINKPHP’”} Thinkphp

{else /} other Framework

{/if}

3)in not in

$id = 1;

$this->assign('id', $id);

{in name=”id” value=”1,2,3”}

id

{/in}

{notin name=”id” value=”1,2,3”}

id

{/notin}

{in name=”id” value=”$range”}

id

{/in}

4)between和notbetween

{between name=”id” value=”1,10”}

{/between}

{notbetween name=”id” value=”A,Z”}

{/between}

5)present notpresent

判断某个变量是否已经定义

{present name=”name”}

name已经赋值

{/present}

6)empty notempty

{empty name=”name”}

name为空值

{/empty}

7)defined

{defined name=”Name”}

Name常量已经定义

{/defined}

3.资源文件加载

script type='text/javascript' src='/static/js/common.js'>
<link rel="stylesheet" type="text/css" href="/static/css/style.css" />
{load href="/static/js/common.js" /}{load href="/static/css/style.css" /}
{load href="/static/js/common.js,/static/css/style.css" /}

​ 多资源文件加载

4.标签嵌套

{volist name="list" id="vo"}    {volist name="vo['sub']" id="sub"}        {$sub.name}    {/volist}{/volist}

5.原生php

{php}echo 'Hello,world!';{/php}

简而言之,在PHP标签里面不能再使用PHP本身不支持的代码。

6.定义标签

1)assgin标签

{assign name=”var” value=”123”} //模版文件定义变量

{assign name=”Think.get.id” value=”123”} //系统变量

{assign name=”var” value=”$val”}

{assign name="var" value="$Think.get.name" /}

2)define标签

{define name="MY_DEFINE_NAME" value="3" /}
{define name="MY_DEFINE_NAME" value="$Think.get.name" /}

10.日志

1介绍

日志记录由\think\Log类完成 日志记录和跟踪调试

1)日志初始化

使用日志记录之前,需要初始化日志类,指定当前使用的日志巨鹿方式

Log::init([

​ ‘type’ => ‘File’,

​ ‘path’ => APP_PATH.’logs/’

]);

日志保存目录为APP_PATH.’logs/’

应用需要扩展自己的日志驱动:

Log::init([

​ ‘type’ => ‘\org\Log\File’,

​ ‘path’ => APP_PATH.’logs/’

]);

2日志驱动

1)日志驱动

日志可以通过支持不同的方式写入,写入驱动包括File,Socket,默认日志会记录到文件中

‘log’ =>[

​ ‘type’ => ‘test’,

]

2)File驱动

'log'   => [    // 日志记录方式,支持 file socket 
'type' => 'File',    //日志保存目录  
'path' => LOG_PATH,    //单个日志文件的大小限制,超过后会自动记录到第二个文件    'file_size'     =>2097152,    //日志的时间格式,默认是` c `    'time_format'   =>'c'],

3.日志写入

1)手动记录

Log::record() 记录日志信息到内存

Log::save() 把保存在内存中的日志信息写入

Log::write() 实时写入一条日志信息

Log::record(‘测试日志信息’);

Log::record(‘测试日志信息,这是警告级别’,’notice’);

Log::write(‘实时写入’,’notice’); //实时写入

2)日志级别

  • log 常规日志,用于记录日志
  • error 错误,一般会导致程序的终止
  • notice 警告,程序可以运行但是还不够完美的错误
  • info 信息,程序输出信息
  • debug 调试,用于调试信息
  • sql SQL语句,用于SQL记录,只在数据库的调试模式开启时有效
Log::error('错误信息');Log::info('日志信息');// 和下面的用法等效Log::record('错误信息','error');Log::record('日志信息','info');

4.独立日志

'log'   => [    'type'          => 'file',   
// error和sql日志单独记录    'apart_level'   =>  ['error','sql'],],

5.日志清空

Log::clear();

6.写入授权

日志功能支持写入授权,设置某个请求日志授权Key

应用配置文件或者应用公共文件添加当前访问的授权Key定义

Log::key(Request::instance()->ip());

日志配置参数中增加allow_key参数

‘log’ =>[

​ ‘type’ => ‘File’,

​ ‘allow_key’ => [‘202.12.36.89’]

]

11.错误和调试

1.调试模式

应用配置文件

‘app_debug’ => false;

优势:

1.开启日志记录,任何错误信息和调试信息都会详细记录

2.详细记录整个执行过程

3.模版修改可以即时生效

4.记录SQL日志,方便分析SQL

5.通过Trace功能更好的调试和发现错误

6.发生异常的时候显示详细的异常信息

2.异常处理

1)异常处理接管

异常页面由开发者自定义类进行处理

‘exception_handle’ =>’\app\common\exception\Http’

4.抛出异常

使用\think\Exception类来抛出异常

throw new \think\Exception(‘异常消息’, 100006); //手动抛出异常

抛出HTTP异常

可以使用\think\exception\HttpException类来抛出异常

throw new \think\exception\HttpException(404, ‘异常消息’, null);

5.Trace调试

实时显示当前页面的操作的请求信息,运行情况,SQL执行,错误提示

1)开启Trace调试

‘app_trace’ => true;

2)页面Trace显示

‘trace’ => [

​ ‘type’ => ‘html’

]

页面右下角显示ThinkPHP LOGO;

显示个6个选型卡

基本 当前的页面摘要信息,执行时间,内存开销,文件加载数,查询次数

文件 列出当前页面执行过程中加载的文件及其大小

流程 会列出当前页面执行到的行为和相关流程

错误 当前页面的错误

SQL 当前页面执行到SQL语句信息

调试 开发人员在程序中进行的调试输出

3)浏览器Trace显示

‘trace’ =>[

​ ‘type’ => ‘console’

]

5.变量调试

系统提供了\think\Debug类各种调试

dump

6.性能调试

使用think\Debug类

Debug::remark(‘begin’);

Debug::remark(‘end’); //标记代码区间

echo Debug::getRangeTime(‘begin’, ‘end’).’s’; //获取执行时间

echo Debug::getRangeTime(‘begin’, ‘end’, 6).’s’;//获取统计精度

环境支持内存占用统计

Debug::getRangeMen(‘begin’, ‘end’).’kb’;

7.SQL调试

1)查看SQL记录

开启了数据库的调试模式,可以在日志文件中看到详细的SQL执行记录和性能分析

2)监听SQL

Db::listen(function($sql, $$time, $explain));{

echo $sql.['$time'.'s'];

}

3)调试执行的SQL语句

在模型操作中 ,为了更好的查明错误,经常需要查看下最近使用的SQL语句,我们可以用getLastsql方法来输出上次执行的sql语句。例如:

User::get(1);echo User::getLastSql();

输出结果是 SELECT * FROM 'think_user' WHERE 'id' = '1'

也可以使用fetchSql方法直接返回当前的查询SQL而不执行,例如:

echo User::fetchSql()->find(1);

输出的结果是一样的。

getLastSql方法只能获取最后执行的SQL记录,如果需要了解更多的SQL日志,可以通过查看当前的Trace信息或者日志文件。

7.远程调试

8.404页面


一旦抛出了HttpException异常,可以支持定义单独的异常页面的模板地址,只需要在应用配置文件中增加:

'http_exception_template'    =>  [    // 定义404错误的重定向页面地址    404 =>  APP_PATH.'404.html',    // 还可以定义其它的HTTP status    401 =>  APP_PATH.'401.html',]

模板文件支持模板引擎中的标签。

http_exception_template配置仅在部署模式下面生效。

一般来说HTTP异常是由系统自动抛出的,但我们也可以手动抛出

throw new \think\exception\HttpException(404, '页面不存在');

或者通过助手函数abort手动抛出HTTP异常,例如:

abort(404,'页面不存在');

8.验证

1验证器

使用独立的\think\Validata类

1)独立验证

$validate = new Validate([

​ ‘name’ => ‘require|max:25’,

​ ‘email’ => ‘email’

]);

$data = [

​ ‘name’ => ‘thinkphp’,

​ ‘email’ => ‘thinkphp@qq.com’

];

if (!$validata->check($data)){

​ dump($validate->getError());

}

2)验证器

定义好验证器类

namespace app\index\validate;

use think\Validata;

class User extends Validata

{

​ protected $rul = [

​ ‘name’ => ‘require|max:25’,

​ ‘email’ => ‘email’

​ ];

}

需要User验证的地方

$data = [

​ ‘name’ => ‘thinkphp’,

​ ‘email’ => ‘thinkphp@qq.com’

];

$validate = Loader::validate(‘User’);

if (!valiedata->check($data)){

​ dump($validate->getError);

}

2.验证规则

1)设置规则

$rules = [

​ ‘name’ => ‘require|max:26’,

​ ‘age’ => ‘number|between:1,120’

];

$validate = new Validate($rules);

动态添加规则

$rules = [

​ ‘name’ => ‘require|max:25’,

​ ‘age’ => ‘number|between:1,120’

];

$validate = new Validate($rules);

$validate->rule('zip', '/^\d{6}$/');

$validate->rule([‘email’ =>’email’]);

2)规则定义

$rules = [

​ ‘name’ => ‘require|max:25’,

​ ‘age’ => ‘number|between:1,120’

];

3)属性定义

namespace app\index\validate;

use think\Validate;

class User extends Validate

{

​ protected $rule = [

​ ‘name’ => ‘require|max:25’,

​ ‘age’ => ‘number|between:1,129’,

​ ‘email’ => ‘email’

];

​ protected $message = [

​ ‘name.require’ => ‘名称必须’,

​ ‘name.max’ => ‘名称最多不能超过25个字符’,

​ ‘age.number’ => ‘年龄必须是数字’

​ ‘age.between’ => ‘年龄只能在1-120之间’

​ ‘email’ => ‘邮箱格式错误’

];

}

批量验证

$validate = new Validate($rule, $msg);

$result = $validate->batch()->check($data);

自定义验证规则

系统内置了一些常用的规则,如果还不够用,可以自己扩展验证规则。

如果使用了验证器的话,可以直接在验证器类添加自己的验证方法,例如:

namespace app\index\validate;use think\Validate;class User extends Validate{    protected $rule = [        'name'  =>  'checkName:thinkphp',        'email' =>  'email',    ];    protected $message = [        'name'  =>  '用户名必须',        'email' =>  '邮箱格式错误',    ];    // 自定义验证规则    protected function checkName($value,$rule,$data)    {        return $rule == $value ? true : '名称错误';    }}

验证方法支持传入的参数包括 value rule 和 $data三个,并且第三个参数支持引用传参。

并且需要注意的是,自定义的验证规则方法名不能和已有的规则冲突。

接下来,就可以这样进行验证:

$validate = Loader::validate('User');if(!$validate->check($data)){    dump($validate->getError());}

如果没有使用验证器类,则支持使用extend方法扩展验证规则,例如:

$validate = new Validate(['name' => 'checkName:1']);$validate->extend('checkName', function ($value, $rule) {    return $rule == $value ? true : '名称错误';});$data   = ['name' => 1];$result = $validate->check($data);

支持批量注册验证规则,例如:

$validate = new Validate(['name' => 'checkName:1']);$validate->extend([    'checkName'=> function ($value, $rule) {    return $rule == $value ? true : '名称错误';},    'checkStatus'=> [$this,'checkStatus']]);$data   = ['name' => 1];$result = $validate->check($data);

设置字段信息

V5.0.4+版本开始,验证类的架构方法支持传入field参数批量设置字段的描述信息,例如:

$rule = [    'name'  => 'require|max:25',    'age'   => 'number|between:1,120',    'email' => 'email',];$field = [    'name'  => '名称',    'age'   => '年龄',    'email' => '邮箱',    ];$data = [    'name'  => 'thinkphp',    'age'   => 10,    'email' => 'thinkphp@qq.com',];$validate = new Validate($rule, [] , $field);$result   = $validate->check($data);

3.错误信息

1)使用默认的错误提示信息

$rule = [    'name'  => 'require|max:25',    'age'   => 'number|between:1,120',    'email' => 'email',];

​ age只能在 1 - 120 之间`。

4.验证场景

namespace app\index\validate;use think\Validate;class User extends Validate{    protected $rule =   [        'name'  => 'require|max:25',        'age'   => 'number|between:1,120',        'email' => 'email',        ];    protected $message  =   [        'name.require' => '名称必须',        'name.max'     => '名称最多不能超过25个字符',        'age.number'   => '年龄必须是数字',        'age.between'  => '年龄只能在1-120之间',        'email'        => '邮箱格式错误',        ];    protected $scene = [        'edit'  =>  ['name','age'],    ];}
$data = [    'name'  => 'thinkphp',    'age'   => 10,    'email' => 'thinkphp@qq.com',];$validate = new Validate($rule);$result = $validate->scene('edit')->check($data);

定义场景规则重新设置

namespace app\index\validate;use think\Validate;class User extends Validate{    protected $rule =   [        'name'  => 'require|max:25',        'age'   => 'number|between:1,120',        'email' => 'email',        ];    protected $message  =   [        'name.require' => '名称必须',        'name.max'     => '名称最多不能超过25个字符',        'age.number'   => '年龄必须是数字',        'age.between'  => '年龄只能在1-120之间',        'email'        => '邮箱格式错误',        ];    protected $scene = [        'edit'  =>  ['name','age'=>'require|number|between:1,120'],    ];
$rule = [    'name'  => 'require|max:25',    'age'   => 'number|between:1,120',    'email' => 'email',];$msg = [    'name.require' => '名称必须',    'name.max'     => '名称最多不能超过25个字符',    'age.number'   => '年龄必须是数字',    'age.between'  => '年龄只能在1-120之间',    'email'        => '邮箱格式错误',];$data = [    'name'  => 'thinkphp',    'age'   => 10,    'email' => 'thinkphp@qq.com',];$validate = new Validate($rule);$validate->scene('edit', function($key,$data){    return 'email'==$key && isset($data['id'])? true : false;});$result = $validate->scene('edit')->check($data);

5.控制器验证

继承\think\Controller

namespace app\index\validate;use think\Validate;class User extends Validate{    protected $rule = [        'name'  =>  'require|max:25',        'email' =>  'email',    ];    protected $message = [        'name.require'  =>  '用户名必须',        'email' =>  '邮箱格式错误',    ];    protected $scene = [        'add'   =>  ['name','email'],        'edit'  =>  ['email'],    ];}

控制器的验证代码简化为:

$result = $this->validate($data,'User');if(true !== $result){    // 验证失败 输出错误信息    dump($result);}

场景验证:

$result = $this->validate($data,'User.edit');if(true !== $result){    // 验证失败 输出错误信息    dump($result);}

6.模型验证

$User = new User;$result = $User->validate(    [        'name'  => 'require|max:25',        'email'   => 'email',    ],    [        'name.require' => '名称必须',        'name.max'     => '名称最多不能超过25个字符',        'email'        => '邮箱格式错误',    ])->save($data);if(false === $result){    // 验证失败 输出错误信息    dump($User->getError());}

模型验证代码

$User = new User;// 调用当前模型对应的User验证器类进行数据验证$result = $User->validate(true)->save($data);if(false === $result){    // 验证失败 输出错误信息    dump($User->getError());}

调用不是当前的模型名称

$User = new User;// 调用当前模型对应的User验证器类进行数据验证$result = $User->validate(true)->save($data);if(false === $result){    // 验证失败 输出错误信息    dump($User->getError());}

7.内置规则

require 字段

‘name’ => ‘require’,

number或者integer

‘num’ => ‘number’

float

‘num’ => ‘float

boolean’

‘num’ => ‘boolean’

email

‘email’ => ‘email’

array

‘info’ => ‘array’

accepted 字段为yes on 1

‘accept’ => ‘accepted’

date 日期

‘date’ => ‘date’

alpha 字母

‘name’ => ‘alpha’

alphaNum 字母和数字

‘name’ => ‘alphaNum’

alphaDash 字母和数字,下划线,破折号

‘name’ => ‘alphaDash’

activeUrl 域名或者Ip

‘host’ => ‘activeURL’

url URL地址

‘url’ => ‘url’

ip Ip地址

‘ip’ =>’ip’

dateFormat:format

‘create_time’ => ‘dateFormat:y-m-d’

长度和区间验证类

in

num => ‘in:1,2,3’

notin 不在某个范围 同上

between

‘num’ => ‘between:1,10’

notBetween

length

num => ‘length:4,15’

指定长度

num => ‘length:4’

max:number

‘name’ => ‘max:25’

min:number

after:日期 某个字段值是否在某个日期之后

‘begin_time’ => ‘after:2016-1-32’

before 某个字段值是否在某个日期之前

'end_time'   => 'before:2016-10-01',

allowip ip在某个范围中

'name'   => 'allowIp:114.45.4.55',

denyip ip是否禁止访问

expire:开始时间,结束时间

验证当前操作(注意不是某个值)是否在某个有效日期之内,例如:

'expire_time'   => 'expire:2016-2-1,2016-10-01',

字段比较类

confirm

验证某个字段是否和另外一个字段的值一致,例如:

'repassword'=>'require|confirm:password'

5.0.4+版本开始,增加了字段自动匹配验证规则,如password和password_confirm是自动相互验证的,只需要使用

'password'=>'require|confirm'

会自动验证和password_confirm进行字段比较是否一致,反之亦然。

different

验证某个字段是否和另外一个字段的值不一致,例如:

'name'=>'require|different:account'

egt 或者 >=

验证是否大于等于某个值,例如:

'score'=>'egt:60''num'=>'>=:100'

gt 或者 >

验证是否大于某个值,例如:

'score'=>'gt:60''num'=>'>:100'

elt 或者 <=

验证是否小于等于某个值,例如:

'score'=>'elt:100''num'=>'<=:100'

lt 或者 <

验证是否小于某个值,例如:

'score'=>'lt:100''num'=>'<:100'

eq 或者 = 或者 same

验证是否等于某个值,例如:

'score'=>'eq:100''num'=>'=:100''num'=>'same:100'

filter验证

支持使用filter_var进行验证,例如:

'ip'=>'filter:validate_ip'

正则验证

支持直接使用正则验证,例如:

'zip'=>'\d{6}',// 或者'zip'=>'regex:\d{6}',

如果你的正则表达式中包含有|符号的话,必须使用数组方式定义。

'accepted'=>['regex'=>'/^(yes|on|1)$/i'],

也可以实现预定义正则表达式后直接调用,例如:

上传验证

file

验证是否是一个上传文件

image:width,height,type

验证是否是一个图像文件,width height和type都是可选,width和height必须同时定义。

fileExt:允许的文件后缀

验证上传文件后缀

fileMime:允许的文件类型

验证上传文件类型

fileSize:允许的文件字节大小

验证上传文件大小

行为验证

使用行为验证数据,例如:

'data'=>'behavior:\app\index\behavior\Check'

其它验证

unique:table,field,except,pk

验证当前请求的字段值是否为唯一的,例如:

// 表示验证name字段的值是否在user表(不包含前缀)中唯一'name'   => 'unique:user',// 验证其他字段'name'   => 'unique:user,account',// 排除某个主键值'name'   => 'unique:user,account,10',// 指定某个主键值排除'name'   => 'unique:user,account,10,user_id',

如果需要对复杂的条件验证唯一,可以使用下面的方式:

// 多个字段验证唯一验证条件'name'   => 'unique:user,status^account',// 复杂验证条件'name'   => 'unique:user,status=1&account='.$data['account'],

requireIf:field,value

验证某个字段的值等于某个值的时候必须,例如:

// 当account的值等于1的时候 password必须'password'=>'requireIf:account,1'

requireWith:field

验证某个字段有值的时候必须,例如:

// 当account有值的时候password字段必须'password'=>'requireWith:account'

8.静态调用

Validate::dateFormat('2016-03-09','Y-m-d'); // true// 验证是否有效的日期Validate::is('2016-06-03','date'); // true// 验证是否有效邮箱地址Validate::is('thinkphp@qq.com','email'); // true// 验证是否在某个范围Validate::in('a',['a','b','c']); // true// 验证是否大于某个值Validate::gt(10,8); // true// 正则验证Validate::regex(100,'\d+'); // true

9表单令牌

表单令牌


验证规则支持对表单的令牌验证,首先需要在你的表单里面增加下面隐藏域:

<input type="hidden" name="__token__" value="{$Request.token}" />

或者

{:token()}

然后在你的验证规则中,添加token验证规则即可,例如,如果使用的是验证器的话,可以改为:

    protected $rule = [        'name'  =>  'require|max:25|token',        'email' =>  'email',    ];

如果你的令牌名称不是__token__,则表单需要改为:

<input type="hidden" name="__hash__" value="{$Request.token.__hash__}" />

或者:

{:token('__hash__')}

验证器中需要改为:

    protected $rule = [        'name'  =>  'require|max:25|token:__hash__',        'email' =>  'email',    ];

如果需要自定义令牌生成规则,可以调用Request类的token方法,例如:

namespace app\index\controller;use think\Controller;class Index extends Controller{    public function index()    {        $token = $this->request->token('__token__', 'sha1');        $this->assign('token', $token);        return $this->fetch();    }}

然后在模板表单中使用:

<input type="hidden" name="__token__" value="{$token}" />

或者不需要在控制器写任何代码,直接在模板中使用:

{:token('__token__', 'sha1')}

10杂项

缓存


概述

ThinkPHP采用think\Cache类提供缓存功能支持。

版本新增功能
5.0.2增加remember方法

设置

缓存支持采用驱动方式,所以缓存在使用之前,需要进行连接操作,也就是缓存初始化操作。

$options = [    // 缓存类型为File    'type'  =>  'File',     // 缓存有效期为永久有效    'expire'=>  0,     //缓存前缀    'prefix'=>  'think'     // 指定缓存目录    'path'  =>  APP_PATH.'runtime/cache/',];Cache::connect($options);

或者通过定义配置参数的方式,在应用配置文件中添加:

'cache'  => [    'type'   => 'File',    'path'   => CACHE_PATH,    'prefix' => '',    'expire' => 0,],

支持的缓存类型包括file、memcache、wincache、sqlite、redis和xcache。

缓存参数根据不同的缓存方式会有所区别,通用的缓存参数如下:

参数描述
type缓存类型
expire缓存有效期 (默认为0 表示永久缓存)
prefix缓存前缀(默认为空)

使用

缓存初始化之后,就可以进行相关缓存操作了。

如果通过配置文件方式定义缓存参数的话,可以无需手动进行缓存初始化操作,可以直接进行缓存读取和设置等操作。

设置缓存

设置缓存有效期

Cache::set('name',$value,3600);

如果设置成功返回true,否则返回false。

缓存自增

针对数值类型的缓存数据,可以使用自增操作,例如:

// name自增(步进值为1)Cache::inc('name');// name自增(步进值为3)Cache::inc('name',3);

缓存自减

针对数值类型的缓存数据,可以使用自减操作,例如:

// name自减(步进值为1)Cache::dec('name');// name自减(步进值为3)Cache::dec('name',3);

获取缓存

获取缓存数据可以使用:

dump(Cache::get('name')); 

如果name值不存在,则默认返回 false

支持指定默认值,例如:

dump(Cache::get('name','')); 

表示如果name值不存在,则返回空字符串。

删除缓存

Cache::rm('name'); 

获取并删除缓存

Cache::pull('name'); 

如果name值不存在,则返回null

清空缓存

Cache::clear(); 

不存在则写入缓存数据后返回(v5.0.2+

Cache::remember('name',function(){    return time();});

助手函数

系统对缓存操作提供了助手函数cache,用法如下:

$options = [     // 缓存类型为File    'type'   => 'File',      // 缓存有效期为永久有效    'expire' => 0,     // 指定缓存目录    'path'   => APP_PATH . 'runtime/cache/', ];// 缓存初始化// 不进行缓存初始化的话,默认使用配置文件中的缓存配置cache($options);// 设置缓存数据cache('name', $value, 3600);// 获取缓存数据var_dump(cache('name'));// 删除缓存数据cache('name', NULL);// 设置缓存的同时并且进行参数设置cache('test', $value, $options); 

缓存标签

支持给缓存数据打标签,例如:

Cache::tag('tag')->set('name1','value1');Cache::tag('tag')->set('name2','value2');// 或者批量设置缓存标签Cache::set('name1','value1');Cache::set('name2','value2');Cache::tag('tag',['name1','name2']);// 清除tag标签的缓存数据Cache::clear('tag');

同时使用多个缓存类型

如果要同时使用多个缓存类型进行操作的话,可以做如下配置:

'cache' =>  [    // 使用复合缓存类型    'type'  =>  'complex',    // 默认使用的缓存    'default'   =>  [        // 驱动方式        'type'   => 'File',        // 缓存保存目录        'path'   => CACHE_PATH,    ],    // 文件缓存    'file'   =>  [        // 驱动方式        'type'   => 'file',        // 设置不同的缓存保存目录        'path'   => RUNTIME_PATH . 'file/',    ],      // redis缓存    'redis'   =>  [        // 驱动方式        'type'   => 'redis',        // 服务器地址        'host'       => '127.0.0.1',    ],     ],

cache.type配置为complex之后,就可以缓存多个缓存类型和缓存配置,每个缓存配置的方法和之前一样,并且你可以给相同类型的缓存类型(使用不同的缓存标识)配置不同的缓存配置参数。

当使用

Cache::set('name', 'value');Cache::get('name');

的时候,其实使用的是default缓存标识的缓存配置,如果需要切换到其它的缓存标识操作,可以使用:

// 切换到file操作Cache::store('file')->set('name','value');Cache::get('name');// 切换到redis操作Cache::store('redis')->set('name','value');Cache::get('name');

2.Session

使用think\Session

1)Session初始化

应用配置文件

‘session’ => [

​ ‘prefix’ => ‘think’,

​ ‘type’ => ”

​ ‘auto_start’ => true

];

Session::set(‘name’, ‘thinkphp’);

Session::get(‘name’);

没有使用Session类,使用下面操作

Session::init([

​ ‘prefix’ => ‘module’,

​ ‘type’ => ”,

​ ‘auto_start’ => true

]);

2)设置参数

type session类型

expire session过期时间

prefix session前缀

auto_start 是否自动开启

use_trans_sid是否使用use_trans_sid
var_session_id请求session_id变量名
idsession_id
namesession_name
pathsession保存路径
domainsession cookie_domain
use_cookies是否使用cookie
cache_limitersession_cache_limiter
cache_expiresession_cache_expire

3)基础用法

Session::set(‘name’, ‘thinkphp’);

Session::has(‘name’); //是否存在

Session::get(‘name’); //取值

Session::delete(‘name’); //删除

Session::pull(‘name’); //取值并删除

Session::clear(); //清空

Session::set(‘name.item’, ‘thinkphp’); //二维数组

3.cookie

使用cookie支持

Cookie::init([‘prefix’=>’think_’, ‘expire’=>3600, ‘path’=>’/’]);

Cookie::prefix(‘think_’);

1)设置

Cookie::set(‘name’, ‘value’, 3600);

Cookie::set(‘name’, [1, 2, 3]);

2)判断

Cookie::has(‘name’);

3)获取

Cookie:get(‘name’);

Cookie::get(‘name’, ‘think_’); //获取指定前缀的cookie值

4)清空

Cookie::clear();

4.多语言

使用内置的\think\Lang类提供多语言支持

1)开启和加载语言包

应用配置文件

‘default_lang’ => ‘zh-cn’

开启多语言切换

‘lang_switch_on’ => true;

开启后,系统自动检测当前语言

1是否有$_GET[‘lang’]

2.识别$_SERVER[‘HTTP_ACCEPT_LANGUAGE’]

语言文件定义

系统会默认加载下面三个语言包:

框架语言包: thinkphp\lang\当前语言.php应用语言包: application\lang\当前语言.php模块语言包: application\模\lang\当前语言.php

如果你还需要加载其他的语言包,可以在设置或者自动检测语言之后,用load方法进行加载:

Lang::load(APP_PATH . 'common\lang\zh-cn.php');

ThinkPHP语言文件定义采用返回数组方式:

return [     'hello thinkphp'  => '欢迎使用ThinkPHP',     'data type error' => '数据类型错误',];

也可以在程序里面动态设置语言定义的值,使用下面的方式:

Lang::set('define2','语言定义');$value = Lang::get('define2');

通常多语言的使用是在控制器里面,但是模型类的自动验证功能里面会用到提示信息,这个部分也可以使用多语言的特性。例如原来的方式是把提示信息直接写在模型里面定义:

['title','require','标题必须!',1],

如果使用了多语言功能的话(假设,我们在当前语言包里面定义了’ lang_var’=>’标题必须!’),就可以这样定义模型的自动验证

['title','require','{%lang_var}',1],

如果要在模板中输出语言变量不需要在控制器中赋值,可以直接使用模板引擎特殊标签来直接输出语言定义的值:

{$Think.lang.lang_var}

可以输出当前语言包里面定义的 lang_var语言定义。

变量传入支持

语言包定义的时候支持传入变量,有两种方式

使用命名绑定方式,例如:

'file_format'    =>    '文件格式: {:format},文件大小:{:size}',

在模板中输出语言字符串的时候传入变量值即可:

{:lang('file_format',['format' => 'jpeg,png,gif,jpg','size' => '2MB'])}

第二种方式是使用格式字串,如果你需要使用第三方的翻译工具,建议使用该方式定义变量。

'file_format'    =>    '文件格式: %s,文件大小:%d',

在模板中输出多语言的方式更改为:

{:lang('file_format',['jpeg,png,gif,jpg','2MB'])}

5.分页

Thinkphp5.0内置分页实现,使用Db类查询调用paginate方法

$list = Db::name(‘user’)->where(‘status’, 1)->paginate(10);

$this->assign('list', $list);

return $this->fetch();

模版文件中分页输出代码

<div><ul>{volist name='list' id='user'}    <li> {$user.nickname}</li>{/volist}</ul></div>{$list->render()}

单独模版变量

// 查询状态为1的用户数据 并且每页显示10条数据$list = User::where('status',1)->paginate(10);// 获取分页显示$page = $list->render();// 模板变量赋值$this->assign('list', $list);$this->assign('page', $page);// 渲染模板输出return $this->fetch();
<div><ul>{volist name='list' id='user'}    <li> {$user.nickname}</li>{/volist}</ul></div>

1)传入总记录数

// 查询状态为1的用户数据 并且每页显示10条数据 总记录数为1000$list = User::where('status',1)->paginate(10,1000);// 获取分页显示$page = $list->render();// 模板变量赋值$this->assign('list', $list);$this->assign('page', $page);// 渲染模板输出return $this->fetch();

2)简洁分页

输出仅仅只有上下页的分页输出

// 查询状态为1的用户数据 并且每页显示10条数据$list = User::where('status',1)->paginate(10,true);// 把分页数据赋值给模板变量list$this->assign('list', $list);// 渲染模板输出return $this->fetch();

简洁分页模式输出代码

<ul class="pager"><li><a href="?page=1">&laquo;</a></li><li class="disabled"><span>&raquo;</span></li></ul>

分页参数

主要的分页参数如下:参数描述
list_rows每页数量
page当前页
pathurl路径
queryurl额外参数
fragmenturl锚点
var_page分页变量
type分页类名

分页参数的设置方式有两种,第一种是在配置文件中定义,例如:

//分页配置'paginate'               => [    'type'     => 'bootstrap',    'var_page' => 'page',],

type属性支持命名空间,例如:

//分页配置'paginate'               => [    'type'     => '\org\page\bootstrap',    'var_page' => 'page',],

也可以在调用分页方法的时候传入,例如:

$list = Db::name('user')->where('status',1)->paginate(10,true,[    'type'     => 'bootstrap',    'var_page' => 'page',]);

6.文件上传

1)上传文件

表单代码

<form action="/index/index/upload" enctype="multipart/form-data" method="post"><input type="file" name="image" /> <br> <input type="submit" value="上传" /> </form> 

控制器代码

public function upload()

{

​ $file = request()->file(‘image’);

`$info = $file->move(ROOT_PATH.'public'.DB.'uploads');

​ if ($info){

​ echo $info->getExtension();

​ echo $info->getSaveName();

​ echo $info->getFileName()

​ }else{

​ echo $file->getError();

}

}

2)多文件上传

<form action="/index/index/upload" enctype="multipart/form-data" method="post"><input type="file" name="image[]" /> <br> <input type="file" name="image[]" /> <br> <input type="file" name="image[]" /> <br> <input type="submit" value="上传" /> </form> 
public function upload(){    // 获取表单上传文件    $files = request()->file('image');    foreach($files as $file){        // 移动到框架应用根目录/public/uploads/ 目录下        $info = $file->move(ROOT_PATH . 'public' . DS . 'uploads');        if($info){            // 成功上传后 获取上传信息            // 输出 jpg            echo $info->getExtension();             // 输出 42a79759f284b767dfcb2a0197904287.jpg            echo $info->getFilename();         }else{            // 上传失败获取错误信息            echo $file->getError();        }        }}

3)上传验证

public function upload(){    // 获取表单上传文件 例如上传了001.jpg    $file = request()->file('image');    // 移动到框架应用根目录/public/uploads/ 目录下    $info = $file->validate(['size'=>15678,'ext'=>'jpg,png,gif'])->move(ROOT_PATH . 'public' . DS . 'uploads');    if($info){        // 成功上传后 获取上传信息        // 输出 jpg        echo $info->getExtension();        // 输出 20160820/42a79759f284b767dfcb2a0197904287.jpg        echo $info->getSaveName();        // 输出 42a79759f284b767dfcb2a0197904287.jpg        echo $info->getFilename();     }else{        // 上传失败获取错误信息        echo $file->getError();    }}

4)上传规则(修改文件命名)

$file = request()->file(‘image’);

$file->rule(‘md5’)->move(‘/home/www/upload’);

date 根据日期和微妙数生成

md5 对文件使用MD5

sha1 对文件使用sha1_file散列生成

// 获取表单上传文件 例如上传了001.jpg$file = request()->file('image');// 移动到服务器的上传目录 并且使用原文件名$file->move('/home/www/upload/','');

5)获取文件hash散列值

// 获取表单上传文件$file = request()->file('image');// 移动到服务器的上传目录 并且使用原文件名$upload = $file->move('/home/www/upload/');// 获取上传文件的hash散列值echo $upload->md5();echo $upload->sha1();

7.图像处理

使用composer安装Thinkphp5图像处理类库

composer require topthink/think -image

$image = \think\Image::open(‘./image.png’); //打开图像

$image= \think\Image::open(request()->file(‘image’)); //从请求中的文件上传对象

1)获取图像信息

$image = \think\Image::open('./image.png');// 返回图片的宽度$width = $image->width(); // 返回图片的高度$height = $image->height(); // 返回图片的类型$type = $image->type(); // 返回图片的mime类型$mime = $image->mime(); // 返回图片的尺寸数组 0 图片宽度 1 图片高度$size = $image->size(); 

2)剪裁图片

$image = \think\Image::open('./image.png');//将图片裁剪为300x300并保存为crop.png$image->crop(300, 300)->save('./crop.png');
$image = \think\Image::open('./image.png');//将图片裁剪为300x300并保存为crop.png$image->crop(300, 300,100,30)->save('./crop.png');

3)生成缩略图

$image = \think\Image::open('./image.png');// 按照原图的比例生成一个最大为150*150的缩略图并保存为thumb.png$image->thumb(150, 150)->save('./thumb.png');

我们看到实际生成的缩略图并不是150*150,因为默认采用原图等比例缩放的方式生成缩略图,最大宽度是150。

可以支持其他类型的缩略图生成,设置包括\think\Image的下列常量或者对应的数字:

//常量,标识缩略图等比例缩放类型const THUMB_SCALING   = 1; //常量,标识缩略图缩放后填充类型const THUMB_FILLED    = 2; //常量,标识缩略图居中裁剪类型const THUMB_CENTER    = 3; //常量,标识缩略图左上角裁剪类型const THUMB_NORTHWEST = 4;//常量,标识缩略图右下角裁剪类型const THUMB_SOUTHEAST = 5; //常量,标识缩略图固定尺寸缩放类型const THUMB_FIXED     = 6; 

居中剪裁

$image = \think\Image::open('./image.png');// 按照原图的比例生成一个最大为150*150的缩略图并保存为thumb.png$image->thumb(150,150,\think\Image::THUMB_CENTER)->save('./thumb.png');

右下角剪裁

$image = \think\Image::open('./image.png');// 按照原图的比例生成一个最大为150*150的缩略图并保存为thumb.png$image->thumb(150,150,\think\Image::THUMB_SOUTHEAST)->save('./thumb.png');

图像反转180

$image = \think\Image::open('./image.png');// 对图像进行以x轴进行翻转操作$image->flip()->save('./filp_image.png');

轴反转

$image = \think\Image::open('./image.png');// 对图像进行以y轴进行翻转操作$image->flip(\think\image::FLIP_Y)->save('./filp_image.png');

图像90度反转

$image = \think\Image::open('./image.png');// 对图像使用默认的顺时针旋转90度操作$image->rotate()->save('./rotate_image.png');

图像保存参数

save方法可以配置的参数参数默认描述
pathname必填项图像保存路径名称
type默认与原图相同图像类型
quality80图像质量
interlacetrue是否对JPEG类型图像设置隔行扫描

添加水印

$image = \think\Image::open('./image.png');// 给原图左上角添加水印并保存water_image.png$image->water('./logo.png')->save('water_image.png'); 

water方法的第二个参数表示水印的位置,默认值是WATER_SOUTH,可以传入下列\think\Image类的常量或者对应的数字:

//常量,标识左上角水印const WATER_NORTHWEST = 1; //常量,标识上居中水印const WATER_NORTH     = 2; //常量,标识右上角水印const WATER_NORTHEAST = 3; //常量,标识左居中水印const WATER_WEST      = 4; //常量,标识居中水印const WATER_CENTER    = 5; //常量,标识右居中水印const WATER_EAST      = 6; //常量,标识左下角水印const WATER_SOUTHWEST = 7; //常量,标识下居中水印const WATER_SOUTH     = 8; //常量,标识右下角水印const WATER_SOUTHEAST = 9; 

左上角进行测试

$image = \think\Image::open('./image.png');// 给原图左上角添加水印并保存water_image.png$image->water('./logo.png',\think\Image::WATER_NORTHWEST)->save('water_image.png');

水印透明度

$image = \think\Image::open('./image.png');// 给原图左上角添加透明度为50的水印并保存alpha_image.png$image->water('./logo.png',\think\Image::WATER_NORTHWEST,50)->save('alpha_image.png');

8.文件处理

使用\think\File文件处理类

9.验证码

composer require topthink/think -captcha

验证码配置

'captcha'  => [        // 验证码字符集合        'codeSet'  => '2345678abcdefhijkmnpqrstuvwxyzABCDEFGHJKLMNPQRTUVWXY',         // 验证码字体大小(px)        'fontSize' => 25,         // 是否画混淆曲线        'useCurve' => true,          // 验证码图片高度        'imageH'   => 30,        // 验证码图片宽度        'imageW'   => 100,         // 验证码位数        'length'   => 5,         // 验证成功后是否重置                'reset'    => true],

验证码显示

<div>{:captcha_img()}</div>

或者

<div><img src="{:captcha_src()}" alt="captcha" /></div>

控制器验证(添加captcha验证规则)

$this->validate($data,[    'captcha|验证码'=>'require|captcha']);

9.单元测试

composer require topthink/think -testing

安装完成,根目录下面增加tests目录和phpunit.xml文件

php think unit

1)添加单元测试文件

tests/IndexTest.php

<?phpuse tests\TestCase;class IndexTest extends TestCase{    public function testSomethingIsTrue()    {        $this->assertTrue(true);    }}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值