ThinkPHP采用单一入口模式访问应用,对应用的全部请求都定向到应用的入口文件,系统会从URL参数中解析当前请求的模块、控制器和操做,下面是一个标准的URL访问格式:
http://serverName/index.php/模块/控制器/操做javascript
若是咱们直接访问入口文件的话,因为URL中没有模块、控制器和操做,所以系统会访问默认模块(Home)下面的默认控制器(Index)的默认操做(index),所以下面的访问是等效的:php
http://serverName/index.php
http://serverName/index.php/Home/Index/index
复制代码
这种URL模式就是系统默认的PATHINFO模式,不一样的URL模式获取模块和操做的方法不一样,ThinkPHP支持的URL模式有四种:普通模式、PATHINFO、REWRITE和兼容模式。html
这里用到了M函数,是ThinkPHP内置的实例化模型的方法,并且用M方法实例化模型不须要建立对应的模型类,你能够理解为M方法是直接在操做底层的Model类,而Model类具有基本的CURD操做方法。java
M('Data') 实例化后,就能够对think_data数据表(think_ 是咱们在项目配置文件中定义的数据表前缀)进行操做(包括CURD)了,M函数的用法还有不少,咱们之后会深刻了解。linux
CURD是一个数据库技术中的缩写词,通常的项目开发的各类参数的基本功能都是CURD。它表明建立(Create)、更新(Update)、读取(Read)和删除(Delete)操做。CURD 定义了用于处理数据的基本原子操做。之因此将CURD 提高到一个技术难题的高度是由于完成一个涉及在多个数据库系统中进行CURD操做的汇总相关的活动,其性能可能会随数据关系的变化而有很是大的差别。ajax
CURD在具体的应用中并不是必定使用create、update 、read和delete字样的方法,可是他们完成的功能是一致的正则表达式
咱们并无在控制器里面定义add操做方法,可是很显然,访问是正常的。由于ThinkPHP在没有找到对应操做方法的状况下,会检查是否存在对应的模板文件,因为咱们有对应的add模板文件,因此控制器就直接渲染该模板文件输出了。因此说对于没有任何实际逻辑的操做方法,咱们只须要直接定义对应的模板文件就好了。sql
在insert操做方法中用了D函数,和M函数不一样,D函数须要有对应的模型类,下面咱们就来建立模型类。thinkphp
若是你的数据彻底是内部操做写入而不是经过表单的话(也就是说能够充分信任数据的安全),那么能够直接使用add方法,如:数据库
$Form = D('Form');
$data['title'] = 'ThinkPHP';
$data['content'] = '表单内容';
$Form->add($data);
也能够支持对象方式操做:
$Form = D('Form');
$Form->title = 'ThinkPHP';
$Form->content = '表单内容';
$Form->add();
对象方式操做的时候,add方法无需传入数据,会自动识别当前的数据对象赋值。
这里之因此用M方法而没有用D方法,是由于find方法是基础模型类Model中的方法,因此没有必要浪费开销去实例化FormModel类(即便已经定义了FormModel类)。咱们一般采用find方法读取某个数据
若是你只须要查询某个字段的值,还可使用getField方法,
例如:
$Form = M("Form");
// 获取标题
$title = $Form->where('id=3')->getField('title');
上面的用法表示获取id值为3的数据的title字段值。其实getField方法有不少用法,可是获取某个字段的值是getField方法最常规的用法。
查询操做是最经常使用的操做,尤为是涉及到复杂的查询条件,咱们会在查询语言一章对查询进行更加详细的讲解。
数据的更新操做在ThinkPHP使用save方法,能够看到,咱们一样可使用create方法建立表单提交的数据,而save方法则会自动把当前的数据对象更新到数据库,而更新的条件其实就是表的主键,这就是咱们在编辑页面要把主键的值做为隐藏字段一块儿提交的缘由。
有些时候,咱们只须要修改某个字段的值,就可使用setField方法,而不须要每次都调用save方法。
咱们掌握了基本的数据CURD方法,但更多的状况下面,因为业务逻辑的差别,CURD操做每每不是那么简单,尤为是复杂的业务逻辑下面,这也是ActiveRecord模式的不足之处。ThinkPHP的查询语言配合连贯操做能够很好解决复杂的业务逻辑需求,本篇咱们就首先来深刻了解下框架的查询语言。
介绍
ThinkPHP内置了很是灵活的查询方法,能够快速的进行数据查询操做,查询条件能够用于读取、更新和删除等操做,主要涉及到where方法等连贯操做便可,不管是采用什么数据库,你几乎采用同样的查询方法(个别数据库例如Mongo在表达式查询方面会有所差别),系统帮你解决了不一样数据库的差别性,所以咱们把框架的这一查询方式称之为查询语言。查询语言也是ThinkPHP框架的ORM亮点,让查询操做更加简单易懂
1、使用字符串做为查询条件
$User = M("User"); // 实例化User对象
$User->where('type=1 AND status=1')->select();
2、使用数组做为查询条件(把多个条件复制给数组 最后传入条件数组)
$User = M("User"); // 实例化User对象
$condition['name'] = 'thinkphp';
$condition['status'] = 1;
// 把查询条件传入查询方法
经过使用 _logic 定义查询逻辑:$condition['_logic'] = 'OR'; 还有and
$User->where($condition)->select();
3、使用对象方式来查询
$User = M("User"); // 实例化User对象
// 定义查询条件
$condition = new stdClass();
$condition->name = 'thinkphp';
$condition->status= 1;
$User->where($condition)->select();
使用对象方式查询和使用数组查询的效果是相同的,而且是能够互换的,大多数状况下,咱们建议采用数组方式更加高效。
表达式查询
上面的查询条件仅仅是一个简单的相等判断,可使用查询表达式支持更多的SQL查询语法,也是ThinkPHP查询语言的精髓,查询表达式的使用格式:
$map['字段名'] = array('表达式','查询条件');
表达式 含义
EQ 等于(=)
NEQ 不等于(<>)
GT 大于(>)
EGT 大于等于(>=)
LT 小于(<)
ELT 小于等于(<=)
LIKE 模糊查询
[NOT] BETWEEN (不在)区间查询
[NOT] IN (不在)IN 查询
EXP 表达式查询,支持SQL语法
示例以下:
EQ :等于(=)
例如:
$map['id'] = array('eq',100);
和下面的查询等效
$map['id'] = 100;
表示的查询条件就是id = 100
NEQ: 不等于(<>)
例如:
$map['id'] = array('neq',100);
表示的查询条件就是 id <> 100
GT:大于(>)
例如:
$map['id'] = array('gt',100);
表示的查询条件就是 id > 100
快捷查询
采用快捷查询方式,能够进一步简化查询条件的写法,例如:
1、实现不一样字段相同的查询条件
$User = M("User"); // 实例化User对象
$map['name|title'] = 'thinkphp';
// 把查询条件传入查询方法
$User->where($map)->select();
查询条件就变成
name= 'thinkphp' OR title = 'thinkphp'
2、实现不一样字段不一样的查询条件
$User = M("User"); // 实例化User对象
$map['status&title'] =array('1','thinkphp','_multi'=>true);
// 把查询条件传入查询方法
$User->where($map)->select();
'_multi'=>true必须加在数组的最后,表示当前是多条件匹配,这样查询条件就变成
status= 1 AND title = 'thinkphp'
,查询字段支持更多的,例如:
$map['status&score&title'] =array('1',array('gt','0'),'thinkphp','_multi'=>true);
查询条件就变成
status= 1 AND score >0 AND title = 'thinkphp'
注意:快捷查询方式中“|”和“&”不能同时使用。
区间查询
ThinkPHP支持对某个字段的区间查询,例如:
$map['id'] = array(array('gt',1),array('lt',10),'and') ;
获得的查询条件是:
(`id` > 1) AND (`id` < 10)
最后一个能够是AND、 OR或者 XOR运算符,若是不写,默认是AND运算。
区间查询的条件能够支持普通查询的全部表达式,也就是说相似LIKE、GT和EXP这样的表达式均可以支持。另外区间查询还能够支持更多的条件,只要是针对一个字段的条件均可以写到一块儿,例如:
$map['name'] = array(array('like','%a%'), array('like','%b%'), array('like','%c%'), 'ThinkPHP','or');
最后的查询条件是:
(`name` LIKE '%a%') OR (`name` LIKE '%b%') OR (`name` LIKE '%c%') OR (`name` = 'ThinkPHP')
组合查询
组合查询的主体仍是采用数组方式查询,只是加入了一些特殊的查询支持,包括字符串模式查询(_string)、复合查询(_complex)、请求字符串查询(_query),混合查询中的特殊查询每次查询只能定义一个,因为采用数组的索引方式,索引相同的特殊查询会被覆盖。
1、字符串模式查询(采用_string 做为查询条件)
数组条件还能够和字符串条件混合使用,例如:
$User = M("User"); // 实例化User对象
$map['id'] = array('neq',1);
$map['name'] = 'ok';
$map['_string'] = 'status=1 AND score>10';
$User->where($map)->select();
最后获得的查询条件就成了:
( `id` != 1 ) AND ( `name` = 'ok' ) AND ( status=1 AND score>10 )
2、请求字符串查询方式
请求字符串查询是一种相似于URL传参的方式,能够支持简单的条件相等判断。
$map['id'] = array('gt','100');
$map['_query'] = 'status=1&score=100&_logic=or';
获得的查询条件是:
`id`>100 AND (`status` = '1' OR `score` = '100')
3、复合查询
复合查询至关于封装了一个新的查询条件,而后并入原来的查询条件之中,因此能够完成比较复杂的查询条件组装。
例如:
$where['name'] = array('like', '%thinkphp%');
$where['title'] = array('like','%thinkphp%');
$where['_logic'] = 'or';
$map['_complex'] = $where;
$map['id'] = array('gt',1);
查询条件是
( id > 1) AND ( ( name like '%thinkphp%') OR ( title like '%thinkphp%') )
复合查询使用了_complex做为子查询条件来定义,配合以前的查询方式,能够很是灵活的制定更加复杂的查询条件。
不少查询方式能够相互转换,例如上面的查询条件能够改为:
$where['id'] = array('gt',1);
$where['_string'] = ' (name like "%thinkphp%") OR ( title like "%thinkphp") ';
复制代码
最后生成的SQL语句是一致的。
统计查询
在应用中咱们常常会用到一些统计数据,例如当前全部(或者知足某些条件)的用户数、全部用户的最大积分、用户的平均成绩等等,ThinkPHP为这些统计操做提供了一系列的内置方法,包括:
方法 说明
Count 统计数量,参数是要统计的字段名(可选)
Max 获取最大值,参数是要统计的字段名(必须)
Min 获取最小值,参数是要统计的字段名(必须)
Avg 获取平均值,参数是要统计的字段名(必须)
Sum 获取总分,参数是要统计的字段名(必须)
用法示例:
$User = M("User"); // 实例化User对象
// 获取用户数:
$userCount = $User->count();
// 或者根据字段统计:
$userCount = $User->count("id");
// 获取用户的最大积分:
$maxScore = $User->max('score');
// 获取积分大于0的用户的最小积分:
$minScore = $User->where('score>0')->min('score');
// 获取用户的平均积分:
$avgScore = $User->avg('score');
// 统计用户的总成绩:
$sumScore = $User->sum('score');
复制代码
而且全部的统计查询均支持连贯操做的使用。
SQL查询
ThinkPHP内置的ORM和ActiveRecord模式实现了方便的数据存取操做,并且新版增长的连贯操做功能更是让这个数据操做更加清晰,可是ThinkPHP仍然保留了原生的SQL查询和执行操做支持,为了知足复杂查询的须要和一些特殊的数据操做,SQL查询的返回值由于是直接返回的Db类的查询结果,没有作任何的处理。主要包括下面两个方法:
一、query方法
query 执行SQL查询操做
用法 query($sql,$parse=false)
参数 sql(必须):要查询的SQL语句 parse(可选):是否须要解析SQL
返回值 若是数据非法或者查询错误则返回false,不然返回查询结果数据集(同select方法)
使用示例:
$Model = new Model() // 实例化一个model对象 没有对应任何数据表
$Model->query("select * from think_user where status=1");
若是你当前采用了分布式数据库,而且设置了读写分离的话,query方法始终是在读服务器执行,所以query方法对应的都是读操做,而无论你的SQL语句是什么。
二、execute方法
execute 用于更新和写入数据的sql操做
用法 execute($sql,$parse=false)
参数 sql(必须):要执行的SQL语句 parse(可选):是否须要解析SQL
返回值 若是数据非法或者查询错误则返回false ,不然返回影响的记录数
使用示例:
$Model = new Model() // 实例化一个model对象 没有对应任何数据表
$Model->execute("update think_user set name='thinkPHP' where status=1");
复制代码
若是你当前采用了分布式数据库,而且设置了读写分离的话,execute方法始终是在写服务器执行,所以execute方法对应的都是写操做,而无论你的SQL语句是什么。
动态查询
借助PHP5语言的特性,ThinkPHP实现了动态查询,核心模型的动态查询方法包括下面几种:
方法名 说明 举例
getBy 根据字段的值查询数据 例如,getByName,getByEmail
getFieldBy 根据字段查询并返回某个字段的值 例如,getFieldByName
1、getBy动态查询
该查询方式针对数据表的字段进行查询。例如,User对象拥有id,name,email,address 等属性,那么咱们就可使用下面的查询方法来直接根据某个属性来查询符合条件的记录。
$user = $User->getByName('liu21st');
$user = $User->getByEmail('liu21st@gmail.com');
$user = $User->getByAddress('中国深圳');
暂时不支持多数据字段的动态查询方法,请使用find方法和select方法进行查询。
2、getFieldBy动态查询
针对某个字段查询并返回某个字段的值,例如
$userId = $User->getFieldByName('liu21st','id');
表示根据用户的name获取用户的id值。
子查询
子查询有两种使用方式:
一、使用select方法
当select方法的参数为false的时候,表示不进行查询只是返回构建SQL,例如:
// 首先构造子查询SQL
$subQuery = $model->field('id,name')->table('tablename')->group('field')->where($where)->order('status')->select(false);
当select方法传入false参数的时候,表示不执行当前查询,而只是生成查询SQL。
二、使用buildSql方法
$subQuery = $model->field('id,name')->table('tablename')->group('field')->where($where)->order('status')->buildSql();
调用buildSql方法后不会进行实际的查询操做,而只是生成该次查询的SQL语句(为了不混淆,会在SQL两边加上括号),而后咱们直接在后续的查询中直接调用。
// 利用子查询进行查询
$model->table($subQuery.' a')->where()->order()->select()
构造的子查询SQL可用于ThinkPHP的连贯操做方法,例如table where等。
连贯操做能够有效的提升数据存取的代码清晰度和开发效率,而且支持全部的CURD操做,也是ThinkPHP的ORM中的一个亮点。使用也比较简单, 假如咱们如今要查询一个User表的知足状态为1的前10条记录,并但愿按照用户的建立时间排序 ,代码以下:
$User->where('status=1')->order('create_time')->limit(10)->select();
复制代码
这里的where、order和limit方法就称之为连贯操做方法,除了select方法必须放到最后一个外(由于select方法并非连贯操做方法),连贯操做的方法调用顺序没有前后
连贯操做仅在当次查询或者操做有效,完成后会自动清空连贯操做的全部传值(有个别特殊的连贯操做会记录当前的传值,如cache连贯操做)。简而言之,连贯操做的结果不会带入之后的查询。
系统支持的连贯操做方法有:
方法 做用 支持的参数类型
where* 用于查询或者更新条件的定义 字符串、数组和对象
table 用于定义要操做的数据表名称 字符串和数组
alias 用于给当前数据表定义别名 字符串
data 用于新增或者更新数据以前的数据对象赋值 数组和对象
field 用于定义要查询的字段(支持字段排除) 字符串和数组
order 用于对结果排序 字符串和数组
limit 用于限制查询结果数量 字符串和数字
page 用于查询分页(内部会转换成limit) 字符串和数字
group 用于对查询的group支持 字符串
having 用于对查询的having支持 字符串
join* 用于对查询的join支持 字符串和数组
union* 用于对查询的union支持 字符串、数组和对象
distinct 用于查询的distinct支持 布尔值
lock 用于数据库的锁机制 布尔值
cache 用于查询缓存 支持多个参数(之后在缓存部分再详细描述)
relation 用于关联查询(须要关联模型扩展支持) 字符串
validate 用于数据自动验证 数组
auto 用于数据自动完成 数组
filter 用于数据过滤 字符串
scope* 用于命名范围 字符串、数组
bind* 用于数据绑定操做 数组或多个参数
token 用于令牌验证 布尔值
comment 用于SQL注释 字符串
index 用于数据集的强制索引 字符串
strict 用于数据入库的严格检测 布尔值
全部的连贯操做都返回当前的模型实例对象,其中带*标识的表示支持屡次调用
I方法是ThinkPHP用于更加方便和安全的获取系统输入变量,能够用于任何地方,用法格式以下:
I('变量类型.变量名/修饰符',['默认值'],['过滤方法'],['额外数据源'])
变量类型是指请求方式或者输入类型,包括:
变量类型 含义
get 获取GET参数
post 获取POST参数
param 自动判断请求类型获取GET、POST或者PUT参数
request 获取REQUEST 参数
put 获取PUT 参数
session 获取 $_SESSION 参数
cookie 获取 $_COOKIE 参数
server 获取 $_SERVER 参数
globals 获取 $GLOBALS参数
path 获取 PATHINFO模式的URL参数
data 获取 其余类型的参数,须要配合额外数据源参数
注意:变量类型不区分大小写。
变量名则严格区分大小写。
默认值和过滤方法均属于可选参数。
咱们以GET变量类型为例,说明下I方法的使用:
echo I('get.id'); // 至关于 $_GET['id']
echo I('get.name'); // 至关于 $_GET['name']
支持默认值:
echo I('get.id',0); // 若是不存在$_GET['id'] 则返回0
echo I('get.name',''); // 若是不存在$_GET['name'] 则返回空字符串
采用方法过滤:
// 采用htmlspecialchars方法对$_GET['name'] 进行过滤,若是不存在则返回空字符串
echo I('get.name','','htmlspecialchars');
支持直接获取整个变量类型,例如:
// 获取整个$_GET 数组
I('get.');
用一样的方式,咱们能够获取post或者其余输入类型的变量,例如:
I('post.name','','htmlspecialchars'); // 采用htmlspecialchars方法对$_POST['name'] 进行过滤,若是不存在则返回空字符串
I('session.user_id',0); // 获取$_SESSION['user_id'] 若是不存在则默认为0
I('cookie.'); // 获取整个 $_COOKIE 数组
I('server.REQUEST_METHOD'); // 获取 $_SERVER['REQUEST_METHOD']
param变量类型是框架特有的支持自动判断当前请求类型的变量获取方式,例如:
echo I('param.id');
若是当前请求类型是GET,那么等效于 $_GET['id'],若是当前请求类型是POST或者PUT,那么至关于获取 $_POST['id'] 或者 PUT参数id。
因为param类型是I函数默认获取的变量类型,所以事实上param变量类型的写法能够简化为:
I('id'); // 等同于 I('param.id')
I('name'); // 等同于 I('param.name')
path类型变量能够用于获取PATHINFO方式的URL参数(必须是PATHINFO模式参数有效,不管是GET仍是POST方式都有效)
I方法的全部获取变量若是没有设置过滤方法的话都会进行htmlspecialchars过滤,那么:// 等同于
htmlspecialchars($_GET['name'])
I('get.name');
,该参数也能够设置支持多个过滤,例如:
'DEFAULT_FILTER' => 'strip_tags,htmlspecialchars'
设置后,咱们在使用:
// 等同于 htmlspecialchars(strip_tags($_GET['name']))
I('get.name');
若是咱们在使用I方法的时候 指定了过滤方法,那么就会忽略DEFAULT_FILTER的设置,例如:
// 等同于 strip_tags($_GET['name'])
echo I('get.name','','strip_tags');
过滤名称必须是filter_list方法中的有效值(不一样的服务器环境可能有所不一样),可能支持的包括:
int
boolean
float
validate_regexp
validate_url
validate_email
validate_ip
string
stripped
encoded
special_chars
unsafe_raw
email
url
number_int
number_float
magic_quotes
callback
也能够支持正则匹配过滤,例如:
// 采用正则表达式进行变量过滤
I('get.name','','/^[A-Za-z]+$/');
I('get.id',0,'/^\d+$/');
若是正则匹配不经过的话,则返回默认值。
变量修饰符
I函数支持对变量使用修饰符功能,能够更好的过滤变量。
用法以下:
I('变量类型.变量名/修饰符');
例如:
I('get.id/d');
I('post.name/s');
I('post.ids/a');
可使用的修饰符包括:
修饰符 做用
s 强制转换为字符串类型
d 强制转换为整形类型
b 强制转换为布尔类型
a 强制转换为数组类型
f 强制转换为浮点类型
模板定义
每一个模块的模板文件是独立的,为了对模板文件更加有效的管理,ThinkPHP对模板文件进行目录划分,默认的模板文件定义规则是:
视图目录/[模板主题/]控制器名/操做名+模板后缀
默认的视图目录是模块的View目录(模块能够有多个视图文件目录,这取决于你的应用须要),框架的默认视图文件后缀是.html。
大多数状况下你不须要主题功能,所以新版模板主题默认是空(表示不启用模板主题功能)。
通常状况下,模板文件都在模块的视图目录下面,而且是以模块下面的控制器名为目录,而后是每一个控制器的具体操做模板文件,例如:
User控制器的add操做对应的模板文件就应该是:./Application/Home/View/User/add.html
若是你的默认视图层不是View,例如:
// 设置默认的视图层名称
'DEFAULT_V_LAYER' => 'Template',
那么,对应的模板文件就变成了:./Application/Home/Template/User/add.html。
模板文件的默认后缀的状况是.html,也能够经过 TMPL_TEMPLATE_SUFFIX 来配置成其余的。例如,咱们能够配置:
'TMPL_TEMPLATE_SUFFIX'=>'.tpl'
定义后,User控制器的add操做 对应的模板文件就变成是: ./Application/Home/View/User/add.tpl
若是以为目录结构太深,能够经过设置 TMPL_FILE_DEPR 参数来配置简化模板的目录层次,例如设置:
'TMPL_FILE_DEPR'=>'_'
默认的模板文件就变成了:./Application/Home/View/User_add.html
渲染模板输出最经常使用的是使用display方法,调用格式:
display('[模板文件]'[,'字符编码'][,'输出类型'])
模板文件的写法支持下面几种:
用法 描述
不带任何参数 自动定位当前操做的模板文件
[模块@][控制器:][操做] 经常使用写法,支持跨模块 模板主题能够和theme方法配合
完整的模板文件名 直接使用完整的模板文件名(包括模板后缀)
下面是一个最典型的用法,不带任何参数:
// 不带任何参数 自动定位当前操做的模板文件
$this->display();
表示系统会按照默认规则自动定位模板文件,其规则是:
若是当前没有启用模板主题则定位到:当前模块/默认视图目录/当前控制器/当前操做.html ;
若是有启用模板主题则定位到:当前模块/默认视图目录/当前主题/当前控制器/当前操做.html;
若是有更改TMPL_FILE_DEPR设置(假设 'TMPL_FILE_DEPR'=>'_')的话,则上面的自动定位规则变成: 当前模块/默认视图目录/当前控制器_当前操做.html 和 当前模块/默认视图目录/当前主题/当前控制器_当前操做.html。
因此一般display方法无需带任何参数便可输出对应的模板,这是模板输出的最简单的用法。
一般默认的视图目录是View
若是没有按照模板定义规则来定义模板文件(或者须要调用其余控制器下面的某个模板),可使用:
// 指定模板输出
// 表示调用当前控制器下面的edit模板
$this->display('edit');
或者指定控制器
// 表示调用Member控制器下面的read模板
$this->display('Member:read');
若是咱们使用了模板主题功能,那么也能够支持跨主题调用,使用:
// 调用blue主题下面的User控制器的edit模板
$this->theme('blue')->display('User:edit');
渲染输出不须要写模板文件的路径和后缀,确切地说,这里面的控制器和操做并不必定须要有实际对应的控制器和操做,只是一个目录名称和文件名称而已,例如,你的项目里面可能根本没有Public控制器,更没有Public控制器的menu操做,可是同样可使用
$this->display('Public:menu');
输出这个模板文件。
display方法支持在渲染输出的时候指定输出编码和类型,例如,能够指定编码和类型:
// 输出XML页面类型(配合你的应用需求能够输出不少类型)
$this->display('read', 'utf-8', 'text/xml');
若是须要获取渲染模板的输出内容而不是直接输出,可使用fetch方法。
fetch方法的用法除了不须要指定输出编码和类型外其它和display基本一致,格式:
fetch('模板文件')
模板文件的调用方法和display方法彻底同样,区别就在于fetch方法渲染后不是直接输出,而是返回渲染后的内容,例如:
$content = $this->fetch('Member:edit');
使用fetch方法获取渲染内容后,你能够进行过滤和替换等操做,或者用于对输出的复杂需求。
渲染内容
若是你没有定义任何模板文件,或者把模板内容存储到数据库中的话,你就须要使用show方法来渲染输出了,show方法的调用格式:
show('渲染内容'[,'字符编码'][,'输出类型'])
例如,
$this->show($content);
// 也能够指定编码和类型
$this->show($content, 'utf-8', 'text/xml');
注意:show方法中的内容也能够支持模板解析。
模板赋值
若是要在模板中输出变量,必须在在控制器中把变量传递给模板,系统提供了assign方法对模板变量赋值,不管何种变量类型都统一使用assign赋值。
$this->assign('name',$value);
assign方法必须在display和show方法以前调用,而且系统只会输出设定的变量,其它变量不会输出(系统变量例外),必定程度上保证了变量的安全性。
系统变量能够经过特殊的标签输出,无需赋值模板变量
赋值后,就能够在模板文件中输出变量了,若是使用的是内置模板的话,就能够这样输出:
{$name}
若是要同时输出多个模板变量,可使用下面的方式:
$array['name'] = 'thinkphp';
$array['email'] = 'liu21st@gmail.com';
$array['phone'] = '12335678';
$this->assign($array);
这样,就能够在模板文件中同时输出name、email和phone三个变量。
模板变量的输出根据不一样的模板引擎有不一样的方法,咱们在后面会专门讲解内置模板引擎的用法。若是你使用的是PHP自己做为模板引擎的话 ,就能够直接在模板文件里面输出了:
<?php echo $name.'['.$email.''.$phone.']';?>
若是采用内置的模板引擎,可使用:
{$name} [ {$email} {$phone} ]
输出一样的内容。
变量输出(这里主要是指标量类型的输出)的方法很简单,例如,在控制器中咱们给模板变量赋值:
$name = 'ThinkPHP';
$this->assign('name',$name);
$this->display();
而后就能够在模板中使用:
Hello,{$name}!
模板编译后的结果就是:
Hello,<?php echo($name);?>!
这样,运行的时候就会在模板中显示:
Hello,ThinkPHP!
注意模板标签的{和$之间不能有任何的空格,不然标签无效。
因此,下面的标签
Hello,{ $name}!
将不会正常输出name变量,而是直接保持不变输出:
Hello,{ $name}!
模板中咱们能够用下面的方式输出:
Name:{$data.name}
Email:{$data.email}
或者用下面的方式也是有效:
Name:{$data['name']}
Email:{$data['email']}
若是data变量是一个对象(而且包含有name和email两个属性),那么能够用下面的方式输出:
Name:{$data:name}
Email:{$data:email}
或者
Name:{$data->name}
Email:{$data->email}
系统变量
普通的模板变量须要首先赋值后才能在模板中输出,可是系统变量则不须要,能够直接在模板中输出,系统变量的输出一般以{$Think 打头,例如:
{$Think.server.script_name} // 输出$_SERVER['SCRIPT_NAME']变量
{$Think.session.user_id} // 输出$_SESSION['user_id']变量
{$Think.get.pageNumber} // 输出$_GET['pageNumber']变量
{$Think.cookie.name} // 输出$_COOKIE['name']变量
支持输出$_SERVER、$_ENV、 $_POST、 $_GET、 $_REQUEST、$_SESSION和 $_COOKIE变量。
还能够输出常量
{$Think.const.MODULE_NAME}
或者直接使用
{$Think.MODULE_NAME}
使用函数
咱们每每须要对模板输出变量使用函数,可使用:
{$data.name|md5}
编译后的结果是:
<?php echo (md5($data['name'])); ?>
若是函数有多个参数须要调用,则使用:
{$create_time|date="y-m-d",###}
表示date函数传入两个参数,每一个参数用逗号分割,这里第一个参数是y-m-d,第二个参数是前面要输出的create_time变量,由于该变量是第二个参数,所以须要用###标识变量位置,编译后的结果是:
<?php echo (date("y-m-d",$create_time)); ?>
若是前面输出的变量在后面定义的函数的第一个参数,则能够直接使用:
{$data.name|substr=0,3}
表示输出
<?php echo (substr($data['name'],0,3)); ?>
虽然也可使用:
{$data.name|substr=###,0,3}
但彻底没用这个必要。
还能够支持多个函数过滤,多个函数之间用“|”分割便可,例如:
{$name|md5|strtoupper|substr=0,3}
编译后的结果是:
<?php echo (substr(strtoupper(md5($name)),0,3)); ?>
函数会按照从左到右的顺序依次调用。
若是你以为这样写起来比较麻烦,也能够直接这样写:
{:substr(strtoupper(md5($name)),0,3)}
默认值
咱们能够给变量输出提供默认值,例如:
{$user.nickname|default="这家伙很懒,什么也没留下"}
对系统变量依然能够支持默认值输出,例如:
{$Think.get.name|default="名称为空"}
默认值和函数能够同时使用,例如:
{$Think.get.name|getName|default="名称为空"}
使用运算符
咱们能够对模板输出使用运算符,包括对“+”“ –” “*” “/”和“%”的支持。
例如:
运算符 使用示例
+ {$a+$b}
- {$a-$b}
* {$a*$b}
/ {$a/$b}
% {$a%$b}
++ {$a++} 或 {++$a}
-- {$a--} 或 {--$a}
综合运算 {$a+$b*10+$c}
在使用运算符的时候,再也不支持点语法和常规的函数用法,例如:
{$user.score+10} //错误的
{$user['score']+10} //正确的
{$user['score']*$user['level']} //正确的
{$user['score']|myFun*10} //错误的
{$user['score']+myFun($user['level'])} //正确的
模板能够支持三元运算符,例如:
{$status?'正常':'错误'}
{$info['status']?$info['msg']:$info['error']}
三元运算符中暂时不支持点语法,所以下面的写法是错误的:
{$info.status?$info.msg:$info.error}
循环输出
循环输出主要是使用volist和foreach标签输出。
VOLIST
volist标签一般用于查询数据集(select方法)的结果输出,一般模型的select方法返回的结果是一个二维数组,能够直接使用volist标签进行输出。
在控制器中首先对模版赋值:
$User = M('User');
$list = $User->limit(10)->select();
$this->assign('list',$list);
在模版定义以下,循环输出用户的编号和姓名:
<volist name="list" id="vo">
{$vo.id}:{$vo.name}<br/>
</volist>
Volist标签的name属性表示模板赋值的变量名称,所以不可随意在模板文件中改变。id表示当前的循环变量,能够随意指定,但确保不要和name属性冲突,例如:
<volist name="list" id="data">
{$data.id}:{$data.name}<br/>
</volist>
支持输出查询结果中的部分数据,例如输出其中的第5~15条记录
<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>
Mod属性还用于控制必定记录的换行,例如:
<volist name="list" id="vo" mod="5" >
{$vo.name}
<eq name="mod" value="4"><br/></eq>
</volist>
为空的时候输出提示:
<volist name="list" id="vo" empty="暂时没有数据" >
{$vo.id}|{$vo.name}
</volist>
empty属性不支持直接传入html语法,但能够支持变量输出,例如:
$this->assign('empty','<span class="empty">没有数据</span>');
$this->assign('list',$list);
而后在模板中使用:
<volist name="list" id="vo" empty="$empty" >
{$vo.id}|{$vo.name}
</volist>
模板中能够直接使用函数设定数据集,而不须要在控制器中给模板变量赋值传入数据集变量,如:
<volist name=":fun('arg')" id="vo">
{$vo.name}
</volist>
FOREACH
除了volist标签以外,还可使用foreach标签,foreach标签相似与volist标签,只是更加简单,没有太多额外的属性,例如:
<foreach name="list" item="vo">
{$vo.id}:{$vo.name}
</foreach>
name表示数据源 item表示循环变量。
foreach标签还能够输出一维数组,例如:
<foreach name="list" item="vo" >
{$key}|{$vo}
</foreach>
<switch name="User.level">
<case value="1">value1</case>
<case value="2">value2</case>
<default />default
</switch>
对于case的value属性能够支持多个条件的判断,使用”|”进行分割,例如:
<switch name="Think.get.type">
<case value="gif|png|jpg">图像格式</case>
<default />其余格式
</switch>
表示若是$_GET["type"] 是gif、png或者jpg的话,就判断为图像格式。
Case标签还有一个break属性,表示是否须要break,默认是会自动添加break,若是不要break,可使用:
<switch name="Think.get.userId|abs">
<case value="1" break="0">admin</case>
<case value="2">admin</case>
<default />default
</switch>
也能够对case的value属性使用变量,例如:
<switch name="User.userId">
<case value="$adminId">admin</case>
<case value="$memberId">member</case>
<default />default
</switch>
要求name变量的值等于value就输出,可使用:
<eq name="name" value="value">value</eq>
能够支持和else标签混合使用:
<eq name="name" value="value">
相等
<else/>
不相等
</eq>
范围判断标签
范围判断标签包括in、notin、between和notbetween四个标签,都用于判断变量是否中某个范围。
IN和NOTIN
用法:
假设咱们中控制器中给id赋值为1:
$id = 1;
$this->assign('id',$id);
咱们可使用in标签来判断模板变量是否在某个范围内,例如:
<in name="id" value="1,2,3">
id在范围内
</in>
最后会输出:id在范围内。
若是判断不在某个范围内,可使用:
<notin name="id" value="1,2,3">
id不在范围内
</notin>
能够把上面两个标签合并成为:
<in name="id" value="1,2,3">
id在范围内
<else/>
id不在范围内
</in>
name属性还能够支持直接判断系统变量,例如:
<in name="Think.get.id" value="1,2,3">
$_GET['id'] 在范围内
</in>
value属性也可使用变量,例如:
<in name="id" value="$range">
id在范围内
</in>
$range变量能够是数组,也能够是以逗号分隔的字符串。
BETWEEN 和 NOTBETWEEN
可使用between标签来判断变量是否在某个区间范围内,可使用:
<between name="id" value="1,10">
输出内容1
</between>
一样,可使用notbetween标签来判断变量不在某个范围内:
<notbetween name="id" value="1,10">
输出内容2
</notbetween>
也可使用else标签把两个用法合并,例如:
<between name="id" value="1,10">
输出内容1
<else/>
输出内容2
</between>
当使用between标签的时候,value只须要一个区间范围,也就是只支持两个值,后面的值无效,例如
<between name="id" value="1,3,10">
输出内容1
</between>
实际判断的范围区间是1~3,而不是1~10,也能够支持字符串判断,例如:
<between name="id" value="A,Z">
输出内容1
</between>
name属性能够直接使用系统变量,例如:
<between name="Think.post.id" value="1,5">
输出内容1
</between>
value属性也可使用变量,例如:
<between name="id" value="$range">
输出内容1
</between>
赋值判断标签
可使用present、empty等标签进行赋值判断输出。
present标签用于判断某个变量是否已经定义,用法:
<present name="name">
name已经赋值
<else />
name尚未赋值
</present>
name属性能够直接使用系统变量,例如:
<present name="Think.get.name">
$_GET['name']已经赋值
</present>
empty标签用于判断某个变量是否为空,用法:
name为空
name不为空
name属性能够直接使用系统变量,例如:
<empty name="Think.get.name">
$_GET['name']为空值
</empty>
DEFINED标签用于判断某个常量是否有定义,用法以下:
<defined name="NAME">
NAME常量已经定义
<else />
NAME常量未定义
</defined>
原生代码
Php代码能够和标签在模板文件中混合使用,能够在模板文件里面书写任意的PHP语句代码 ,包括下面两种方式:
第一种:使用php标签
例如:
<php>echo 'Hello,world!';</php>
咱们建议须要使用PHP代码的时候尽可能采用php标签,由于原生的PHP语法可能会被配置禁用而致使解析错误。
第二种:使用原生php代码
<?php echo 'Hello,world!'; ?>
公共模板和模板布局
咱们学习了模板的输出后,就会发现不少应用存在大量的模板文件,如何简化模板文件的定义和公共调用就成了关键,ThinkPHP的模板引擎内置了公共模板和布局模板功能支持,能够方便的规划和公用你的模板文件。
公共模板
在当前模版文件中包含其余公用的模版文件使用include标签,标签用法:
<include file='模版表达式或者模版文件1,模版表达式或者模版文件2,...' />
使用模版表达式
模版表达式的定义规则为:
模块@主题/控制器/操做
例如:
<include file="Public/header" /> // 包含头部模版header
<include file="Public/menu" /> // 包含菜单模版menu
<include file="Blue/Public/menu" /> // 包含blue主题下面的menu模版
能够一次包含多个模版,例如:
<include file="Public/header,Public/menu" />
,包含模版文件并不会自动调用控制器的方法,也就是说包含的其余模版文件中的变量赋值须要在当前操做中完成。
论你使用什么方式包含外部模板,Include标签支持在包含文件的同时传入参数,例如,下面的例子咱们在包含header模板的时候传入了title和keywords变量:
<include file="Public/header" title="ThinkPHP框架" keywords="开源WEB开发框架" />
就能够在包含的header.html文件里面使用title和keywords变量,以下:
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>[title]</title>
<meta name="keywords" content="[keywords]" />
</head>
注意:若是外部模板有所更改,模板引擎并不会从新编译模板,除非在调试模式下或者缓存已通过期。若是部署模式下修改了包含的外部模板文件后,须要把模块的缓存目录清空,不然没法生效。
模板布局
ction参数绑定
在以前的内容中,涉及的控制器操做方法都是没有任何参数的,其实ThinkPHP能够支持操做方法的参数绑定功能。
Action参数绑定是经过直接绑定URL地址中的变量做为操做方法的参数,能够简化方法的定义甚至路由的解析,其原理是把URL中的参数(不包括模块、控制器和操做名)和控制器的操做方法中的参数(按变量名或者变量顺序)进行绑定。
按变量名绑定
默认的参数绑定方式是按照变量名进行绑定,例如,咱们给Blog控制器定义了两个操做方法read和archive方法,因为read操做须要指定一个id参数,archive方法须要指定年份(year)和月份(month)两个参数,那么咱们能够以下定义:
<?php
namespace Home\Controller;
use Think\Controller;
class BlogController extends Controller{
public function read($id){
echo 'id='.$id;
}
public function archive($year='2013',$month='01'){
echo 'year='.$year.'&month='.$month;
}
}
注意这里的操做方法并无具体的业务逻辑,只是简单的示范。
URL的访问地址分别是:
http://serverName/index.php/Home/Blog/read/id/5
http://serverName/index.php/Home/Blog/archive/year/2013/month/11
两个URL地址中的id参数和year和month参数会自动和read操做方法以及archive操做方法的同名参数绑定。
变量名绑定不必定由访问URL决定,路由地址也能起到相同的做用
输出的结果依次是:
id=5
year=2013&month=11
按照变量名进行参数绑定的参数必须和URL中传入的变量名称一致,可是参数顺序不须要一致。也就是说
http://serverName/index.php/Home/Blog/archive/month/11/year/2013
和上面的访问结果是一致的,URL中的参数顺序和操做方法中的参数顺序均可以随意调整,关键是确保参数名称一致便可。
若是使用下面的URL地址进行访问,参数绑定仍然有效:
http://serverName/index.php?s=/Home/Blog/read/id/5
http://serverName/index.php?s=/Home/Blog/archive/year/2013/month/11
http://serverName/index.php?c=Blog&a=read&id=5
http://serverName/index.php?c=Blog&a=archive&year=2013&month=11
若是用户访问的URL地址是(至于为何会这么访问暂且不提):
http://serverName/index.php/Home/Blog/read/
那么会抛出下面的异常提示: 参数错误:id
报错的缘由很简单,由于在执行read操做方法的时候,id参数是必须传入参数的,可是方法没法从URL地址中获取正确的id参数信息。因为咱们不能相信用户的任何输入,所以建议你给read方法的id参数添加默认值,例如:
public function read($id=0){
echo 'id='.$id;
}
这样,当咱们访问 http://serverName/index.php/Home/Blog/read/ 的时候 就会输出
id=0
当咱们访问 http://serverName/index.php/Home/Blog/archive/ 的时候,输出:
year=2013&month=01
始终给操做方法的参数定义默认值是一个避免报错的好办法
按变量顺序绑定的方式目前仅对PATHINFO地址有效,因此下面的URL访问参数绑定会失效:
http://serverName/index.php?c=Blog&a=read&id=5
http://serverName/index.php?c=Blog&a=archive&year=2013&month=11
可是,兼容模式URL地址访问依然有效:
http://serverName/index.php?s=/Home/Blog/read/5
http://serverName/index.php?s=/Home/Blog/archive/2013/11
若是你的操做方法定义都不带任何参数或者不但愿使用该功能的话,能够关闭参数绑定功能:
'URL_PARAMS_BIND' => false
空操做是指系统在找不到请求的操做方法的时候,会定位到当前控制器的空操做(_empty)方法来执行。
例如,下面咱们用空操做功能来实现一个城市切换的功能。 咱们只须要给CityController类定义一个_empty方法:
<?php
namespace Home\Controller;
use Think\Controller;
class CityController extends Controller{
public function _empty($name){
//把全部城市的操做解析到city方法
$this->city($name);
}
//注意 city方法 自己是 protected 方法
protected function city($name){
//和$name这个城市相关的处理
echo '当前城市' . $name;
}
}
接下来,咱们就能够在浏览器里面输入
http://serverName/index.php/Home/City/beijing/
http://serverName/index.php/Home/City/shanghai/
http://serverName/index.php/Home/City/shenzhen/
因为City控制器并无定义beijing、shanghai或者shenzhen操做方法,所以系统会定位到空操做方法 _empty中去解析,_empty方法的参数就是当前URL里面的操做名,所以会看到依次输出的结果是:
当前城市:beijing
当前城市:shanghai
当前城市:shenzhen
复制代码
注意:空操做方法仅在你的控制器类继承系统的Think\Controller类才有效。
空控制器
空控制器的概念是指当系统找不到请求的控制器名称的时候,系统会尝试定位空控制器(EmptyController)。
如今咱们把前面的需求进一步,把URL由原来的
http://serverName/index.php/Home/City/shanghai/
变成
http://serverName/index.php/Home/shanghai/
这样更加简单的方式,若是按照传统的模式,咱们必须给每一个城市定义一个控制器类,而后在每一个控制器类的index方法里面进行处理。但是若是使用空控制器功能,这个问题就能够迎刃而解了。
咱们能够给项目定义一个EmptyController类
<?php
namespace Home\Controller;
use Think\Controller;
class EmptyController extends Controller{
public function index(){
//根据当前控制器名来判断要执行那个城市的操做
$cityName = CONTROLLER_NAME;
$this->city($cityName);
}
//注意 city方法 自己是 protected 方法
protected function city($name){
//和$name这个城市相关的处理
echo '当前城市' . $name;
}
}
接下来,咱们就能够在浏览器里面输入
http://serverName/index.php/Home/beijing/
http://serverName/index.php/Home/shanghai/
http://serverName/index.php/Home/shenzhen/
因为系统并不存在beijing、shanghai或者shenzhen控制器,所以会定位到空控制器(EmptyController)去执行,会看到依次输出的结果是:
当前城市:beijing
当前城市:shanghai
当前城市:shenzhen
复制代码
空控制器和空操做还能够同时使用,用以完成更加复杂的操做。
前置和后置操做
_initialize方法是调用全部操做方法以前都会执行,前置和后缀操做则是针对某个特定的操做方法而言。
若是当前访问的操做是存在(必须是实际在控制器中定义过)的,系统会检测当前操做是否具备前置和后置操做,若是存在就会按照顺序执行,前置和后置操做的方法名是在要执行的方法前面加 _before_和_after_,例如:
namespace Home\Controller;
use Think\Controller;
class IndexController extends Controller{
//前置操做方法
public function _before_index(){
echo 'before<br/>';
}
public function index(){
echo 'index<br/>';
}
//后置操做方法
public function _after_index(){
echo 'after';
}
}
若是咱们访问 http://serverName/index.php
结果会输出
before
index
after
对于任何操做方法咱们均可以按照这样的规则来定义前置和后置方法。
若是在操做方法里面使用了exit或者error方法的话 有可能不会再执行后置方法了,例如:
namespace Home\Controller;
use Think\Controller;
class IndexController extends Controller{
//前置操做方法
public function _before_index(){
echo 'before<br/>';
}
public function index(){
echo 'index<br/>';
exit;
}
//后置操做方法
public function _after_index(){
echo 'after';
}
}
若是咱们再次访问结果会输出
before
index
除了初始化、前置和后置操做以外,咱们还能够在控制器之外的地方对操做方法进行扩展,这个之后会在行为扩展部分描述。
页面跳转
系统的Think\Controller类内置了两个页面跳转方法error和success,分别用于错误(提示)跳转和成功(提示)跳转。两个方法都会输出一个提示信息页面,而后自动跳转到指定的地址。下面是一个简单的例子:
$New = M('New'); //实例化New对象
$result = $New->add($data);
if($result){
// 成功后跳转到新闻列表页面
$this->success('新增成功,即将返回列表页面', '/New/index');
} else {
// 错误页面的默认跳转页面是返回前一页,一般不须要设置
$this->error('新增失败');
}
success和error方法有三个参数,分别是提示信息、跳转地址和跳转页面等待时间(秒),除了第一个参数外其余都是可选的。
提示信息:成功或者错误信息字符串。
跳转地址:页面跳转地址是可选的,success方法的默认跳转地址是$_SERVER["HTTP_REFERER"],error方法的默认跳转地址是javascript:history.back(-1);。
等待时间:默认的等待时间success方法是1秒,error方法是3秒。
success和error方法均可以对应的模板,默认两个方法对应的模板是框架自带的跳转模板dispatch_jump.tpl:
//默认错误跳转对应的模板文件
'TMPL_ACTION_ERROR' => THINK_PATH . 'Tpl/dispatch_jump.tpl',
//默认成功跳转对应的模板文件
'TMPL_ACTION_SUCCESS' => THINK_PATH . 'Tpl/dispatch_jump.tpl',
success方法默认页面显示以下:
2015-06-06/557256edb73ad
error方法默认页面显示以下:
2015-06-06/557256c33274c
你能够从新定义跳转模板,一般建议直接放到项目目录下面(下面采用公共模块的模板做为项目统一的跳转模板):
//默认错误跳转对应的模板文件
'TMPL_ACTION_ERROR' => 'Common@Public/error',
//默认成功跳转对应的模板文件
'TMPL_ACTION_SUCCESS' => 'Common@Public/success',
模板文件可使用模板标签,而且可使用下面的模板变量:
变量 含义
$message 页面成功提示信息
$error 页面错误提示信息
$waitSecond 跳转等待时间 单位为秒
$jumpUrl 跳转页面地址
重定向
若是不须要提示页面,ThinkPHP还能够实现直接重定向操做,Think\Controller类提供了redirect方法实现页面的重定向功能。
重定向到操做
redirect('重定向操做地址(通常为[控制器/操做])','参数(字符串或者数组)','重定向等待时间(秒)','重定向提示信息')
例如:
$New = M('New'); //实例化New对象
$result = $New->add($data);
if($result){
// 停留5秒后跳转到New模块的category操做,而且显示页面跳转中字样
$this->redirect('New/category', 'cate_id=2&status=1', 5,'页面跳转中...');
} else {
// 错误页面
$this->redirect('New/error');
}
能够传入参数和设置重定向的等待时间,甚至给出等待的提示信息:
注意:重定向后会改变当前的URL地址。
重定向到URL
若是你仅仅是想重定向要一个指定的URL地址,而不是到控制器的操做方法,能够直接使用redirect函数重定向,例如:
$New = M('New'); //实例化New对象
$result = $New->add($data);
if($result){
//重定向到指定的URL地址
redirect('/New/category/cate_id/2', 5, '页面跳转中...');
}
redirect函数的第一个参数是要跳转的实际URL地址。
判断请求类型
在不少状况下面,咱们须要判断当前操做的请求类型是GET 、POST 、PUT或 DELETE,一方面能够针对请求类型做出不一样的逻辑处理,另一方面有些状况下面须要验证安全性,过滤不安全的请求。
系统内置了一些常量用于判断请求类型,包括:
常量 说明
IS_GET 判断是不是GET方式提交
IS_POST 判断是不是POST方式提交
IS_PUT 判断是不是PUT方式提交
IS_DELETE 判断是不是DELETE方式提交
IS_AJAX 判断是不是AJAX提交
REQUEST_METHOD 当前提交类型
使用举例以下:
class UserController extends Controller{
public function update(){
if (IS_POST){
$User = M('User');
$User->create();
$User->save();
$this->success('保存完成');
}else{
$this->error('非法请求');
}
}
}
个别状况下判断AJAX请求的时候,你可能须要在表单里面添加一个隐藏域,告诉后台属于ajax方式提交,默认的隐藏域名称是ajax(能够经过VAR_AJAX_SUBMIT配置),若是是JQUERY类库的话,则无需添加任何隐藏域便可自动判断。
AJAX返回
ThinkPHP能够很好的支持AJAX请求,系统的\Think\Controller类提供了ajaxReturn方法用于AJAX调用后返回数据给客户端。而且支持JSON、JSONP、XML和EVAL四种方式给客户端接受数据,而且支持配置其余方式的数据格式返回。
ajaxReturn方法调用示例:
$data = 'ok';
$this->ajaxReturn($data);
支持返回数组数据:
$data['status'] = 1;
$data['content'] = 'content';
$this->ajaxReturn($data);
默认配置采用JSON格式返回数据(经过配置DEFAULT_AJAX_RETURN进行设置),咱们能够指定格式返回,例如:
// 指定XML格式返回数据
$data['status'] = 1;
$data['content'] = 'content';
$this->ajaxReturn($data,'xml');
返回数据data能够支持字符串、数字和数组、对象,返回客户端的时候根据不一样的返回格式进行编码后传输。若是是JSON/JSONP格式,会自动编码成JSON字符串,若是是XML方式,会自动编码成XML字符串,若是是EVAL方式的话,只会输出字符串data数据。
JSON和JSONP虽然只有一个字母的差异,但其实他们根本不是一回事儿:JSON是一种数据交换格式,而JSONP是一种非官方跨域数据交互协议。一个是描述信息的格式,一个是信息传递的约定方法。
默认的JSONP格式返回的处理方法是jsonpReturn,若是你采用不一样的方法,能够设置:
'DEFAULT_JSONP_HANDLER' => 'myJsonpReturn', // 默认JSONP格式返回的处理方法
URL伪静态一般是为了知足更好的SEO效果,ThinkPHP支持伪静态URL设置,能够经过设置URL_HTML_SUFFIX参数随意在URL的最后增长你想要的静态后缀,而不会影响当前操做的正常执行。
单个URL后缀
默认状况下,伪静态的设置为html,所以下面的URL访问是等效的:
http://serverName/Home/Blog/index
http://serverName/Home/Blog/index.html
但后者更具备静态页面的URL特征,而且不会影响原来参数的使用。
但若是咱们访问
http://serverName/Home/Blog/index.xml
则会提示出错。
2015-06-06/55726422017c7
除非咱们设置了:
'URL_HTML_SUFFIX'=>'xml'
全后缀支持
若是咱们设置伪静态后缀为空,则能够支持全部的静态后缀访问,而且会记录当前的伪静态后缀到常量 __EXT__ ,但不会影响正常的页面访问。
'URL_HTML_SUFFIX'=>''
设置后,下面的URL访问都有效:
http://serverName/Home/blog/index.html
http://serverName/Home/blog/index.shtml
http://serverName/Home/blog/index.xml
http://serverName/Home/blog/index.pdf
能够经过常量 __EXT__ 判断当前访问的后缀,例如:
if('pdf'==__EXT__){
// 输出PDF文档
}elseif('xml'==__EXT__){
// 输出XML格式文档
}
多个后缀支持
若是但愿仅支持设置的多个伪静态后缀访问,能够设置以下:
// 多个伪静态后缀设置 用|分割
'URL_HTML_SUFFIX' => 'html|shtml|xml'
那么,当访问 http://serverName/Home/blog/index.pdf 的时候会报系统错误。
禁止访问后缀
能够设置禁止访问的URL后缀,例如:
'URL_DENY_SUFFIX' => 'pdf|ico|png|gif|jpg', // URL禁止访问的后缀设置
若是访问 http://serverName/Home/blog/index.pdf 就会直接返回404错误。
意:
URL_DENY_SUFFIX的优先级比URL_HTML_SUFFIX要高。
在应用开发中, 常常会遇到一些带有提示信息的跳转页面, 例如操做成功或者操做错误页面, 而且自动跳
转到另一个目标页面。 系统的 \Think\Controller 类内置了两个跳转方法success和error, 用于页面跳转
提示, 并且能够支持ajax提交。
使用方法很简单, 举例以下:
$User = M('User'); //实例化User对象
$result = $User->add($data);
if($result){
//设置成功后跳转页面的地址, 默认的返回页面是$_SERVER['HTTP_REFERER']
$this->success('新增成功', '/User/index');
} else {
//错误页面的默认跳转页面是返回前一页, 一般不须要设置
$this->error('新增失败');
}
success和error方法的第一个参数表示提示信息, 第二个参数表示跳转地址, 第三个参数是跳转时间( 单
位为秒) , 例如:
ThinkPHP3.2.3彻底开发手册
本文档使用 看云 构建 - 77 -
// 操做完成3秒后跳转到 /Article/index
$this->success('操做完成','/Article/index',3);
// 操做失败5秒后跳转到 /Article/error
$this->error('操做失败','/Article/error',5);
跳转地址是可选的, success方法的默认跳转地址是 $_SERVER["HTTP_REFERER"] , error方法的默认跳
转地址是 javascript:history.back(-1);
Thinkphp自动验证规则(转载)
楼主:dailinsonglin 时间:2013-06-03 13:45:28 点击:2362 回复:0 脱水模式 给他打赏 只看楼主 阅读设置
其实说白了,这篇文章就是转给本身看的,省的下次用的时候满网络找了。有须要的同窗也能够看看。自动验证是很是有用的一个技术。日常的验证基本就是,用户名是否为空,用户名是否重复,密码,重复密码是否一致。官方给的就是这些。那么咱们不可能只用到这些,铁定还有别的规则,因此下面这些规则供同窗借鉴,也供我本身借鉴。
array(‘name’,’/^[a-z]\w{3,}$/i’,’名字不符合要求!’);
array(‘password’,’/^[a-z]\w{6,30}$/i’,’密码不符合要求!’);
array(‘account’,’/^[A-Za-z]+$/’,’帐号必须使用英文!’);
附上一些表单验证中比较经常使用的正则表达式写法:
匹配中文字符的正则表达式: [\一-\龥]
匹配双字节字符(包括汉字在内):[^\x00-\xff]
匹配Email地址的正则表达式:\w+([-+.]\w+)*\w+([-.]\w+)*\.\w+([-.]\w+)*
匹配网址URL的正则表达式:[a-zA-z]+://[^\s]*
匹配账号是否合法(字母开头,容许5-16字节,容许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$
匹配国内电话号码:\d{3}-\d{8}|\d{4}-\d{7}
匹配中国邮政编码:[1-9]\d{5}(?!\d)
匹配ip地址:\d+\.\d+\.\d+\.\d+
匹配特定数字:
^[1-9]\d*$ //匹配正整数
^-[1-9]\d*$ //匹配负整数
^-?[1-9]\d*$ //匹配整数
^[1-9]\d*|0$ //匹配非负整数(正整数 + 0)
^-[1-9]\d*|0$ //匹配非正整数(负整数 + 0)
^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$ //匹配正浮点数
^-([1-9]\d*\.\d*|0\.\d*[1-9]\d*)$ //匹配负浮点数
^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$ //匹配浮点数
^[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0$ //匹配非负浮点数(正浮点数 + 0)
^(-([1-9]\d*\.\d*|0\.\d*[1-9]\d*))|0?\.0+|0$ //匹配非正浮点数(负浮点数 + 0)
匹配特定字符串:
^[A-Za-z]+$ //匹配由26个英文字母组成的字符串
^[A-Z]+$ //匹配由26个英文字母的大写组成的字符串
^[a-z]+$ //匹配由26个英文字母的小写组成的字符串
^[A-Za-z0-9]+$ //匹配由数字和26个英文字母组成的字符串
^\w+$ //匹配由数字、26个英文字母或者下划线组成的字符串
实例:
protected $_validate = array(
array('username','require','用户名必须!'), // 数据是否为空 注:默认增长修改都验证
array('username','','用户名已经存在!',0,’unique’,1), // 在新增的时候验证username字段是否惟一
array('password','checkPwd','密码格式不正确',0,’function’), // 密码格式能够用chenkPwd方法自定义
array('repassword','password','确认密码不正确',0,’confirm’), // 验证确认密码是否和密码一致
array('sex','array(0,1,2)','性别必须为0,1,2',0,'in'), // 验证数据是否在一个范围内
array('age','number','年龄必须为数字'), // 验证数据是否为数字
array('email','email','邮箱格式不正确'), // 内置正则验证邮箱
array('email','/^/w+([-+.]/w+)*/w+([-.]/w+)*/./w+([-.]/w+)*$/','邮箱格式不正确), // 自定义正则验证数据
array('mypage','url','我的网址格式不正确'), // 内置正则验证URL地址
array('verify','****','验证码不正确',0,'equal'), // 验证数据是否等于某个值 注:****能够是随机验证码
array('salary','currency','薪水验证不正确','0'), // 内置验证货币数据
);
文章均属 松林's blog 原创 转载请注明转自松林's blog
//检查url
public function check_url($url){
if(!preg_match('/http:\/\/[\w.]+[\w\/]*[\w.]*\??[\w=&\+\%]*/is',$url)){
return false;
}
return true;
}
模板输出变量
{$name}
Email: {$data.email}
或者用下面的方式也是有效:
Name: {$data['name']}
对象
Email: {$data:email}
或者
Name: {$data->name}
{$Think.server.script_name} // 输出$_SERVER['SCRIPT_NAME']变量 系统变量
常量
{$Think.const.MODULE_NAME}
前言
A标签是html中经常使用的标签,它与button按钮是实现页面跳转的两种最经常使用的方式,常常在开发中咱们更喜欢使用A标签,它们二者能够相互替换,但他们在执行js脚本时有着细微的区别。
使用A标签执行JS脚本的几种方式
一、href="javascript:js_method();"
这是咱们最经常使用的方法,可是这种方法在传递this等参数的时候很容易出问题,并且javascript:协议做为a的href属性的时候不只会致使没必要要的触发window.onbeforeunload事件,在IE里面更会使gif动画图片中止播放。W3C标准不推荐在href里面执行javascript语句。
二、href="javascript:void(0);" onclick="js_method()"
这种方法是不少网站最经常使用的方法,也是最周全的方法,onclick方法负责执行js函数,而void是一个操做符,void(0)返回undefined,地址不发生跳转。并且这种方法不会像第一种方法同样直接将js方法暴露在浏览器的状态栏,推荐使用此方法。
三、href="javascript:;" onclick="js_method()"
这种方法跟跟第2种相似,区别只是执行了一条空的js代码。Href与onclick区别是每一个href里的javascript方法都用try、catch包围。
四、href="#" onclick="js_method()"
这种方法也是网上很常见的代码,#是标签内置的一个方法,表明top的做用。因此用这种方法点击后网页后返回到页面的最顶端。
五、href="#" onclick="js_method();return false;"
这种方法点击执行了js函数后return false,页面不发生跳转,执行后仍是在页面的当前位置。
综合上述,在a中调用js函数最适当的方法推荐使用后几种,注意第四种会返回页面最顶端,当有这种需求时可使用。
模型的名字要和数据库表对应。
可是若是不对应,要进行定义数据表的名字。
在数据库里面有一个 think_categories 表, 而咱们定义的模型类名称是
CategoryModel , 按照系统的约定, 这个模型的名称是Category, 对应的数据表名称应该是
think_category ( 所有小写) , 可是如今的数据表名称是 think_categories , 所以咱们就须要设置
tableName 属性来改变默认的规则( 假设咱们已经在配置文件里面定义了 DB_PREFIX 为 think_) 。
namespace Home\Model;
use Think\Model;
class CategoryModel extends Model {
protected $tableName = 'categories';
}
注意这个属性的定义不须要加表的前缀 think_
若是咱们须要CategoryModel模型对应操做的数据表是 top_category , 那么咱们只须要设置数据表前缀
便可:
namespace Home\Model;
use Think\Model;
class CategoryModel extends Model {
protected $tablePrefix = 'top_';
}
若是你的数据表直接就是 category , 而没有前缀, 则能够设置 tablePrefix 为空字符串。
namespace Home\Model;
use Think\Model;
class CategoryModel extends Model {
protected $tablePrefix = '';
}
没有表前缀的状况必须设置, 不然会获取当前配置文件中的 DB_PREFIX 。
ThinkPHP3.2.3彻底开发手册
本文档使用 看云 构建 - 93 -
而对于另一种特殊状况, 咱们须要操做的数据表是 top_categories , 这个时候咱们就须要定义
trueTableName 属性
namespace Home\Model;
use Think\Model;
class CategoryModel extends Model {
protected $trueTableName = 'top_categories';
}
注意 trueTableName 须要完整的表名定义。
除了数据表的定义外, 还能够对数据库进行定义( 用于操做当前数据库之外的数据表) , 例如
top.top_categories :
namespace Home\Model;
use Think\Model;
class CategoryModel extends Model {
protected $trueTableName = 'top_categories';
protected $dbName = 'top';
}
D方法 数据模型实例化
$User = D('User');
$User->select();
D方法的参数就是模型的名称, 而且和模型类的大小写定义是一致的.
D方法能够自动检测模型类, 若是存在自定义的模型类, 则实例化自定义模型类, 若是不存在, 则会实例
化系统的\Think\Model基类, 同时对于已实例化过的模型, 不会重复实例化
D方法还能够支持跨模块调用, 须要使用:
//实例化Admin模块的User模型
D('Admin/User');
//实例化Extend扩展命名空间下的Info模型
D('Extend://Editor/Info');
D方法实例化模型类的时候一般是实例化某个具体的模型类, 若是你仅仅是对数据表进行基本的CURD操做
的话, 使用M方法实例化的话, 因为不须要加载具体的模型类, 因此性能会更高。
例如:
// 使用M方法实例化
$User = M('User');
// 和用法 $User = new \Think\Model('User'); 等效
// 执行其余的数据操做
$User->select();
M方法也能够支持跨库操做, 例如:
// 使用M方法实例化 操做db_name数据库的ot_user表
$User = M('db_name.User','ot_');
// 执行其余的数据操做
$User->select();
M方法的参数和\Think\Model类的参数是同样的, 也就是说, 咱们也能够这样实例化:
$New = M('new','think_',$connection);
// 等效于 $New = new \Think\Model('new','think_',$connection);
具体的参数含义能够参考前面的介绍。
M方法实例化的时候, 默认状况下是直接实例化系统的\Think\Model类, 若是咱们但愿实例化其余的公共
模型类的话, 可使用以下方法:
$User = M('\Home\Model\CommonModel:User','think_','db_config');
// 至关于 $User = new \Home\Model\CommonModel('User','think_','db_config');
实例化空模型类
若是你仅仅是使用原生SQL查询的话, 不须要使用额外的模型类, 实例化一个空模型类便可进行操做了,
例如:
//实例化空模型
$Model = new Model();
//或者使用M快捷方法是等效的
$Model = M();
//进行原生的SQL查询
$Model->query('SELECT * FROM think_user WHERE status = 1');
实例化空模型类后还能够用table方法切换到具体的数据表进行操做
咱们在实例化的过程当中, 常用D方法和M方法, 这两个方法的区别在于M方法实例化模型无需用户为
每一个数据表定义模型类, 若是D方法没有找到定义的模型类, 则会自动调用M方法。
若是须要显式获取当前数据表的字段信息, 可使用模型类的getDbFields方法来获取当前数据对象的全
部字段信息, 例如:
$User = M('User');
$fields = $User->getDbFields();
若是你在部署模式下面修改了数据表的字段信息, 可能须要清空 Data/_fields 目录下面的缓存文件, 让系
统从新获取更新的数据表字段信息, 不然会发生新增的字段没法写入数据库的问题
<if condition="$info['logo'] neq ''"> <span style="float:left;padding-righ:10px"><img src="{weiwin:$info.logo}"/></span>
</if>{weiwin:$info.info}</div>
js跳转到其余控制器还有方法 window.location.href='index.php?g=Wap&m=Card&a=index&token='+token+'&wecha_id='+wid;
URL大小写
可是系统自己提供了一个不区分URL大小写的解决方案,能够经过配置简单实现。
只要在项目配置中,增长:
'URL_CASE_INSENSITIVE' =>true
配置好后,即便是在Linux环境下面,也能够实现URL访问再也不区分大小写了。
http://serverName/index.php/Home/Index/index
// 将等效于
http://serverName/index.php/home/index/index
这里须要注意一个地方,一旦开启了不区分URL大小写后,若是咱们要访问相似UserTypeController的控制器,那么正确的URL访问应该是:
// 正确的访问地址
http://serverName/index.php/home/user_type/index
// 错误的访问地址(linux环境下)
http://serverName/index.php/home/usertype/index
利用系统提供的U方法能够为你自动生成相关的URL地址。
3.2.3版本开始,I函数支持对变量使用修饰符功能,能够更好的过滤变量。
用法以下: I('变量类型.变量名/修饰符');
例如:
I('get.id/d');
I('post.name/s');
I('post.ids/a');
可使用的修饰符包括:
修饰符 做用
s 强制转换为字符串类型
d 强制转换为整形类型
b 强制转换为布尔类型
a 强制转换为数组类型
f 强制转换为浮点类型
请求类型
在不少状况下面,咱们须要判断当前操做的请求类型是GET 、POST 、PUT或 DELETE,一方面能够针对请求类型做出不一样的逻辑处理,另一方面有些状况下面须要验证安全性,过滤不安全的请求。 系统内置了一些常量用于判断请求类型,包括:
常量 说明
IS_GET 判断是不是GET方式提交
IS_POST 判断是不是POST方式提交
IS_PUT 判断是不是PUT方式提交
IS_DELETE 判断是不是DELETE方式提交
IS_AJAX 判断是不是AJAX提交
REQUEST_METHOD 当前提交类型
class UserController extends Controller{
public function update(){
if (IS_POST){
$User = M('User');
$User->create();
$User->save();
$this->success('保存完成');
}else{
$this->error('非法请求');
}
}
}
须要注意的是,若是使用的是ThinkAjax或者本身写的Ajax类库的话,须要在表单里面添加一个隐藏域,告诉后台属于ajax方式提交,默认的隐藏域名称是ajax(能够经过VAR_AJAX_SUBMIT配置),若是是JQUERY类库的话,则无需添加任何隐藏域便可自动判断。
下面咱们用空操做功能来实现一个城市切换的功能。 咱们只须要给CityController类定义一个_empty(空操做)方法:
<?php
namespace Home\Controller;
use Think\Controller;
class CityController extends Controller{
public function _empty($name){
//把全部城市的操做解析到city方法
$this->city($name);
}
//注意 city方法 自己是 protected 方法
protected function city($name){
//和$name这个城市相关的处理
echo '当前城市' . $name;
}
}
success和error方法的第一个参数表示提示信息,第二个参数表示跳转地址,第三个参数是跳转时间(单位为秒),例如:
// 操做完成3秒后跳转到 /Article/index
$this->success('操做完成','/Article/index',3);
// 操做失败5秒后跳转到 /Article/error
$this->error('操做失败','/Article/error',5);
跳转地址是可选的,success方法的默认跳转地址是$_SERVER["HTTP_REFERER"],error方法的默认跳转地址是javascript:history.back(-1);。
默认的等待时间success方法是1秒,error方法是3秒
success和error方法均可以对应的模板,默认的设置是两个方法对应的模板都是:
//默认错误跳转对应的模板文件
'TMPL_ACTION_ERROR' => THINK_PATH . 'Tpl/dispatch_jump.tpl',
//默认成功跳转对应的模板文件
'TMPL_ACTION_SUCCESS' => THINK_PATH . 'Tpl/dispatch_jump.tpl',
也可使用项目内部的模板文件
//默认错误跳转对应的模板文件
'TMPL_ACTION_ERROR' => 'Public:error';
//默认成功跳转对应的模板文件
'TMPL_ACTION_SUCCESS' => 'Public:success';
模板文件可使用模板标签,而且可使用下面的模板变量:
变量 含义
$msgTitle 操做标题
$message 页面提示信息
$status 操做状态 1表示成功 0 表示失败 具体还能够由项目自己定义规则
$waitSecond 跳转等待时间 单位为秒
$jumpUrl 跳转页面地址
success和error方法会自动判断当前请求是否属于Ajax请求,若是属于Ajax请求则会调用ajaxReturn方法返回信息。 ajax方式下面,success和error方法会封装下面的数据返回:
$data['info'] = $message; // 提示信息内容
$data['status'] = $status; // 状态 若是是success是1 error 是0
$data['url'] = $jumpUrl; // 成功或者错误的跳转地址
重定向
Controller类的redirect方法能够实现页面的重定向功能。
redirect方法的参数用法和U函数的用法一致(参考URL生成部分),例如:
//重定向到New模块的Category操做
$this->redirect('New/category', array('cate_id' => 2), 5, '页面跳转中...');
上面的用法是停留5秒后跳转到New模块的category操做,而且显示页面跳转中字样,重定向后会改变当前的URL地址。
若是你仅仅是想重定向要一个指定的URL地址,而不是到某个模块的操做方法,能够直接使用redirect函数重定向,例如:
//重定向到指定的URL地址
redirect('/New/category/cate_id/2', 5, '页面跳转中...')
Redirect函数的第一个参数是一个URL地址。
控制器的redirect方法和redirect函数的区别在于前者是用URL规则定义跳转地址,后者是一个纯粹的URL地址。