ThinkPHP框架
一、框架介绍
PHP框架真正的发展是从php5开始的,在php5中对对象模型的修改对框架的发展起了很大的作用。PHP框架就是通过提供一个开发web程序的基本架构,把基于web开发的PHP程序摆到流水线上。换句话说,php开发框架有助于促进快速软件开发,节约了开发时间,减少了代码的重复编写。
1.1、什么是框架
框架(framework)其实就是开发一个系统的半成品,是在一个给定的问题领域内,实现一个应用程序的一部分设计,简单的说就是项目骨架已经搭好并提供了丰富的组建库,只增加了一些内容或者调用一些提供好的组件就可以完成自己的系统。
我们可以把框架的项目部署理解为一个建筑的地基以及环境的搭建,组建库理解为各种建筑材料,我们只需要“装修”一番,就可以将其变成办公楼,住宅楼,商业街....(个人主页、OA系统、电子商城....)
1.2、为什么要用框架
框架最大的好处就是重用。因为web发展到今天已经很复杂了,特别是服务器软件,涉及到的知识、内容和问题已经很多了,在项目开发过程中如果如果使用一个成熟的框架,就相当于让别人帮你完成了一些基础工作(50%以上),我们只需要集中精力完成系统的业务逻辑设计。而且框架一般都是成熟稳健的,可以处理系统的很多细节问题,比如事物处理,安全性,数据流控制等问题。还有框架一般都经过很多人使用,所以结构、扩展都很好,而且是不断升级的,你可以直接享受别人升级代码带来的好处。框架也将问题划分开了各个解决,易于控制,易于延展,易于分配资源。应用框架强调的是软件的设计重用性和系统的可扩展性,以缩短大型软件应用系统的开发周期,提高开发质量。
1.3、框架和MVC
框架是软件,而设计模式是软件的知识,一个框架往往含有一个或者多个设计模式,现在几乎所有流行的PHP框架都能实现MVC设计模式,将开发程序强制拆分成视图、控制器和模型三层,所以,使用框架后,就不用纠结去如何实现MVC了。如果不用框架去实现MVC,不仅MVC不易于理解,分离的难度也比较高。
M - Model 模型 负责数据操作
V - View 视图、模版 负责前台页面显示
C - Controller 模块 描述功能,调度M和V
一个框架不仅要具备MVC。还要具备以下一些功能
1.3.1、目录组织结构
可以自动部署项目所需的全部目录结构,或按框架的规则要求,创建项目的目录结构
1.3.2、类加载
框架中所有开发中用到的功能类,都可以自动加载。包括系统中提供的强大的基类库,以及用户自定义的功能类
1.3.3、基础类
每个成熟的框架都为用户提供了非常丰富的基类,让程序员在自定义方法中直接就可以从基类中继承来大量的功能
1.3.4、URL处理
框架中几乎都需要URL处理方式。对URL的管理包括两个方面。首先当用户请求约定的URL时,应用程序需要解析它变成可以理解的参数。第二,应用程序需要提供一种创造URL的方法,以便创建的URL应用程序是可以理解的。
1.3.5、输入处理
用户的一些输入通常都在URL参数中,或者通过表单提交。为了防止一些不合理的数据和输入攻击,框架中可以完成对输入内容进行过滤以及自动完成一些数据验证工作。
1.3.6、错误异常处理
在使用框架开发系统时,框架会提供一些配套的错误处理方式和程序调试模式,方便程序员快速解决开发中遇到的问题
1.3.7、扩展类
在框架中除了提供一些丰富的基类,还会提供一些常用的功能扩展类,包括web项目中一些常见功能,像分页程序,上传类等,也会提供用户自定义扩展类的接口。
二、ThinkPHP
1.好处
1、免费的,代码开源
2、单入口+模板引擎(thinktemplatexml)+MVC的一种的开发模式;
3、智能url路由 (0-3)
index.php?m=User&a=show&id=100
index.php/m/User/a/show/id/100
index.php/User/show/id/100
4、目录是自动创建
5、ajax+数据操作、表单验证等等都很智能
自动验证 自动完成 自动映射
ThinkPHP\CI\YII
2.框架下载
下载地址: www.thinkphp.cn
3.项目目录
3.1、index.php 项目入口文件
1、//检测PHP环境
if(version_compare(PHP_VERSION,'5.3.0','<')) die('require PHP > 5.3.0 !');
2、 //定义项目路径
define('APP_PATH', './Application/');
//注意此处后面必须加斜线
3、//加载框架入口文件 //注意 一定要严格区分大小写,防止项目迁移
require("./ThinkPHP/ThinkPHP.php");
//注意是requeire而不适用include 因为这个核心文件如果引入出错,那么整个项目就没必要运行了
3.2、MVC对应的项目文件夹
M ---- ./Application/Home/Model
V ---- ./Application/Home/View
C ---- ./Home/Action/Home/Controller
4 ThinkPHP运用
4.1 URL四种访问方式URL_MODEL
1. 普通模式(URL_MODEL=0)
http://域名/项目文件夹名/入口文件?m=控制名&a=方法名&id=100
m:代表的是模块名(控制器名)
a:代表的模块的操作名(方法名)
/2015112/tp/index.php?m=Home&c=User&a=hello&name=tom&age=20
2. Pathinfo方式
http://域名/项目名/入口/模块名/方法名/键1/值1/键2/值2
http://localhost/2015110/middle/thinkphp/index.php/Index/index/test/zzz/name/tom.shtml
3、rewrite模式
http://localhost/2015110/middle/thinkphp/index.php/Index/index/test/zzz/name/tom.shtml
有时候要把地址栏中的index.php去掉 localhost/.../hinkshop/Index/index
4、兼容模式
当默认服务器无法兼容pathinfo模式的时候
http://localhost/2015110/middle/thinkphp/index.php?s=/Index/index/test/zzz/name/tom.shtml
注意:URL模式的更改在配置文件中的Home/Conf/config.php中更改URL_MODEL的值来实现的
4.2、TP:跳转方法
1、提示性信息页面模版 ThinkPHP/tpl/dispatch_jump.tpl
$this->success(提示性信息,U(Action/Method));
$this->error(提示性信息);
也可以自定义跳转模板,在config.Php文件中添加如下配置项:
'TMPL_ACTION_ERROR' => 'Public/error';
'TMPL_ACTION_SUCCESS' => 'Public/success';
就可以使用自己定义的配置模版啦
2、页面重定向
当程序在一个方法里面想跳转另一个方法时候,需要传递数据过去!
Eg: 传值形式类似于U
//重定向到New模块的Category操作
$this->redirect('New/category', array('cate_id' => 2), 5, '页面跳转中...');
·单纯的URL跳转
redirect('http://www.baidu.com', 5, '页面跳转中...');
函数的redirect(“url地址”,5,'页面跳转中...')只能跳转本控制器
注意两种用法的区别:
第一种是类的成员方法$this->redirect(),第二种是普通函数,直接使用
4.3 调用模版:
一个控制器对应一个模版目录
IndexController.class.php------>项目目录/view/Index/XXXX.html
$this->display(只有文件名没有后缀)如果控制里面方法不想调用与之名称一致的模版文件用此方法
$this->display();
注意:当display方法的值为空的时候代表调用与此控方法名相同模版名
// 主题 在./Application/Home/conf/config.php
'DEFAULT_THEME' => 'default', //默认模板主题名称
注意:如果设置了主题(default),为了防止模版路径过深
配置:TMPL_FILE_DEPR =>"_"
所有模版文件:./Application/Home/view/default/控制器名_XXXX.html
控制器名_模版名.html
4.4 debug调试模式
1.index.php------------>define('APP_DEBUG', true);
开启trace追踪页面
2./App/conf/config.php------------->"SHOW_PAGE_TRACE" => true,
3.'SHOW_ERROR_MSG' => false,
//显示配置项“ERROR_MESSAGE”,3.2中设置为false,true反而不显示错误信息
//app_debug开启的话,强制忽略此时show_error_msg
"ERROR_MESSAGE"=>"听说丑的人都会犯这个错",
4.'URL_HTML_SUFFIX' =>'html|shtml|htm', // URL伪静态后缀设置
5. 配置文件
惯例配置文件
/ThinkPHP/conf/convention.php 项目默认配置,不要在此文件里面修改配置项的值
项目配置文件
/Application/Home/conf/config.php 配置项目里一些信息,可以自定义配置,
优先级 C()>当前模块config.php>Application/Common/conf/config.php> convention.php
return array(
"配置项" =>值,
....
)
在代码中可以使用系统提供的C函数
1. 读取 $变量 = C("配置项名称");
2. 修改 C("配置项的名称","值")
3. 动态配置 C("动态的配置项名称",值)
6.函数库
系统函数库
ThinkPHP/common/
-common.php(<3.1) 是全局必须加载的基础函数库,在任何时候都可以直接调用
-functions.php是框架标准模式的公共函数库,其他模式可以替换加载自己的公共函数库或者对公共函数库中的函数进行重新定义
-runtime.php(<3.1)是框架运行时文件,仅在调试模式或者编译过程才会被加载,因此其中的方法在项目中不能直接调用
3.2版本common.php和~runtime.php已经不存在,合并为functions.php
项目函数库
Application/Home/common/
项目函数库通常位于项目的Common目录下面,文件名为function.php,不能写错
函数使用:
引入函数所在命名空间
Namespacename\funcname();
7. 控制器的使用
7.1控制器之间的调用
1、本控制器调用其的控制器
$obj = A("控制器名");
eg: $Good = A("Good") //不是goodController
2、调用需要的方法
对象->方法名();
eg:
$Good->getHotGood();
作用:数据[代码]重用!
注意:在被调用的控制器里面那个方法 不能在调用模版了!数据以返回值的形式返回。
7.2 thinktemplate 模版引擎
1、调用模版:
$this->display();调用与此方法名一致的模版文件
$this->display(只有文件名没有后缀)
如果控制里面方法不想调用与之名称一致的模版文件用此方法
2、在展示模版之前,TP给我提供了两种往模版进行赋值的方法:
· $name = “张三”;
$this->name = $name;
$this->assign("模版变量名",php中的数据|变量)->assign(‘sex’,’xx’)->assign(‘age’,20)->display(“index”)
thinkPHP模版边界符默认 { }
前台使用:{$username}
'TMPL_L_DELIM'=>"{",
'TMPL_R_DELIM'=>"}"
注意:数组在模版中取值,可以是$arr[‘name’],也可以是$arr.name。
但是在模版中的数组元素值需要取值并运算的时候 只能使用 []的取值形式
模版变量也可以注释掉 {//$name}
模板引擎:
tp模版中的魔术变量
__ROOT__:会替换成当前TP项目的根目录(不含域名)
__APP__:会替换成入口文件地址(不含域名)
__MODULE__:会替换成当前模块的URL地址(不含域名)
__CONTROLLER__(__或者__URL__兼容考虑):会替换成当前控制器的URL地址(不含域名)
__ACTION__:会替换成当前操作的URL地址(不含域名)
__SELF__:会替换成当前的页面URL(入口文件)
__PUBLIC__:会被替换成当前网站的公共目录通常是 /Public/
注意:魔术方法无疑是提供了很大的方便性,但是当我们的跳转或者传值很复杂的时候,可以考虑模版中的{:U()}函数
8.模版中的控制结构
8.1: if结构
<if condition="$条件">
代码块
<elseif condition="条件"/>
代码块
<else />
代码块
</if>
eg:
<if condition="$username=='admin'">
管理员
<else />
非管理员
</if>
eq或者 equal: 等于 ==
neq 或者notequal:不等于 !=
gt: 大于 >
egt: 大于等于 >=
lt: 小于 <
elt: 小于等于 <=
heq: 恒等于 ===
nheq: 不恒等于 !==
8.2 switch结构:
<switch name="uname" >
<casevalue="admin">管理员</case>
<casevalue="admin1">注册用户</case>
<default/>
普通会员
</switch>
注意:
1.switch的name值,不能带$符号,否则就编译成变量的变量
2. value的值 不管什么类型都得带上引号
3.<switch></switch>中间不能放任何注释
8.3 TP模版标签
1、模版中的临时变量
<assignname="varname" value="123"/>
注意: value的值必须带上引号
2、判断变量是否等于某个值
<eq name="var_name(无$)" value="value(值)">(内容1)<else/>内容2</eq>
<neqname="var_name(无$)" value="value(值)">(内容1)<else/>内容2</neq>
3、判断变量是否为空
<emptyname="变量">1<else />2</empty>
<notemptyname="变量">1<else/>2</notempty>
4、判断变量是否被赋值
<present name="qe">1<else/>2</present>
<notpresentname="">1<else/>2</notpresent>
// empty和present的区别在于空字符串的识别,$a = “”. empty认为值为空,但是present认为已经被赋值。其他情况就一样了
5、判断某个变量是否等于多个值中的一个
<in name="变量名" value="值1,值2,值3">1<else/>2</in>
等同于:
if(in_array($varname,array(值1,值2,值3))){
echo1;
}else{
echo2;
}
<notin name="变量名" value="值1,值2,值3">1<else/>2</notin>
6、区间判断
<between name=’var’ value=’start,end’></between>
7、常量的定义:
<define name="DB_HOST"value="localhost"/>
<definedname="DB_HOST">1<else/>2</defined>
<ifcondition="defined('DB_HOST')">
1
<else />
2
</if>
if(defined("DB_HOST")){
echo1;
}else{
echo2;
}
注意:模版中的常量输出 {$Think.const.HHH}或者{:HHH}
8.4 标签中的代码直接输出 模版代码不解析
<literal>
{$tag}
</literal>
8.5 在模版中直接写PHP代码
<php>
echo 1;
</php>
||
<?php echo 1;?>
8.6、模版中的三元运算符
{ $var>10?”yes”:”no” }
模版中的三元运算符等同于PHP中的三元运算符,并且写法规则也是一样的
8.7、循环结构:
for循环
<for start=’100’ end=’0’ comparison=”elt” step=-1 name=’i’>
</for>
Start : $i=100;
Comparison: elt 表示小于等于,当然也可以切换其他比较符号
End: $i=0; $i<=$end
Name: $i
在for标签中 可以省略comparison,默认就是start<end
foreach
<foreach name="变量名" item="vo"key="k">
{$vo}
</foreach>
name:被遍历的数组----->从php页面传过来的模版变量,无$符号
item:数组的元素 value的变量名
{$vo.键名} === {$vo["键名"]}
Volist
标签主要用于在模板中循环输出数据集或者多维数组
<volist name="list"id="vo" offset="5" length='10' mod=’2’ empty=”对不起,数组不存在” >
{$mod} {$vo.name}
</volist>
Name:遍历的数组的名称
Id:每个数组元素值的表示符号,等同于foreach中的 $key=>$vo中的$vo
Offset:数组元素起始下标
Length:循环的数组元素个数
Empty:当遍历的数组不存在的时候,执行该句输出
Mod:作为取模的参数使用的
在遍历内部用$mod来接收当前记录索引值对mod取余的结果
Key: 当不定义时,可以使用{$key}表示标识符,使用{$i}标识当前是第几次循环
而定义key属性的时候,属性值不为key时,都表示为第几次循环。
8.8 函数的使用在模版中使用的是PHP的函数
{$webTitle|md5|strtoupper|substr=###,0,3|。。。}
编译后的PHP代码就是:
<?phpecho (substr(strtoupper(md5($webTitle)),0,3)); ?>
###表示传递实参数是当前的那个标量
{$add_time|date="Y-m-d H:i:s",###}
注意:在使用模版函数的时候,什么时候会用到###???
在模版中使用函数时,如果该变量不是函数的第一个参数的时候,在后续的参数设置过程中需要用###来代替本变量,但是如果本变量本来就是作为第一个形参传递到函数中的时候,就可以把###省略掉了
8.9、系统变量
模板引擎还支持系统变量和系统常量、以及系统特殊变量的输出。它们的输出不需要事先赋值给某个模板变量。系统变量的输出必须以$Think.打头,并且仍然可以支持使用函数
Eg: {$Think.now} 以默认格式获取当前的日期时间(非时间戳格式)
默认常量,当前时间戳
{$Think.const.NOW_TIME|date='Y-m-d H:i:s',###} 把当前时间戳转换成指定日期时间格式
{:NOW_TIME|date='Y-m-d H:i:s',###}这种有编译错误
8.10模版中文件的引入
<include file="路径+文件" />
用法1: <includefile="./App/Tpl/default/head.html" />
这种写法中,必须从index.php项目入口文件开始写,而且模版文件也必须带上后缀
用法2:
<include file="Pub/header" /> 或者 <include file=”Pub:header”>
这种写法是指 引入某个控制器的某个方法,
而该方法会自动调用与方法名相同的模版名,所以此时是不需要加上后缀的。
css|js|images|文件的引入:
<importtype='js' file="Js. user" /> //引入js文件的名称为user.js
<import type='css' file="Css.style,Css.index"/> //引入的css文件名为style.css和index.css
上面的方式默认的import的起始路径是网站根目录下Public目录,并且默认的type就是js
也可以如下引入:
<jsfile="__PUBLIC__/Js/Common.js"/>
<cssfile="__PUBLIC__/Css/common.css"/>
注意:外部的JS和外部的CSS中使用到的图片全部都是用相对路径。
Css的相对路径是相对于CSS文件本身,所以是../images/xxx.jpg
但是JS的图片是相对于模版目录,而且忽略主题设置,所以是 ../../Public/images/xxx.jpg(3.1)
在3.2里面则直接以入口文件为相对路径“./Public/img/xxx.jpg”
可以以服务器根目录/来设置
9、数据库连接
在配置文件中作如下设置:
'DB_NAME' =>'thinshop', //数据库名
'DB_USER' => 'root', //用户名
'DB_PWD' => '', //密码
'DB_PREFIX' => '', //数据库表前缀
'DB_CHARSET' => 'utf8', //数据库编码默认采用utf8
ThinkPHP中不需要用户自己去创建数据库连接或者实例化数据库对象,只有当你去实例化模型层的时候,基类Model才会自动帮你连接数据库
10、实例化模型层
1、实例化标准模型(基础模型基类model)
a) $obj =new Model(‘user’);
b) $obj =M(‘user’);
注意:
在TP的要求中,实例化基础模型层的时候后,M的参数必须是一张存在的表
2、实例化自定义模型层
a) $obj =new UserModel()
b) $obj =D(‘User’);
注意:D方法和M方法的区别
D和M都可以实现对表对象的实例化,对表的CRUD操作也都是一样的,不同的地方在于,D方法实例化一个表对象的同时也代表着实例化了一个模型层的类文件,所以D方法既可以像M一样操作数据库,也可以用自己的模型层文件中的自定义的方法,自然在功能上就比M强大了一些,当然,运行速度也就降了下来。
还有,当模型层文件不存在的时候,D===M。因为在编译过程中,发现需要实例化的模型层文件不存在,那么,对D的编译就会变成对M的编译。
3、实例化公共模型层 extends
a) 当我们需要每一个模型都需要额外的方法时候,为了避免每个模型都要做同样的处理,那么我们选择设置一个公共的模型层。
b) 实现方法是 让这个CommonModel类继承 Model类,然后其他的类全部都继承CommonModel类
4、实例化空模型层
$obj = M();
a) 为了让不熟悉TP框架的ORM的人能快速上手TP的数据库操作,ThinkPHP提供了空模型层的概念
或者 有某种数据库操作非常非常复杂,复杂到ORM处理起来非常困难的地步,这个时候推荐大家使用空模型层的概念直接进行底层数据库操作
b) 这个空模型层只有两种方法
1、$obj->query();
Query对查询操作的返回是数组,对增删改的返回是空数组
2、$obj->execute();
Execute对查询操作的返回是查询的记录数,对增删改的返回是影响行数
所以:增删改使用execute方法,而查询则使用query方法。
Dump函数:TP系统提供的输出数组的方法
$obj->getLastSql():可以输出最后一个sql语句,可以用他来排除我们后期ORM语句组装产生错误 别名 _sql();
或者通过打开‘SHOE_PAGE_TRACE’=>TRUE的trace调试模式中的SQL选项卡来监视数据库操作
11、数据库操作
11.1、增
insertinto表 (字段列表) values(对应的数据列表),(),(),()
insertinto表 set字段1=值1,字段2=值2.......
1、模型对象->add($data)
$data:一个一维关联数组,以键名作为表字段,以数组元素值
作为字段内容
返回值:lastInsertId
2、模型对象->addAll($data)
$data:一个二维关联数组,以表字段作为键名,以字段内容作为数组元素值
返回值:lastInsertId
注意add和addAll获取的lastInsertId的区别。
3、模型对象->data($data);
使用data方法来准备将要被插入表的数据
$data:一维关联数组,与前两条结构相同
$user->data($data)->add(); //连贯操作
吐槽声一片,不如直接$user->add($data)这种方法。
4、模型对象->create()
帮助用户快速过滤表单提交的数据。
Eg: $_POST = array(
‘name’=>’张三’,
‘pwd’=>”123456”
‘sub’=>注册
)
如上述表单提交的数组中,name、pwd都是user表的字段,也是本次操作所需要操作的内容,但是sub就明显不是数据库字段,在操作的时候就需要排除$_POST中的sub
$data = $user->create($_POST);
如果经过create操作之后,$data = array(‘name’=>’张三’,’pwd’=>”123456”),就可 以直接作为诸如add等方法的参数而使用了
注意:就像我们创建的Model文件的名称必须和表明相同一样,
我们创建的form的name的属性值也应该和表的字段名相同,这样才更符合tp的规则
11.2、 删除
delete from表名条件
$user->where("条件")->delete(); 返回影响的记录条数
$M->delete(主键值); //AR的模式操作
11.3、更新 save
update表名 set字段名=value,字段名=value,........ where条件
点击修改----->控制器方法(通过传值的数据的标识,获取数据,传入模版)----->编辑页面(把数据填入到表单对应的位置)----->更新(标识传入过去)------->控制方法里面(获取更新的数据的标识)---->更新
$user= M(‘user’);
$where = “id=3”;
$data[‘name’] =’新名称’//注意此时的data需要以数组形式存储需要修改的值 区别于where
$user->where($where)->save($data);
11.4、查询
基础查询
1、模型对象->find() 一条记录转化成一维的数据 字段名=>value
select* from表 limit 1
2、模型对象->select() 查询所有的记录 转化为一个二维的数组
条件查询
3、单条件
模型对象->where($where)->select()
Eg: $where =”name=’张三’”;
4、多条件查询时
模型对象->where($where)->select()
①、依旧是字符串:$where =”name=’张三’ and age=20 or.....”;
②、更倾向于使用数组
$where = array("字段1"=>值1,"字段2"=>值2)
注意:此时数组的多个条件之间是默认使用 AND来连接的!!并且数组条件会自动和表字段映射,过滤掉表中不存在的字段。
如果想要条件之间是OR,则需要在$where这个数组中添加一个这样的键值对 “_logic”=>”or”
eg: $where = array('id'=>6,'subject'=>"测试新闻",'_logic'=>"or");
表达式查询
5、如果条件中需要 > < != in not in between and 等查询条件时
格式: $where[‘字段名’] = array(‘表达式’,’条件’)
Eg:查询uid>3的信息
$where = array(‘uid’=>array(‘gt’,3));
$where = array('id'=>array('between','3,5'));
$where = array('id'=>array('notbetween','3,5'));
$where =array('id'=>array('in','1,3,5'));
$where =array('id'=>array('not in','1,3,5'));
$where =array('subject'=>array('like','%测试%'));
$where =array('subject'=>array('like',array('%测试%','%中%')));
//注意这里like的两个条件是用or来连接
$where =array('id'=>array(array('lt',2),array('gt',5),'or'));
$user->where($where)->select();
6、聚合函数的应用
Count $user->count(); 计算表中的数据条数
Sum $user->sum(‘mark’);
Max $user->max(‘mark’);
Min $user->min(‘mark’);
Avg $user->avg(‘mark’);
7、排序 order
$user->order("id desc")->select();
$user->order("id desc,name asc")->select();
$user->order(array("id"=>"desc","name"=>"asc"))->select();
8、字段筛选 field
field(“字段1,字段2”)选择需要查询的字段
$user->field("id,name")->select();
参2:true->取反 , false:默认
连贯操作:
$user->field("id,name")->select();
9、限制 limit()
limit(start,length);
$user->field("id,name")->order(‘idasc’)->limit(0,5)->select();
10、分页方法
TP内置了分页方法,用法和limit类似
Page(页码,每页条数) 每页条数默认是20条
$user->field("id,name")->order(‘idasc’)->page(1,5)->select();
但是我们实际上用不到分页方法,因为TP还提供了分页类,完爆这种分页方法
11、分组group
Group("addr");
与group相对应的方法 还有一个having
having(); 附加的条件
$user->filed(’addr,count(addr) as num’)->having(“score>90”)->group(‘score’)->select();
12、多表查询 table
Table(array(‘a表明’=>’别名’,‘前缀_表明’=>’别名’))
前缀_tableName",可以通过任何一个模型层对象去调用数据库中任何一个表的数据内容
注意:是带有表前缀和后缀的表名,因为在table函数中没有增加前缀和后缀的功能
$data=M()->table(array(‘stu’=>’s’,’mark’=>m))->where(‘s.sid=m.sid’)->select();
13、alias() :给表取别名
$M->alias(‘m’)->
14、join方法
join()多表连接查询 默认:inner join
有表前缀的表需要带上表前缀
$M->join("表2 on表1.字段=表2.字段")......->select();
$data = M('user u')->join('messagem onu.uid=m.uid')->field("u.uname,u.addr,m.mcontent")->select();
1、默认是内连接,怎么改成左链接或者右连接??
2、如何进行3表或多表查询?
$data = M('user u')->join('inner join message m onu.uid=m.uid')->join('inner join response re onu.uid=re.reuid')->field('u.uname,u.addr,m.mcontent,re.recontent')->select();
内连接: $m->join("inner join表2 on表1.字段 =表2.字段")->join("innerjoin表3表2.字段 =表3.字段").......->select();
右连接: $m->join("rightjoin表2 on表1.字段 =表2.字段")->join("right join表3 on表2.字段 =表3.字段").......->select();
11.5、TP的ORM中事务的使用
事物:
$M->startTrans():开启事务; mysql_query("begin")
$M->commit():提交事务;
$M->rollback():回滚事务;
$M->startTrans();
$row=$M->where("id=".$id)->delete()
if($row){
$id2=$M->where("uid=".$id)->delete();
if($id2){
$M->commit();
}else{
$M->rollback();
}
}else{
$M->rollback();
}
11.6、常用的获取表信息、数据库操作信息的方法
模型对象->getDbError();//得到程序中,数据库操作中的错误 mysql_error();
模型对象->getLastSql();获取最后一条执行的sql语句 _sql()
模型对象->getDbFields():得到模型层中模型的数据库某个表中 字段信息
模型对象->getModelName():得到当前模型层中模型层名字
模型对象->getTableName():得到当前模型层中对应的表名
模型对象->getPk();获取当前操作数据表的主键名
11.7、动态查询
getBy字段(数据):查询某个表中有该字段值的记录;
该查询方式针对数据表的字段进行查询。例如,User对象拥有id,name,email,address等属性,那么我们就可以使用下面的查询方法来直接根据某个属性来查询符合条件的记录。
$User= M("user");
1、$data = $User->getById(100);== $data =M("user")->where("id=100")->find();
2、$data =$User->getByName("admin");==$data= $M->where("name='admin'")->find();
12、数据库切换:
如果需要切换到另外一个数据库(包括在相同和不同的数据库类型之间切换)或者需要连接多个数据库进行操作不同的数据,就需要使用ThinkPHP提供的数据库切换方法(M、db)
1. 直接链接
$m = M("表名","表前缀","数据库类型://用户名:密码@服务器名:端口号/库名");
$M =M("news","","mysql://root:@localhost/mid112");
2. 读取配置文件切换链接
$m = M('weibo','tk_','DB_CONFIG2');
DB_CONFIG2----->config.php
"DB_CONFIG2" => array(
'db_type' => 'mysql',
'db_user' => 'root',
'db_pwd' => 'admin',
'db_host' => 'localhost',
'db_port' => '3306',
'db_name' => 'tk89'
注意:在使用切
换数据库时,不能让两个库中的表名相同,否则在查询的时候,优先查询自己的表,只有当默认连接的库中表不存在的时候才会查询第二个连接(3.1是这样 3.2已经优化)
13、控制器中用得到的常量:
echo MODULE_NAME;
echo APP_NAME; (3.1)
echo ACTION_NAME;
echo THINK_VERSION;
14、TP的会话控制
session: 系统提供了Session管理和操作的完善支持,全部操作可以通过一个内置的session函数完成。
默认情况下,初始化之后系统会自动启动session,如果不希望系统自动启动session的话,可以设置SESSION_AUTO_START为false,例如:
'SESSION_AUTO_START' =>false
session赋值:Session赋值比较简单,直接使用: session('name','value');
如果需要存储多个值的时候,只能一个一个赋值,数组形式的赋值是对session做配置,不是存储session信息:
session取值: $value= session('name');
session删除 : session('name',null);//删除name ;要删除所有的session,可以使用session(null);
session判断: 要判断一个session值是否已经设置,可以使用 session('?name');// true|false用于判断名称为name的session值是否已经设置
COOKIE: cookie()
Cookie设置 :setcookie("name",value,time,path,domain);cookie('name','value'); //设置cookie永不过期cookie('name','value',3600);//指定cookie保存时间
Cookie获取:$value= cookie('name'); 获取所有cookie信息$cookies = cookie();
Cookie删除:删除某个cookie的值,使用:cookie('name',null);要删除所有的Cookie值,可以使用cookie(null);//清空当前设定前缀的所有cookie值
15、TP模型扩展
ThinkPHP本身提供了丰富的模型扩展,目前提供的的扩展模型包括:高级模型(AdvModel)、视图模型(ViewModel)、关联模型(RelationModel)和Mongo模型都是继承Model类并且都通过了扩展完成了很多其他的功能。
Eg:高级模型 AdvModel
ThinkPHP\Library\Think\Model
扩展高级模型的使用:
在3.2以上版本,使用扩展模型需要带上命名空间use Think\Model\AdvModel;
①、自定义模型层的时候选择继承高级模型,而不是继承基础模型
Class UserModel extends AdvModel{}
②、让公共模型层 CommonModel.class.php继承高级模型
Class CommonModel extends AdvModel{}
③、通过switchModel()函数切换模型层
$User->switchModel("Adv")->top10();
④、直接通过M函数
M("AdvModel:User")->top10();
16、几个需要用到模型文件的功能
1、字段映射:ThinkPHP的字段映射功能可以让你在表单中隐藏真正的数据表字段,而不用担心放弃自动创建表单对象的功能
Class UserModel extends Model{
protected $_map = array(
// "表单控件名"=>"数据库字段名",
"biaoti" => "title",
"neirong" => "content",
);
}
这样,在Action中使用create方法去过滤表单数据的时候就会根据$_map去做过滤了
2、自动完成
在Model类定义 $_auto属性,可以完成数据自动处理功能,用来处理默认值、数据过滤以及其他系统写入字段。
Eg:正常的表单处理过程需要对密码进行md5加密,在TP中,我们就可以完成它的自动加密。具体做法是在对应的model类中定义$_auto变量,书写自动完成规则,这样,在使用create()完成表单过滤的同时,就已经完成了对password字段的md5加密了。
$auto = array (
array('password','md5',1,'function') // 对password字段在新增的时候使md5函数处理
);
3、自动验证
TP内置了数据对象的自动验证功能来完成模型的业务规则验证,而大多数情况下面,数据对象是由表单提交的$_POST数据创建。需要使用系统的自动验证功能,只需要在Model类里面定义$_validate属性,
protected $_validate = array(
array('verify','require','验证码必须!'), //默认情况下用正则进行验证
array('name','','帐号名称已经存在!',0,'unique',1), // 在新增的时候验证name字段是否唯一
array('value',array(1,2,3),'值的范围不正确!',2,'in'), // 当值不为空的时候判断是否在一个范围内
array('repassword','password','确认密码不正确',0,'confirm'), // 验证确认密码是否和密码一致
array('password','checkPwd','密码格式不正确',0,'function'), // 自定义函数验证密码格式
);
定义好了$_validate之后,在进行create操作的时候,就会对表单的数据进行自动验证。如果验证失败,则create()返回false,可以通过模型对象->getError()的方法捕获验证失败的反馈信息
Eg:
$article = D("Article");
$data =$article->create();
if (!data){
//如果创建失败表示验证没有通过输出错误提示信息
exit($article->getError());
}else{
dump($data);
//验证通过可以进行其他数据操作
}
17、thinkphp中ajax操作:
_param()
1) IS_AJAX,IS_POST,IS_GET:判断标签或者数据提交方式,
IS_AJAX:如果数据提交方式,是按照ajax提交方式提交的,那么他会返回正确,否则,返回错误.
2) ajax返回,返回的都是json数据:
ajaxReturn($data):返回ajax提交的结果
$data指返回的数据。
该数据可以是字符串,数值,或者数组
都会被ajaxreturn转换成JSON对象,方便前端jq,js操作。
3) ajax返回中也可以使用: success()和error().
Eg: $this->seccess(“yes”,”Index/index”);
AJAX
获取的返回信息:
{"info":"yes","status":1,"url":"Index\/index"}
如果是error()的话,获取到的status则为0
4)设置ajax返回的数据样式配置:
'DEFAULT_AJAX_RETURN' =>'JSON', //默认AJAX数据返回格式,可选JSON XML ...
18、数据分页:第三方的分页类 page类
F:\wamp\www\2015112\tp\ThinkPHP\Library\Think\page.class.php (第三方类库的使用)
一、利用Page类和limit方法
$page = new \Think\Page(总记录数,每页显示条数);
$User = M('User');//实例化User对象
$count = $User->where('status=1')->count();//查询满足要求的总记录数
$Page =new \Think\Page($count,25);//实例化分页类 传入总记录数和每页显示的记录数(25)
$show = $Page->show();//分页显示输出
// 进行分页数据查询 注意limit方法的参数要使用Page类的属性
$list =$User->where('status=1')->order('create_time')->limit($Page->firstRow.','.$Page->listRows)->select();
$this->assign('list',$list);//赋值数据集
$this->assign('page',$show);//赋值分页输出
$this->display();//输出模板
二、分页样式定制
private $config =array(
'header' =>'<span class="rows">共 %TOTAL_ROW%条记录</span>',
'prev' => '<<',
'next' => '>>',
'first' => '1...',
'last' => '...%TOTAL_PAGE%',
'theme' =>'%FIRST%%UP_PAGE%%LINK_PAGE%%DOWN_PAGE%%END%',
);
三、实例
注意:使用limit方法的时候,参数必须是page类的成员变量
19、验证码:
1、生成验证码
$Verify = new \Think\Verify();
$Verify->entry();
2、验证码的显示:
Img标签的src属性值直接设置为生成验证码的方法即可
Eg: <img src="{:U('Home/User/verify')}" id="yzm">
注意:验证码生成之后 是直接加密之后存储在session中的,且默认设置包含验证码有效时间1800S和验证成功之后,session存储的验证码信息直接清空
4、验证码配置
$config=array{
'useImgBg' => false, //使用背景图片
'fontSize' => 25, //验证码字体大小(px)
'useCurve' => true, //是否画混淆曲线
'useNoise' => true, //是否添加杂点
'imageH' => 0, //验证码图片高度
'imageW' => 0, //验证码图片宽度
'length' => 5, //验证码位数
'fontttf' => '', //验证码字体,不设置随机获取
'bg' => array(243, 251, 254), //背景颜色
'reset' => true, //验证成功后是否重置
);
注意:
1、如果图片出不来,试试将ob_end_clean()添加到实例化对象之前
2、不要使用其中的imageH和imageW,如需改变大小直接通过CSS操作<img>
3、中文验证码需要字体文件,如果中文不显示,请检查ThinkPHP\Library\Think\Verify\zhttfs中是否包含了中文字体文件
3、验证验证码:
使用ajax调用Verify类的Check方法即可!
<script>
functioncheck(){
var val= $(".verify").val();
var data ="verify="+val;
$.post("{:U('Home/User/check_verify')}",data,function(re){
if(re==true){
$(".verify").css("border","1px solidgreen");
}else{
$(".verify").css("border","1px solidred");
}
})
}
$(".verify").blur(check);
$("#yzm").click(function(){
var num =Math.random();
var url ="{:U('Home/User/verify/asd/"+num+"')}";
$(this).attr("src",url);
check();
})
</script>
</div>
注意:验证码刷新功能需要带上一个随机数,以保证不会读取ajax缓存导致无法刷新
20、文件上传: Library/ORG/Net/UploadFile.class.php 文件上传类
1、引入并使用
$upload = new\Think\Upload($config);
$info=$upload->uploadOne($_FILES['photo']);单文件上传
$info=$upload->upload(); //多文件上传
注意:
1、使用upload方法不需要任何参数,但是使用uploadOne方法,需要带上上传文件的信息
2、上传之后将会返回上传的文件的存储信息
Dump($info)查看文件信息
2、上传配置:
$config = array(
'mimes' => array(), //允许上传的文件MiMe类型
'maxSize' => 0, //上传的文件大小限制 (0-不做限制)
'exts' => array(), //允许上传的文件后缀
'autoSub' => true, //自动子目录保存文件
'subName' => array('date', 'Y-m-d'), //子目录创建方式,[0]-函数名,[1]-参数,多个参数使用数组
'rootPath' => './Uploads/', //保存根路径
'savePath' => '', //保存路径
'saveName' => array('uniqid', ''), //上传文件命名规则,[0]-函数名,[1]-参数,多个参数使用数组
'saveExt' => '', //文件保存后缀,空则使用原后缀
'replace' => false, //存在同名是否覆盖
'hash' => true, //是否生成hash编码
'callback' => false, //检测文件是否存在回调,如果存在返回文件信息数组
'driver' => '', //文件上传驱动
'driverConfig' => array(), //上传驱动配置
);
21、获取ip:
系统提供了直接获取IP的函数
$ip = get_client_ip();
如果想要获取ip地址所在区域,
$Ip = new\Org\Net\IpLocation('UTFWry.dat');//实例化ipLocation类参数表示IP地址库文件
$area = $Ip->getlocation($ip); //获取某个IP地址所在的位置
print_r($area);
UTFWry.dat下载地址:http://www.thinkphp.cn/extend/270.html
解压之后放在和IpLocation类同级目录
22、项目分组:
对模块的访问是自动判断的,所以通常情况下无需配置模块列表即可访问,在部署模块的时候,默认情况下都是基于类似于子目录的URL方式来访问模块的,例如:
http://serverName/Home/New/index//访问Home模块http://serverName/Admin/Config/index //访问Admin模块http://serverName/User/Member/index//访问User模块
1、设置项目中允许的模块
如果我们需要设置分组的话,需要手动更改tp\Application\Common\Conf\congfig.php,添加如下配置:
'MODULE_ALLOW_LIST' =>
array(
'Home',
'Admin',
'User')
,
'DEFAULT_MODULE' =>
'Home',
// 默认模块
2、拒绝访问模块
如果你的应用有很多的模块,你只是想禁止访问个别模块的话,可以配置禁止访问的模块列表(用于被其他模块调用或者不开放访问),默认配置中是禁止访问Common模块和Runtime模块(Runtime目录是默认的运行时目录),我们可以增加其他的禁止访问模块列表:
// 设置禁止访问的模块列表
'MODULE_DENY_LIST' =>
array(
'Common',
'Runtime',
'User'),
3、模块映射
如果不希望用户直接访问某个模块,可以设置模块映射(对后台的保护会比较实用)。
'URL_MODULE_MAP' =>
array(
'test'=>
'admin'),
注意:这里的映射指的是,隐藏admin模块,访问admin模块表面上体现的是访问test模块,设置了模块映射后,原来的Admin模块将不能访问,只能访问test模块。
我们访问 http://serverName/Admin将会报模块不存在的错误,而 http://serverName/test 则可以正常访问Admin模块。
如果你同时还设置了MODULE_ALLOW_LIST参数的话,必须将允许模块列表中的原来的模块改成映射后的模块名,例如:
'MODULE_ALLOW_LIST' =>
array(
'Home',
'Test',
'User'),
'DEFAULT_MODULE' =>
'Home',
'URL_MODULE_MAP' =>
array(
'test'=>
'admin'),
问题:
Q:加入做了模块映射,那么超链接跳转地址写映射前还是映射后?
A:依然是映射前,会自动映射。比如,把Admin影射成Test,但是实际写的U用的依然是Admin
函数:
A函数 控制器之间的调用
D函数 D函数用于实例化Model对象(模型文件必须存在)
M函数 M函数用于实例化一个没有模型文件的Model
C函数 配置文件操作
U函数 Url生成
S函数 数据缓存
F函数 文件缓存
I函数
$uname =I("get.password","","trim,md5"); //可以设置多个过滤规则
session函数
cookie函数