ThinkPHP-MVC什么是框架
什么是框架,框架,即framework。其实就是某种应用的半成品,就是一组组件,供你选用完成你自己的系统,MVC是一个设计模式,它强制性的使应用程序的输入、处理和输出分开。使用MVC应用程序被分成三个核心部件:模型、视图、控制器。
Zend Framework
Yii
Symfony
Codelgniter
ThinkPHP
……
3、什么是MVC
MVC是施乐帕克研究中心 (Xerox PARC)在八十年代为编程语言Smalltalk-80发明的一种软件设计模式,至今已被广泛使用。
M:Model模型
V:View视图
C:Control 控制器
快速入门
控制器
视图
模型
实用项
4、介绍thinkphp
http://thinkphp.cn
下载thinkphp3.0
直接部署到项目中
php5.2
thinkphp1.0 php5.0
thinkphp3.0 php5.2
thinkphp3.2.2 php5.3
项目布署流程:
1)解压thinkphp,并进入到解压出来的文件夹
2)将ThinkPHP文件夹放在我们的项目中
5、快速入门
1)开发项目入口文件
2)运行以上程序,自动创建相应的程序文件
看到以上界面,说明项目创建成功
在我们的项目中,自动产生了一些文件夹,如下图所示:
Common 项目公共文件目录
Conf 项目配置目录
Lang 项目语言包目录
Lib 项目类库目录
Tpl 项目模板目录
Runtime 项目运行时目录
~runtime.php 这个文件会自动将项目的当前配置、公共函数等程序编译到这个文件中,下次程序运行时,直接运行这个文件即可。
以上URL中的Index会被自动处理为模块名
以上URL中的index会被自动处理为动作名
3)开启调试模式
代码:
运行:
开启调试模式之后,如果发生了一些错误,会有一些提示信息,建议:
开发时,开启调试模式
布署时,关闭调试模
如果你的项目路径与本题相同,可以不定义三个路径常量
注意:开启调试后,不会产生runtime.php文件
4)分析项目入口文件
5)默认配置
为什么输入地址之后,可以看到内容
因为使有以上url时,会自动加载Index模块控制器下的index方法
在框架配置文件中,复制两个配置选项
将以上选项放在项目配置文件中
6)添加新的控制器以及方法
在Lib/Action下创建新的控制器GoodsAction
在GoodsAction中添加新方法add
运行以上程序:
为add方法添加指定模板并显示
一个项目对应一个数据库
一个数据库中包含很多数据表
一个数据表就是一个模块
一个模块可以对应一个控制器
在Tpl下创建Goods文件夹,用于存放所有Goods模块下的模板
修改控制器代码:
运行:
7)配置项目的虚拟主机
修改apache配置文件:
修改hosts文件:
重启apache并重新运行:
二、控制器
1、什么是控制器
控制器用于接收和处理用户的请求
2、定义控制器
在Lib/Action下创建控制器文件
文件名:模块名(首字母大写)Action.class.php
如:我们有一张数据表:member,会员表
/Lib/Action/MemberAction.class.php
控制器内容:
class 模块名(首字母大写)Action extends Action{
}
必须继承父类控制器Action
代码:
3、url调度模式
url的调度模式就是url的访问方式
ThinkPHP支持四种URL模式,可以通过设置URL_MODEL参数来定义
这个配置选项的值共有四个
0 :普通模式
1 :pathinfo模式(默认)
2 :rewrite模式
3 :兼容模式
1)普通模式
语法:
http://项目/入口文件?m=模块名&a=动作名
运行:
2)pathinfo模式
语法:
http://项目/入口文件/模块名/动作名
运行:
在项目的配置文件中,可以修改以下选项修改路径分隔符
URL_PATHINFO_DEPR
访问时:
3)rewrite模式
(1)修改config.php配置选项
(2)httpd.conf配置文件中加载了mod_rewrite.so模块
(3)AllowOverride None 将None改为 All
(4)把下面的内容保存为.htaccess文件放到入口文件的同级目录下
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L]
</IfModule>
语法:
http://项目/模块名/动作名
运行:
4)兼容模式
语法:
http://项目/入口文件?s=/模块名/动作名
运行:
4、空操作
空操作是指系统在找不到指定的操作方法的时候,会定位到空操作(_empty)方法来执行,利用这个机制,我们可以实现错误页面和一些URL的优化。
语法:
public function _empty($name){
}
1)错误页面的定制
访问时:
2)优化url
访问:
我们访问时,由于没有shanghai方法,所以会自动定位到_empty方法中,并将shanghai做为参数传递给$name。
5、空模块
空模块的概念是指当系统找不到指定的模块名称的时候,系统会尝试定位空模块(EmptyAction),利用这个机制我们可以用来定制错误页面和进行URL的优化。
语法:
class EmptyAction extends Action{
}
MODULE_NAME:请求的当前模块名称
1)错误页面的订制
运行:
系统找不到abc控制器,所以会自动定位到EmptyAction中。
2)优化url
运行:
6、项目分组
一般网站项目是由若干个小项目构成的,如:前台、后台、会员、博客等
配置文件config.php中有两个选项,用于配置项目的分组
?APP_GROUP_LIST :分组列表
?DEFAULT_GROUP :默认组名
1)修改配置文件
2)创建分组控制器目录
3)运行
4)对模板进行分组
7、url大小写
TP中的url严格区分大小写,如果想不区分大小写,可以修改以下选项:
配置文件:config.php
?‘URL_CASE_INSENSITIVE’=>true
运行:
8、页面跳转
在需要对用户的操作信息进行提示时,可以使用以下两个方法:
?success :操作成功时所调用的方法
?error :操作失败时所调用的方法
配置文件:config.php
?TMPL_ACTION_SUCCESS :success方法对应的模板
?TMPL_ACTION_ERROR :error方法对应的模板
代码:
运行:
配置文件中:
可以修改以上选项,实现自定义模板
9、页面重定向
如果想实现页面的重定向,可以使用以下方法:
redirect
语法:
$this->redirect(“news/show”, array(‘id’=>2), 5, “页面跳转中” );
参数1:跳转地址
参数2:参数数组
参数3:停留时间
参数4:提示信息
三、视图
1、什么是视图
用户看到的并与之交互的界面
在tp中,视图主要包含两部份:
1)视图类
2)模板
2、模板定义
默认的模板文件定义规则:
模板目录/[分组名/]模块名/操作名+模板后缀
TMPL_TEMPLATE_SUFFIX :模板后缀名
3、分隔符
?'TMPL_L_DELIM'=>'<{', :模板左分界符 默认:{
?'TMPL_R_DELIM'=>'}>', :模板右分界符 默认:}
4、模板赋值与输出
模板赋值:
$this->assign(‘模板变量名’,’值’);
模板输出:
$this->display(‘模板名’);
5、模板字符串替换
在tp的模板中,默认有一些字符串表示一些路径
?__PUBLIC__:当前网站的公共目录
?__APP__: 当前项目的URL地址
?__GROUP__:当前分组的URL地址
?__URL__: 当前模块的URL地址
?__ACTION__:当前操作的URL地址
?TMPL_PARSE_STRING :可以在配置文件中配置此选项,用于一些常用路径的定义
模板文件:
运行:
配置文件:
模板文件:
6、获取内容
?$this->fetch();
fetch :获取内容,返回字符串
display :输出字符串
7、模板注释
tp的模板中可以加入注释,有两种方式:
?{/* 注释内容 */ } 多行注释
?{// 注释内容 } 单行注释
运行:
可以看出,tp模板注释属于服务器端注释,不会显示在客户端中
8、变量输出
在tp的模板中,变量输出主要有三种形式:
1)普通变量
{$name}、{$email}
2)数组变量
{$row[‘name’]}、{$row.name}
3)对象变量
{$obj:name}、{$obj:test()}
控制器代码:
模板代码:
运行结果:
9、系统变量
在tp的模板,有一个内置的对象,它是:$Think,它可以引用很多系统内置的变量
?$Think.server $_SERVER
?$Think.get $_GET $Think.get.username
?$Think.post $_POST
?$Think.request $_REQUEST
?$Think.cookie $_COOKIE
?$Think.session $_SESSION
?$Think.config 引入配置文件中的值
运行:
10、使用函数
语法:
{$name|fn1|fn2=arg1,arg2,### }
运行:
11、默认值
语法:
{$变量|default="默认值"}
以下情况时会自动使用default后面的内容:
1)没有为这个变量分配数据
2)向这个变量分配空数据
12、运算符
在模板中,可以直接使用算术运算符对变量进行运算
?+ {$a+$b}
?- {$ab}
?* {$a*$b}
?/ {$a/$b}
?% {$a%$b}
?++ {$a++} 或 ?{++$a}
?-- {$a--} ?或 {--$a}
控制器:
模板:
运行:
13、文件包含
语法:
<include?file="模板文件名"?/>
是基于项目的入口文件位置。
./Tpl/Admin/Public/header.html
目录结构:
Public:所有公共页模板
在模板中:
include的另一种语法:
<include file=’模块:操作’ />
在上题中,在Index模块下的模板中,可以直接使用这种语法来引用其它模块下的模板
footer.html
运行:
14、导入文件
导入文件是指对资源文件(css、js)的导入
语法:
<import type=‘type’ file=‘file’ />
file(必须):资源文件
type(可选):资源文件类型,默认为js
起始路径是网站的Public目录
以前的导入方式:
文件目录:
模板代码:
运行:
15、volist标签
语法:
<volist?name="list"?id="vo">
{$vo.id}
{$vo.name}
</volist>
?name(必须):要遍历的数组变量
?id(必须):当前数组元素
?offset: 要输出数据的offset
?length: 输出数据的长度,需要指定offset
?key: 循环索引,从1开始排列,默认值:i
控制器:
模板:
运行:
16、foreach标签
foreach用于解析数组
语法:
‘
<foreach name="list"?item="vo" >
{$vo.id}
{$vo.name}
</foreach>
name:要解析的数组名称
item:当前解析到的数组元素
模板:
运行:
17、if标签
语法:
?<if?condition="$name eq 1">
? value1
? <elseif?condition="$name eq 2"/>
? value2
? <else />
? value3
? </if>
关于condition里面的判断条件:
?eq或者 equal:等于
?neq 或者notequal:不等于
?gt:大于
?egt:大于等于
?lt:小于
?elt:小于等于
?heq:恒等于
?nheq:不恒等于
模板:
运行:
18、php标签
在tp的模板中,允许直接使用php代码
语法:
1)<php>echo “hello”;</php>
2)<?php echo “think”; ?>
TMPL_DENY_PHP :用于配置模板中是否拒绝使用php代码
模板:
运行:
修改配置文件,禁用第二种php写法
四、模型
1、什么是模型
模型表示企业数据和业务规则
2、定义模型
Lib/Model下
文件命名规则:
表名(首字母大写)Model.class.php
模型内代码:
class 表名(首字母大写)Model extends Model{
}
在tp中,如果没有特殊的业务要求,可以直接使用Model类,而不需要定义子类模型,但推荐使用子类模型(自定义模型)
数据表:
文件:
代码:
我们尝试去实例化这个模型类对象:
运行:
说明:tp中的模型,被实例化的同时会自动创建与数据库连接
3、配置数据库信息
在配置文件config.php中,添加以下信息
再重新运行以上程序:
看到上图,说明配置信息添加成功。
通过上图,可以看出,tp模型被实例化时,会自动解析当前模型对应的数据表的表结构
4、实例化模型对象
我们目前使用的模型主要分两种:
1)自定义模型
GoodsModel
UserModel
2)基础模型
在tp中,实例化模型主要有两种形式:
1)直接实例化
$goods=new GoodsModel();
2)快速实例化
$goods=D(‘Goods’);
tp 中实例化模型的四种方式:
1)直接实例化用户自定义模型
2)快速实例化用户自定义模型
3)直接实例化基础模型
4)快速实例化基础模型
5、CURD操作
?创建操作(Create)
?读取数据(Read)
?更新数据(Update)
?删除数据(Delete)
1)创建操作
$admin=new AdminModel();
$row=array(
‘name’=>‘zhangsan’,
‘age’=>30 );
$admin->add($row);
2)更改操作
$admin=new AdminModel();
$data=array();
$admin->save($data);
3)删除操作
$admin=new AdminModel();
$admin->delete(‘4,5,6’)
4)查询操作
select();
查询多条数据时使用,结果永远是一个二维数组,即使结果只有一条数据
find();
永远返回一条数据,所以返回值是一个一维数组
运行:
6、字段缓存
当实例化模型对象时,会自动将这个对应的表中的字段信息缓存下来
?字段缓存保存在Runtime/Data/_fields/ 目录下面
?只要是不开启调试模式都会生成字段缓存(字段缓存可以单独设置关闭)。
?可以通过设置DB_FIELDS_CACHE 参数来关闭字段自动缓存
?可以在模型类里面手动定义数据表字段的名称,可以避免IO加载的效率开销,在模型类里面添加fields属性即可
7、字段定义
在子类模型中,使用以下属性定义表中所有字段信息
语法:
?protected $fields=array(
‘id’,
‘username’,
‘password’,
‘_pk’=>‘id’,
‘_autoinc’=>true
);
模型:
定义字段时是定义在子类模型中,但如果实例化父类模型,那么程序还会重新解析表结构。
如果使用定义字段功能,那么实例化时必须使用子类模型。
8、创建数据
ThinkPHP可以帮助你快速地创建数据对象,最典型的应用就是自动根据表单数据创建数据对象,这个优势在一个数据表的字段非常之多的情况下尤其明显。
语法:
?从表单中创建数据
$User->create();
?从数组中创建数据
$User->create($data);
控制器:
当对象调用create方法时,这个方法默认会从$_POST获取数据,再将这个数据放在$category对象的data属性中,当对象调用add方法时,如果没有向函数传递参数,那么会自动从这个对象data属性中读取数据,并完成录入。
create方法的本质是从一个数组中创建数据。
如果一个表单以get形式提交数据,我们也想使用创建数据的功能,可以使用
$category->create($_GET);
创建数据功能必须依赖一个条件:
表单中元素的名字必须和数据表中的名字保持一致,但这样一来,会在客户端源文件暴露数据表结构的真实字段名,如何解决?
9、字段映射
ThinkPHP的字段映射功能可以让你在表单中隐藏真正的数据表字段,而不用担心放弃自动创建表单对象的功能
语法:
protected $_map = array(
‘name'?? => ‘username',
‘pwd’ => ‘userpwd’
‘假名’ => ‘真名’
);
模型:
字段映射原理:
$data = $User->parseFieldsMap($data);
可以看出,如果type的值为1,表示将真名元素转为假名元素,如果type的值为0,表示将假名元素转为真名元素
10、表名操作
在一个数据库中,如果部署了多个项目,那么我们可以使用表前缀解决问题
‘DB_PREFIX' =>‘think_’
tp中默认的表前缀是think_
如:数据库表名
我们接下来需要在配置文件config.php中,添加以下选项:
项目就可以正常工作。
tableName:
如:数据表名是sp_categorys,但是这个表对应的模型是 CategoryModel,那么,我不想改动文件名和类的前提下,还想使用这个模型。
trueTableName:
如:所有数据表的表前缀是sp,但某个表没有表前缀,如表名:goods,而不是sp_goods。
在子类模型中,添加trueTableName属性,表示是数据库的真实表名
11、事务处理
在tp中,模型对象使用以下三个方法实现事务处理:
?$User->startTrans() :开启事务
?$User->commit()? :提交事务
?$User->rollback()? :回滚事务
什么情况下使用事务:
要么都成功,要么都失败
程序有一个文件,里面保存上百个人员的信息,我们需要使用php程序对文件中的人员信息入库。
12、ActiveRecord
简称:AR模式
AR模式的核心:
1)将数据表映射到类
2)将字段映射到类属性
3)将数据映射到类对象
class Goods{
private $id;
private $name;
private $content;
public function __set($name,$value){
$this->$name=$value;
}
public function __get($name){
return $this->$name;
}
public function insert(){
$sql=”insert into goods values(null,‘$this->name’,’$this->content’)”;
}
public function fetch($id){
$sql=”select * from goods where id=’$id’”;
$row=$db->query($sql);
$this->id=$row[‘id’];
$this->name=$row[‘name’];
}
}
$goods=new Goods();
$goods->name=’’;
$goods->content=’’;
$goods->insert();
--------------------------------------------------------------------
$goods=new Goods();
$goods->id=8;
$goods->delete();
$goods=new Goods();
$goods->fetch(8);
echo $goods->name;
TP中AR模式
1)增加数据
?$User?=?M("User");?
?$User->name?=?'ThinkPHP';
?$User->email?=?'ThinkPHP@gmail.com';
?$User->add();
2)修改数据
?$User->find(1);?
?$User->name?=?'TOPThink';?
?$User->save();?
3)删除数据
?$User->delete(8);?
4)查询数据
?$User?=?M("User");?
?$User->find(8);
?echo?$User->name;
?echo?$User->email;
TP中AR模式的原理:
我们可以看到,在这几个操作时,直接对对象的属性赋值,如:$category->name=’abc’,但$category对象下并没有这些属性。原因:魔术方法。
下面,我们一起看一下父类Model中的魔术方法:
可以看出,当我们为某个对象的属性进行赋值时,会自动执行__set方法,这个方法将这个传递过来的属性名保存在当前对象的data属性数组中,并赋值
当对对象取值,会自动执行__get方法,首先判断当前对象data属性数组中是否有这个元素,如果有,返回它的值,否则返回null,
综上所述:
我们为对象赋值的属性和值都是存储在当前对象$data属性中.
add方法举例:
可以看出,如果我们之前调用add方法时没有传递参数data,会首先判断data是否为空,如果为空,再判断当前对象下data属性是否不为空,如果不为空,将$this->data属性数组中的值赋值给参数data.
13、联贯操作
?where
?order
?limit
?field
?group
语法:
$对象->方法1()->方法2()->方法n()->select();
以上方法在使用时没有顺序上的要求
但是最后的方法必须是select();
14、统计查询
?count :查询数据总行数
?max :取最大值
?min :取最小值
?avg :平均值
?sum :求和
以上方法与select或find方法平级的方法
五、实用项
1、设置trace信息
1)开启调试模式
2)开启跟踪信息机制
config.php配置文件
2、session和cookie
在tp中,它又封装了一些方法用于操作session和cookie
1)session相关方法
?session('name','value');? :添加一个新的session,并赋值
?$value = session('name'); :获取指定的session的值
?session('name',null); :删除指定的session的值
?session(null); :清空所有session的值
?session('?name'); :判断指定的session是否存在
在tp中,session机制默认是开启的,可以通过更改配置文件来控制
2)cookie的相关方法
cookie('name','value');? :添加一个新的cookie并赋值
cookie('name','value',3600); :添加一个新的cookie并赋值,同时指定有效期
$value = cookie('name'); :获取指定cookie的值
cookie('name',null); :删除指定cookie的值
session案例:
项目登录案例:
在项目中添加公共控制器CommonAction,用于验证session登录,以后,所有需要验证的模块的控制器都继承这个公共控制器。
3、文件载入
1)函数文件
(1)common.php
Common/common.php
文件位置:
文件内容:
引用函数:
如果关闭调试模式,我们发现,在common.php文件中定义的函数会被写入到runtime.php文件中。下次执行时,会直接从runtime.php文件中查找并执行,也就是说,如果函数文件common.php发生改变,用户不会看到最新结果。
(2)config.php
LOAD_EXT_FILE=“user”
文件位置:
文件内容:
配置文件:
我们在Common目录下创建其它函数文件,在程序中,如果直接使用,发现调用了未定义函数,说明Common目录下的文件,除了common.php之外,都不会被自动加载。我们可这样做,修改配置文件,添加配置选项:LOAD_EXT_FILE=’引用文件的列表’,这样就可以程序中直接使用函数了,同时,我们可以看出,使用这个方法加载的函数不会被写入到runtime.php文件中,所以函数的内容发生改变后,用户可以立即看到最新结果。
Common/user.php
文件位置:
程序:
这种方式的好处在于,需要使用什么样的文件,就去载入哪个文件,而不需要每次载入多余的文件。
2)类文件
(1)import(‘ORG.Util.User’);
ORG/Util/User.class.php
文件位置:
控制器:
运行:
(2)import(‘@.Common.User’);
Lib/Common/User.class.php
文件位置:
控制器:
总结:
将自定义类文件放在tp框架中,使用:
import(‘ORG.Util.User’);
将自定义类文件放在项目中,使用:
import (‘@.Common.User’);
4、验证码
在tp框架程序中,有一个文件,如下图所示,Image.class.php,可以帮助我们实现验证码的输出功能
Image类的使用方式:
(1)在用户控制器UserAction中添加一个动作用于显示验证码:
(2)修改模板中的验证码图片加载路径,让路径指向上个控制器中的方法
(3)运行程序,并输入验证码
(4)对用户输入的验证码进行校验,注意,Image类在保存session验证码时使用了md5加密,所以用户输入的验证码在判断时,也需要使用md5加密,再进行比较
同时,Image类也提供了方法可以输出中文验证码
(1)先将simhei.ttf字体库文件从fonts文件夹复制到与Image类同级目录下
(2)创建控制器动作,用于显示中文验证码
(3)显示与验证,与上题相同
5、数据分页
1)在tp中,有一个类:Page.class.php,可以实现数据分页功能
2)具体步骤
?$User?=?D(“User”);
?$count?= $User->count();
?$page?= new Page($count,25);
?$show?= $Page->show();
?$list = $User->limit($Page->firstRow.',.$Page->listRows)->select();
?$this->assign('list',$list);
?$this->assign('page',$show);
?$this->display();
代码:
模板:
运行:
3)可以通过分页对象的setConfig方法改变分页样式
?setConfig
?header
?prev
?next
?first
?last
在setConfig方法中,可以直接修改分页对象的config属性数组
我们可以在分页对象调用show方法之前,通过setConfig修改文字样式。
