前言
TP的手册相当多,其实不必再出这样的贴子,论技术,我也是菜鸟一个,同时也在学习当中。看到论坛上多了不少新朋友,不少在抱怨手册看不懂,那我就姑且抛砖引玉,尝试与新朋友们更简单地、手把手地进入TP的应用中去。讲解过程中有错的地方,大家帮忙指正。
这个系列,初步定下的目标为,从零开始,以TP示例中心中的Form为例进行讲解,以实践为主,理论为辅,将TP的最基本内容逛一遍,至少让我们一起学会如何进行最简单的对数据进行查、增、改、删操作并输出到模板。
由于我们说的是循序渐进,所以我用步骤式来说明,只要一步一步跟着做,相信聪明的你在使用过程中就会明白TP的应用了。
注意:以下的步骤,仅仅是TP灵活的布署方式其中一种,实际开发中可以根据自己的情况去另行设定。至于为什么那样做,我们会在最后再作总结,我觉得先实操然后再进行说明比较容易明白。以下不再重复解释。
一快速开始一个项目
名词解释:
项目:你要开发的系统,称之为项目。
入口文件:你可以理解为这个项目的唯一的一道门,以后所有的操作都会通过这道门去执行处理。不必理会什么意思,你甚至可以先把它看成是index.php就是入口文件
TP: ThinkPHP框架的简称
1 下载TP1.5正式版
2 拟好你的项目名称,我们这里以 Myapp 为项目名称
3 在www根目录下,将TP框架所有文件全部复制过去,文件夹名称是ThinkPHP
4 与ThinkPHP同级新建一个文件夹,起名为 Myapp,也就是项目名称
5 在www根目录下,创建一个PHP文件,起名index.php,这就是入口文件
入口文件index.php代码:
// 定义ThinkPHP路径
define('THINK_PATH','./ThinkPHP');
// 定义项目名称
define('APP_NAME','Myapp');
// 定义项目路径
define('APP_PATH','./Myapp');
// 加载入口文件
require(THINK_PATH.'/ThinkPHP.php');
// 实例化这个项目
$App = new App();
// 执行初始化
$App->run();
?>
就这么简单几行,然后打开浏览器,输入http://127.0.0.1/
一个TP项目就这样构建出来了。你会看到
^_^ Hello,欢迎使用ThinkPHP!
这行字。并自动为你创建好项目的目录。接下来,我们这个项目添砖加瓦。
二简单认识项目里的各个文件夹
名词解释:
Action:模块控制器类,你暂时可以理解为一个Action文件代表着一个应用模块,Action 文件中的每一个方法(function)代表着一个操作,操作分为有输出到模板的操作和只具执行不需要输出的操作。对于有输出的操作,则代表了你的项目中一个展示给用户应用的web 页面。(注意:这不是正统的术语解释)
Model:数据表相对应的Model类,可以理解为一个Model文件对应着你项目数据库的其中一个表。命名关系请参看这里:https://www.doczj.com/doc/8e13035384.html,/Article/10
在添砖加瓦之前,我们有必要认识一下各个文件夹的用途。
打开Myapp文件夹,里面TP已让你很省心地构建了最基本的目录。其中:
Cache文件夹:项目自动生成的模版缓存会出现在这里
Common文件夹:你的项目中要用到的自己写的函数,可以在这个文件夹下创建一个名为common.php文件,在这个文件中书写函数,这些函数可以用在你项目的各个类,同时也可以在模板变量中使用,TP框架会自动加载。
Conf文件夹:项目的运行配置文件config.php将放在这个文件夹里,(还有路由配置,调试配置等,请先忽略)
Data文件夹:TP会把项目的数据库表字段生成到这里,另外。。。那些先不必理会。Lang文件夹:项目的语言设置目录,先不必理会。
Lib文件夹:应用类库目录,在这文件夹内还有两个文件夹:Action和Model,Action目录放置命名为xxxAction.class.php的控制器文件,Model目录放置对应数据库表的命名为xxxModel.class.php的类文件。
Logs文件夹:项目中自动产生的日志文件会存放在这里。暂不必理会。
Temp文件夹:数据缓存目录,存放项目中自动生成的项目运行缓存文件等,以及使用文件方式时的缓存文件等
Tpl文件夹:模板文件目录,内有一个default文件夹,也就是默认的风格
项目生成的目录结构就先简单介绍到这里,下一步我们要简单地对项目进行最基本的配置。三创建数据表,并对项目进行配置,以便连接到数据库。
1 我们这里使用的是Mysql数据库,利用PhpMyadmin新建一个数据库,名称为myapp。
使用示例中心中的sql如下:
CREATE TABLE `think_form` (
`id` smallint(4) unsigned NOT NULL auto_increment,
`title` varchar(255) NOT NULL,
`content` varchar(255) NOT NULL,
`create_time` int(11) unsigned NOT NULL,
`update_time` int(11) unsigned NOT NULL,
`status` tinyint(1) unsigned NOT NULL,
`email` varchar(50) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ;
2 在Conf文件夹内,建立一个config.php文件。这个文件,就是Myapp项目的配置文件。系统会自动加载
config.php文件中的配置是以数组返回方式进行定义,会覆盖TP框架中的common目录下convention.php的默认配置。没有设置的配置,就以默认为准。配置设置可以利用C函数动态改变,暂且不必理会。
而我们连接到数据库的设置也是在这个文件中书写。
config.php代码如下:
if (!defined('THINK_PATH')) exit();
return array(
'DB_TYPE'=>'mysql', // 使用的数据库是mysql
'DB_HOST'=>'localhost',
'DB_NAME'=>'myapp',// 数据库名
'DB_USER'=>'root',
'DB_PWD'=>'123456',// 填写你连接数据库的密码
'DB_PORT'=>'3306',
'DB_PREFIX'=>'think_', // 数据表表名的前缀请参看https://www.doczj.com/doc/8e13035384.html,/Article/10
);
?>
暂时就是这样,后面会再根据需要进一步添加和讲解。
3 在Lib/Model目录下,创建一个文件,命名为FormModel.class.php。命名规则刚才你已看了两次。
这里就不再多说,我们可以看到,数据表名是think_form,由于我们配置了数据表表名的前缀为think_,所以文件的命名直接使用 "不含前缀的数据表表名+Model.class.php"就行了。
在这个文件中书写代码:
class FormModel extends Model {
}
?>
就这样定义一个类名就行了。该类继承了Model类。至于自动验证,自动过滤,自动填充这些,暂且不理会。
4 提前先爽一下吧。再次利用PhpMyAdmin,在该表中插入一些数据
sql如下:
INSERT INTO `think_form` (`id`, `title`, `content`, `create_time`, `update_time`, `status`, `email`) VALUES
(1, '这是测试数据', 'dfdf', 1212724876, 0, 1, 'dddd@https://www.doczj.com/doc/8e13035384.html,');
然后我们打开Myapp/Lib/Action/IndexAction.class.php文件,将里面的内容删掉。改成
下面这样:
class IndexAction extends Action{
public function index(){
$form = D('Form')->findall();
dump ($form);
exit;
}
}
?>
打开浏览器,输入http://127.0.0.1/,看,数据给输出来了。
PHP开发,无非是对数据库使用了逻辑控制的增删改查和使用模板输出数据内容。
通常数据的插入都是通过表单来进行添加。表单提交涉及到页面显示,
所以这一节我们暂时放下对数据库的操作讲解,先来简单学习一下TP的模板引擎的变量输出。
第四节简单了解TP的模板输出
上一章节我们提及到, TP中的每一个xxxAction.class.php文件代表着一个应用模块,此Action中的每一个方法(function)代表着一个操作,操作分为有输出到模板的操作和只具执行不需要输出的操作。
打开Myapp/Lib/Action/IndexAction.class.php文件,我们看看里面的基础代码
class IndexAction extends Action{
public function index(){
}
}
理论知识:
1 在TP开发中,要增加一个应用模块,就在Action文件夹里建立一个类,类的文件命名格式是模块名称+Action.class.php。例如我们这里的应用模块是Index,所以定义文件名为IndexAction.class.php
2 应用模块类的定义要继承框架的Action类。要为这个应用模块添加一个操作,则定义一个以此操作为命名的function.例如上面的index操作。
通常一个应用模块中,会有若干操作(function)需要有与用户交互的页面,这就需要用到模板输出, TP本身已内置了一套具有TP特色的,很强大易扩展但应用非常方便兼简单的模板引擎。
在应有模块中,如果某个操作是需要页面显示的,只要对应在Myapp/Tpl/default/里建立一个文件夹,文件夹以应用模块的名称来命名,然后在这个文件夹下,建立一个以这个function名称来命名的html文件,就可以在这个方法中使用$this->display()方法来直接调用该模板。(当然也可以调用其它模块下的其它模板或显式指定模板文件位置和名称,由于是循序渐进式的学习,就让我们先忽略吧)了解这些理论后,我们先简单实操一下这些知识。
1 在Myapp/Tpl/default/下建立一个文件夹,根据应用模块的名称,我们将这个文件夹命名为Index
2 在Myapp/Tpl/default/Index/下建立一个html文件,根据操作名称,我们命名该文件为index.html
3 打开Myapp/Lib/Action/IndexAction.class.php文件,修改代码为
class IndexAction extends Action{
public function index(){
$value = 'hello,ThinkPHP';
$this->assign('name',$value);
$this->display();
}
}
?>
代码知识要点(摘自手册:ThinkPHP模板指南,此后的知识要点均来自TP官方手册,不再申明)
在Action类里面使用 assign方法对模板变量赋值,无论何种变量类型都统一使用assign 赋值。
$this->assign('name',$value);
// 下面的写法是等效的
$this->name = $value ;
// 模板变量赋值后就需要调用模板文件来输出相关的变量,模板调用通过display方法来实现
$this->display();
4 打开Myapp/Tpl/default/Index/index.html文件,代码为
测试输出: {$name}
代码知识要点:
模板变量使用{$变量名称}这种标签进行输出。
不同的模板变量类型,使用不同的标签,标签可以自行另外定义,暂且不理会。
5 打开浏览器输入地址:http://127.0.0.1/,我们可以看到,定义的模板变量已经输出来了。附加补充知识:
1 如果要同时输出多个模板变量,可以使用下面的方式:
$array = array();
$array['name'] = 'thinkphp';
$array['email'] = 'liu21st@https://www.doczj.com/doc/8e13035384.html,';
$array['phone'] = '12335678';
$this->assign($array);
这样,就可以在模板文件中同时输出name、email和phone三个变量。
2 我们使用上面的变量定义,将整个数组定义为一个模板变量来输出
$array = array();
$array['name'] = 'thinkphp';
$array['email'] = 'liu21st@https://www.doczj.com/doc/8e13035384.html,';
$array['phone'] = '12335678';
$this->assign('array',$array);
$this->display();
在html中,要输出$array['name']的值,代码是
{$https://www.doczj.com/doc/8e13035384.html,} 或 {$array['name']}
3 将这个数组循环输出
3.1 IndexAction.class.php中代码更改如下
class IndexAction extends Action{
public function index(){
$array = array();
$array['name'] = 'thinkphp';
$array['email'] = 'liu21st@https://www.doczj.com/doc/8e13035384.html,';
$array['phone'] = '12335678';
$value = 'hello,ThinkPHP';
$this->assign('array',$array);
$this->assign('name',$value);
$this->display();
}
}
?>
3.2 将Myapp/Tpl/default/Index/index.html代码更改如下:
{$vo}
代码知识要点:
name='array'是指要循环的模板变量是array,id='vo'是指这个数据在模板输出时所使用的名称
对于TP的模板引擎输出先简单了解到这里。
第五节初步了解URL如何访问模块操作
通过前面的学习,我们已大概地明白了应用模块中的操作与模板如何对应。
而这一节将简单讲解如何通过URL来访问操作。由于我们要循序渐进,所以先只介绍下面章节要用到的知识,要想深入学习还请参看官方手册《URL设计和SEO支持》
TP支持四种URL访问方式,默认是智能模式,所以我们就这种模式进行简要说明。
智能模式下的URL基本结构是这样的
http://servername/appName/moduleName/actionName/params
你可以理解为
http:// 服务器地址/ 入口文件位置/ 应用模块名称/具体操作名称/ GET变量参数
解释一下上面文字中所译的URL结构,为什么appname项目名称我将它译成了入口文件位置:通常情况下,我们的入口文件index.php都是放在根目录中,这时项目名称就会被入口文件index.php所替代。在前几节里,我们已知道,一个Action文件就是一个应用模块,而应用模块中的每个方法(function)就是一个具体操作。因此,假如要访问我们实例中的Index 模块下的index操作。地址应该是
http://127.0.0.1/index.php/Index/index
如果入口文件不是在服务器的根目录,而是在myapp目录下,那么入口文件位置就是Myapp/index.php,此时上面的URL访问就相应要换成
http://127.0.0.1/Myapp/index.php/Index/index
这样说理应很清楚了,不过别让这么多index给混乱咯,对应URL的结构去明白每一个index 的函义,同时注意大小写
简单实操:
1 打开Myapp/Lib/Action/IndexAction.class.php文件,在index这个function下再添加一个操作test
class IndexAction extends Action{
public function index(){
$array = array();
$array['name'] = 'thinkphp';
$array['email'] = 'liu21st@https://www.doczj.com/doc/8e13035384.html,';
$array['phone'] = '12335678';
$value = 'hello,ThinkPHP';
$this->assign('array',$array);
$this->assign('name',$value);
$this->display();
}
public function test(){
header("Content-Type:text/html; charset=utf-8");
echo '哈,访问正确!!';
}
} // 类定义end
?>
2 尝试对应URL结构,来访问这个test操作,如果能成功看到echo的文字。则这节我们又
学会了多一点知识。
附加知识点:
去掉URL里面的index.php
要去掉URL里的入口文件index.php,使URL类似这样的形式
http://127.0.0.1/Index/index
可以按官方手册所提供的方法进行如下操作。
1 确认httpd.conf配置文件中加载了mod_rewrite.so模块
2 AllowOverride None 将None改为 All
3 打开Myapp/Conf/config.php文件,在配置的数组中添加一行:'URL_MODEL'=>2,在入口文件所在的同级目录下,新建一个.htaccess文件,内容是
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L]
如果你的服务器环境支持rewrite,使用http://127.0.0.1/Index/index就可以正常访问到Index模块的index操作了。此后我们的学习中用到的URL,都是假定你使用了rewrite 的情况
第六节CURD知识之一C 创建(create)
从这一节开始,我们就要涉及到数据库操作,TP对数据库的操作非常简便,以下是一些基础知识讲解。
名词解析:
CURD:代表数据库四个基本操作:创建:create,更新:update,读取:read,删除:delete 模型对象:即数据对象,你项目里每一个Model类文件都会对应着一个数据表(或者视图),模型与数据表存在一种映射关系。TP约定了命名要遵循一定的规范,如果不符合,则需要根据情况进行额外的相应设置。例如Model类的tableName属性
在第三节时,曾略为提到Model类文件命名,现在再回顾一下这部分的内容:我们之前在数据库中,已建立了一个think_form数据库表,并且在配置文件config.php中,我们定义了数据表的前缀是think_,模型类(Model)文件的命名规则是:不包括前缀的数据库表表名并且首字母大写+Model.class.php所以之前我们为think_form数据表在Myapp/Lib/Model 目录下建立一个文件FormModel.class.php模型类的特殊命名还可以智能识别驼峰式的表命名,假设我们有个是类似think_new_table这样的表可以命名为NewTableModel.class.php。默认配置便可以智能识别自动对应think_new_table表,因此不必修改配置。
开发过程中,只要简单地定义好与数据表对应的模型类(xxxModel.class.php),就可以进行对数据操作了。如何让这个模型支持自动验证,自动填充,自动过滤这些知识,在下面涉及到时会作相应讲解。一般来说,在表中添加数据都是通过表单来建立,为了更直观地学习CURD中的C,我们接下来建立个表单来进行添加数据的操作。
之前我们已在Myapp/Lib/Model/下建立好FormModel.class.php类----模型(M)
同时也在Myapp/Lib/Action/下添加了一个Index应用模块和写下了一个index操作----控
制器(C)并且在Tpl目录下建立了与之对应的模板目录Index及index.html模板文件-------视图(V)MVC模式的开发已体现了出来。tdweb曾简明扼要地概括了TP中这三者的关系,
C的作用,就是从M中取得数据到V,
使用TP以表单提交数据到库,流程和你所了解的表单提交没有什么区别,只是TP简化了数据操作的处理过程。我们在实际操作中体会一下。
先来看看我们所定义的数据表form的字段:
'id',//自动编号
'title',//标题
'content',//内容
'create_time',//创建时间
'update_time'//更新时间
'email',//邮箱
'status',//状态
其中的create_time字段是为了记录数据插入的时间,我们可以利用TP的数据自动填充来处理。
在Model类定义 $_auto 属性,可以完成数据自动处理功能,用来处理默认值和其他系统写入字段。
注意1:该自动填充可能会覆盖表单提交项目。其目的是为了防止表单非法提交字段。
注意2:要使用Model类的create方法创建数据对象的时候才会自动进行表单数据处理。
1 打开Myapp/Lib/Model/FormModel.class.php文件,更改代码为
class FormModel extends Model {
// 自动填充设置
protected $_auto = array(
array('status','1','ADD'),
array('create_time','time','ADD','function'),
);
}
?>
代码知识要点:
Model类的$_auto属性由多个填充因子组成的数组,填充因子定义格式:
array(填充字段,填充内容,填充条件,附加规则)
填充字段:就是需要进行处理的表单字段,这个字段并不一定要是数据库表中的字段,对于表单内的辅助检测字段比如重复密码和验证码也可以处理。
填充条件:ADD | UPDATE | ALL(注意,此是1.5版本说明,1.6已改为1 2 3,后续教程有说明)
当为ADD时,会在新增数据时自动填充,这是默认的处理方式
当为UPDATE时,在更新数据的时候会自动填充
当为ALL时,所有情况下都会进行自动填充
附加规则:附加规则是针对填充内容而言,表示该内容填充的方式,包括function,callback,field,string
对于field使用其它字段进行填充和string直接标示字符串作为值进行填充很好理解。例如上面
array('status','1','ADD'),
就是将状态status字段的值直接以1填充.
下面主要说说function与callback这两个附加规则。
protected $_auto = array(
array('create_time','time','ADD','function'),
);
上面create_time代表了要处理的字段,填充内容是time,附加规则是function使用函数,填充条件是ADD新增时处理,那么整行代码表示对create_time字段在新增的时候使time 函数作为该字段的值进行自动填充。
再看一个function作为附加规则的例子
protected $_auto = array(
array('password','md5','ADD','function'),
);
当使用function作为附加规则时,第二个填充内容就代表了这个因子是一个函数名称,该函数的参数就是代表填充字段的值,比如password的值是123456,则上面的代码会先将这个值使用函数md5('123456'),这样处理后再插入到数据表中去。
对于function(函数)和callback(回调方法)理论是一样的,只不过一个是表示填充内容所写的是函数名,另一个是表示填充内容是类中的方法名。函数可以是PHP5内置函数或你自己所写的函数。而callback是当前模型类所能调用的一个方法。
有关数据填充方面的详细资料,请参看官方使用手册《ThinkPHP数据操作指南》
2 打开Myapp/Tpl/default/Index/index.html文件,我们修改代码将form写进去
在上面代码中,我们简单地建了一个form表单,并将标题统一使用一个模板变量{$title}。action提交到的处理地址是__URL__/add,其中__URL__是一个常量定义,表示当前模块地址,TP模板引擎会自动将这句解释为/index.php/Index/add,常见的模板使用的常量有
__ROOT__ 网站根目录地址
__APP__ 当前项目(入口文件)地址
__URL__ 当前模块地址
__ACTION__ 当前操作地址
__SELF__ 当前 URL 地址
3 设置模板变量 {$title} ,增加add操作方法
打开Myapp/Lib/Action/IndexAction.class.php文件,修改代码如下
class IndexAction extends Action{
public function index() {
$this->assign('title','添加数据');//这里设置了模板变量{$title}
$this->display();
}
// 处理表单数据的方法
function add() {
$Form = D("Form");
if($Form->create()) {
$Form->add();
$this->redirect();
}else{
header("Content-Type:text/html; charset=utf-8");
exit($Form->getError().' [ 返回 ]');
}
}
}//类定义 end
?>
代码知识要点:
模板变量赋值前面的章节已介绍过。这里就不啰嗦了。
我们来看看add方法的代码。
$Form = D("Form");
这里使用了TP的特色单字母函数D,是操作数据库时最常用的TP函数,表示实例化Form 对象,即$Form = new FormModel();D函数的具体代码可以查看ThinkPHP目录内的common/function.php中的片段,它会自动引入Model类,并判断之前如果实例化过这个Model,就不再实例化,若然该Model不存在,就会抛出异常错误,另外,D可以跨项目访问Model,暂且忽略。
$Form->create()
使用Model类的Create方法创建一个Form对象,失败会返回false。
$Form->add(); //add方法会将表单数据进行写入
$this->redirect(); //执行跳转
就这么简单几行代码,便完成了对数据插入的处理。
现在我们可以尝试一下在表单中输入数据进行提交试试了。
基于本学习系列1-4过渡到本节的补充说明
说明1 从这节开始,TP或dev这两个简称指的都是ThinkPHP 1.6版,可以到svn下载。https://www.doczj.com/doc/8e13035384.html,/svn/branches/dev下载后删除原来的ThinkPHP框架文件,将dev同样命名为ThinkPHP,并仍是放置于网站的根目录下。
另外,为了方便需要时可以对实例截图而不引起读者你误解,基于我的网站目录结构,现将Myapp的index.php位置更改到Myapp文件夹下(不再是原来的根目录).
步1:将根目录中的原index.php剪切并粘贴到Myapp文件夹下。更改代码为:
// 定义ThinkPHP路径
define('THINK_PATH','../ThinkPHP');
// 定义项目名称
define('APP_NAME','Myapp');
// 定义项目路径
define('APP_PATH','.');
// 加载框架入口文件
require(THINK_PATH.'/ThinkPHP.php');
// 实例化这个项目
$App = new App();
// 执行初始化
$App->run();
?>
代码补充注释:代码中项目名称其实是可以不必定义的,系统会自动根据当前的目录名定义名称。
步2:将.htaccess文件复制一份粘贴到Myapp目录下。
步3:将Cache目录,Temp目录,Data目录清空。
说明2 第五节中对于URL访问的默认模式
在dev版默认配置中,dispatch即URL调度功能是关闭的,所以在默认模式下,要访问Index 模块的index操作,地址应是:index.php?m=index&a=index,m指的是模块变量(Model),a 指的是操作变量(Action)。
如果要使用类似第五节中的index.php/moduleName/actionName方式,则要在config.php 文件里设置DISPATCH_ON为true;并且,也只有开启了此功能后,URL_MODEL的设置才会有效。
(在上面的章节我们提及过,可以设置URL_MODEL为2来使用rewrite功能去除显示index.php)
所以,现在我们的config.php代码是
if (!defined('THINK_PATH')) exit();
return array(
'DB_TYPE'=>'mysql', // 使用的数据库是mysql
'DB_HOST'=>'localhost',
'DB_NAME'=>'myapp',// 数据库名
'DB_USER'=>'root',
'DB_PWD'=>'123456',// 填写你连接数据库的密码
'DB_PORT'=>'3306',
'DB_PREFIX'=>'think_', // 数据表表名的前缀请参看https://www.doczj.com/doc/8e13035384.html,/Article/10
'DISPATCH_ON'=> true,
'URL_MODEL'=>2,
'TMPL_VAR_IDENTIFY'=>'array',// 模板变量识别留空自动判断 array 数组obj 对象
'DEBUG_MODE'=>true,//开启调试模式
);
?>
代码补充注释:此节之后的内容会涉及到模板输出及数据操作,所以在这里明确设置了模板变量为数组,并开启TP的调试模式。
注意3:第六节 CURD知识之一 C(创建)中的自动填充
dev版的自动填充功能已移到AdvModel类中。要使用此功能,我们需要在Myapp/Lib/Model 类文件中引入该类.
那么再来看看我们所定义的数据表form的字段:
'id',//自动编号
'title',//标题
'content',//内容
'create_time',//创建时间
'update_time'//更新时间
'email',//邮箱
'status',//状态
引用tdweb手记:
如果需要新建数据时自动填入时间戳,只需要设置数据表字段名"create_time",如果需要修改时自动保存时间戳,那么设置数据表字段名为"update_time"。如果你的数据表字段名不是默认的,那么需要指定,例如
protected $autoCreateTimestamps = 'ctime';
protected $autoUpdateTimestamps = 'utime';
故此,让我们打开Myapp/Lib/Model/FormModel.class.php文件,将代码更改为如下:
// 导入AdvModel类
alias_import('AdvModel');
class FormModel extends AdvModel {
/* 如果数据表的创建时间字段不是create_time,需要另外设置成如下方式*/
//protected $autoCreateTimestamps = 'ctime';
// 自动填充设置
protected $_auto = array(
array('status','1'),//自动填充的定义规则请参看第六节内容填充规则有所不同,见附注
);
}
?>
代码补充注释:
注意:dev版的填充条件改为1 新增 2 更新 3 包含1和2,默认为新增。所以定义更方便了.而使用ADD | UPDATE | ALL会无效的(TO流年大哥:TP代码还有一个特色就是函数或方法的命名很符合语言使用习惯,原来的add,update,all很直观,易记,可惜没了)
array('field','填充内容','填充条件','附加规则',[额外参数])
alias_import($alias,$classfile='')快速定义和别名导入
这是新增的函数,我尝试注解一下,不正确请指正。
该函数可以动态设置文件列表导入和直接导入文件,常会用到的文件别名有
'Page' 分页类 Page.class.php',
'ViewModel' 视图模型类 ViewModel.class.php',
'AdvModel' 高级模型类 AdvModel.class.php',
'RelationModel' 关联模型类 RelationModel.class.php',
当要引入已定义别名的文件,我们只要直接在参数中传递别名就行了。
别名可以自行在ThinkPHP/Common/alias.php中扩充。
除了使用已定义的别名外,也可以使用动态指定。
alias_import('zzg',APP_PATH.'/Lib/ORG/zzg.php');
或一次引入多个文件
$ailias=array(
'Abc'=> APP_PATH.'/Lib/ORG/abc.php',
'Efg' => APP_PATH.'/Lib/Other/efg.php',
);
alias_import($ailias);
注:指定文件或别名不存在时会返回false
类似的函数还有
import($class,$baseUrl = '',$ext='.class.php')
由于性能问题,这个方式以后不再支持
这是ThinkPHP内建的类库和文件导入的一个函数,具有缓存和检测机制,相同的文件不会重复导入,冲突时会提示错误。使用这方法时,系统会自动识别导入类库文件的位置:Think 代表TP框架基类库即ThinkPHP/Lib/Think目录
ORG 代表第三方公共类库即ThinkPHP/Lib/ORG目录
@ 代表当前项目类库,例如Import("@.Action.xxxAction") ----即Myapp/Lib/Action/xxxAction.class.php@指的是当前项目名称,这和使用Import("Myapp.Action.xxxAction")是一样的。
TP的约定是Think、ORG等导入的是以系统(TP)基类库为相对起始目录,否则就认为是项目(Myapp)应用类库为起始目录。
注意1 使用时要注意文件名的大小写
注意2 Import会自动将.转换为/,如果文件名中含有.,则要将.改为#才能正常导入。
注意3 导入的类文件后缀默认是.class.php
2 第三方框架类库导入:vendor($class,$baseUrl = '',$ext='.php'),
起始目录统一是ThinkPHP/Vendor 默认后缀是.php
注:vendor也使用了Import函数。因此...
说明3,原来的模板文件index.html保持不变,因为我们已启用了DISPATCH_ON开关。仅
将Myapp/Lib/Action/IndexAction.class.php代码更改如下
class IndexAction extends Action{
public function index()
{
$Form = D("Form")->select(); //也可以D("Form")->findAll()
dump ( $Form );// 输出查询结果
$this->assign('title','添加数据');//定义标题的模板变量
$this->display();// 渲染模板
}
// 插入数据
function add()
{
header("Content-Type:text/html; charset=utf-8");//为了提示时不乱码 $Form = D('Form');//实例化Form模型
$vo = $Form->create();//创建数据对象
if(false === $vo) {
exit($Form->getError().' [ 返回 ]');
}
$rs = $Form->add();//插入数据
if ($rs) {
redirect('/Myapp/',2,'数据添加成功!');
}else{
exit($Form->getError().' [ 返回 ]');
}
}
}//类定义 end
?>
代码补充解释:
select($options=array());为了方便查看数据,index操作中使用到了一个基本查询方法select()方法代替了之前比较流行的findAll(),不传任何参数则是获取全部数据。
我们仍是循序渐进,具体关于查询的方法会在用到的时候陆续一起学习。
dump($var, $echo=true,$label=null, $strict=true)函数。浏览器友好的变量输出。
当只有一个$var参数时,会直接打印这个$var。dump($Form);会输出类似
array(1) {
[0] => array(7) {
["id"] => string(1) "1"
["title"] => string(18) "这是测试数据"
["content"] => string(4) "dfdf"
["create_time"] => string(10) "1212724876"
["update_time"] => string(1) "0"
["status"] => string(1) "1"
["email"] => string(12) "dddd@https://www.doczj.com/doc/8e13035384.html,"
}
}
也可以设置参数
dump($要输出的变量, 是否直接打印0或1,变量说明 , 是否以正规数组形式0,1)
例如:
dump($Form,1,'Form数据',0);
输出类似
Form数据 Array
(
[0] => Array
(
[id] => 1
[title] => 这是测试数据
[content] => dfdf
[create_time] => 1212724876
[update_time] => 0
[status] => 1
[email] => dddd@https://www.doczj.com/doc/8e13035384.html,
)
)
$vo = $Form->create();
创建数据对象但不保存到数据库
模型类的create方法,如果没有设值,则默认是通过表单提交的数据$_POST进行创建。
同时Create方法也支持从其它方式例如数据对象或者数组等来创建,对这方法说法有点不一样,望指正。
由于简洁版并不自动生成数据表data缓存,所以如果你用create()而不给他传递任何值,仅仅依靠$_POST得到值,那么不管你的表单POST什么,程序都会认为是数据库的字段拼入QL,所以,如果你POST过来的数据而数据表里没有这个字段,则会出现添加失败。
但我看到代码里似乎已自动过滤不符合的数据,并测试过添加数据表里没有的字段没有出现添加失败。
redirect('/Myapp/',2,'数据添加成功!');跳转函数。
函数原型:redirect($url,$time=0,$msg='')
看参数就已经很清楚了。
第7 节数据查询(CURD之R)
在上一节实操中,我们已成功插入了多条测试的数据,但是很明显,我们发现其中的邮箱地址一项不符合格式也可以提交,这当然不是我们所希望见到的,这时我们可以利用TP的数据自动验证功能去控制用户输入。
而之前已提交的数据,也可以通过编辑数据将原来错误格式的邮箱地址重新更改为正确的
email,这些处理让我们都放在下一节的数据编辑中一起学习。
在此之前,先来看看TP最基本的数据查询。
TP的查询很人性化地分成单数据返回或多数据返回,视乎自己项目过程中的实际需要,按照这系列教程的学习习惯,我们仍是在实际操作中去了解,以代码来学习,一起动手吧。
1 先将Myapp/Lib/Action/indexAction.class.php代码稍作修改,以方便更直观地查看查询结果。
public function index()
{
$Form = D("Form");
$data = $Form->order('id desc')->select();
$this->assign('data',$data);
$this->assign('title','添加数据');
$this->display();
}
2 在第四节时,我们了解过模板变量的循环输出,现在使用这知识点将对应的模板文件Myapp/Tpl/default/Index/index.html修改如下
h3{color:green;}
.box{width:600px;margin:10px auto;border:1px dashed #e8e8e8;padding:5px;} .submit{height:2em;padding:0 5px;cursor:pointer;}
{//Form表数据循环输出}
-----------由{$vo.email} 发表于:{$vo.create_time|date='Y-m-d',###}
内容:
{$vo.content}
在浏览器中输入http://127.0.0.1/Myapp/,可以看到现
在已将数据显示在模板了
这时我们只要每输入一条数据信息,就会按照id倒序的方式显示在模板上。
现在模板显示已设定好,我们来一起学习查询的各种方法:
先了解一个TP词汇:连贯操作
所谓连贯操作,是TP利用__call方法来实现的一些特殊的Model类方法,可以对数据对象连续调用数个方法(参数)来设定特定的条件,然后执行最终所指定的操作,这类特定方法的命名都很直观易记,主要方法(参数)有
用于查询表达式的
'field'//要查询的字段名
'table'//数据表名称不指定时,默认为当前数据对象所对应的表
'where'//查询条件
'order'// 排序
'limit'//结果限制
'having'//having支持
'group'//group支持
'distinct'//distinct筛选支持
'lazy'//惰性查询支持
用于统计查询的
'count'//统计满足条件的记录个数
'sum'//统计某个字段的总和
'min'//取得某个字段的最小值
'max'//取得某个字段的最大值
'avg'//统计某个字段的平均值
用于动态查询的
getby
获取单条记录:
1 find($options=array());//$options=array()是查询条件表达式。
利用find方法进行查询,会自动加上limit=1来得到指定条件的一条记录。
我们可以在IndexAction.class.php中的index操作进行实际了解。
查询主键为2的数据
//SELECT * FROM `think_form` WHERE id='2' LIMIT 1
$data = $Form->find(2);
dump ( $data );
dump( $Form->getLastSql() );
exit;
代码注释:
1 由于我们这里查询出来的是单条数据,以模板设定的循环输出不合,所以用dump查看,下同。
2 $Form->getLastSql()方法可以输出最后一条查询sql。
查询符合某个特定条件的数据
// SELECT * FROM `think_form` WHERE ( `email` = 'abcdefg' ) LIMIT 1 $where['email'] = 'abcdefg';
$options['where'] = $where;
$data = $Form->find($options);
dump ( $data );
dump( $Form->getLastSql() );
exit;
但是这样未免麻烦了些,这时我们可以使用连贯操作,结果是一样的。不过这样就直观了很多
$where['email'] = 'abcdefg';//多个条件时同样如此设置
$data = $Form->where($where)->find();
dump ( $data );
dump( $Form->getLastSql() );
exit;
2 getField($field,$condition='') 获取一条记录的某个字段的值
//SELECT `email` AS `abcdefg` FROM `think_form` LIMIT 1
$where['email'] = 'abcdefg';
$data = $Form->getField($where);
注意:这里如果我们使用$data = $Form->where($where)->getField();返回的将会是这个条件的id值sql将会是SELECT * FROM `think_form` WHERE ( `email` = 'abcdefg' ) LIMIT 1
3 getFields($field,$condition='',$sepa=' ')获取数据集的个别字段值
$data = $Form->getFields('email');// SELECT `email` FROM `think_form 得出的结果是一个数组,可以指定需要的字段,条件和指定分隔符号
//SELECT id,create_time,email,content FROM `think_form
$data = $Form->getFields('id,create_time,email,content','','||') ;
3 getby字段名('字段值') --动态根据指定字段获取一条数据
$data = $Form->getbyemail('abcdefg');
//SELECT * FROM `think_form` WHERE email='abcdefg' LIMIT 1
获取多条记录
select($options=array()) 或 findAll($options=array())两者是一样的,findAll可以理解为select的别名。
我们先了解一下$option 这参数。$option 参数设定的是查询表达式,不设置时,默认是获取全部数据.
参数支持如下键名
table 指定表名称,可以跨表访问,若不填则是当前DAO
distinct 指定是否只列出不重复数据,如果想列出不重复数据,则为true,不填则无此功能
field 指定要搜索的字段,不填则为*
join 填写join,可以支持数组或者直接使用字符串,如果是字符串,那么只支持LEFT JOIN,如果想使用RIGHT JOIN,那么只能使用数组定义,并且必须写清RIGHT JOIN where 指定查询条件
where可以多说点,功能很多。
首先说最简单的字符串查询,直接执行就OK了。
使用数组指定查询条件
$whereArr=array(
"account"=>"tdweb",
"home"=>"China"
);
$options=array(
"where"=>$whereArr
);
$Dao->select($options);
这样默认是查询SELECT * FROM `test` WHERE ( `account` = 'tdweb' ) AND ( `home` = 'China' )是查询相等条件的。
那如果我想查询like条件怎么办?
解决方法之一是定义LIKE_MATCH_FIELDS配置,这里指明要进行like查询的字段。现在我们稍微改下程序
public function testDb()
{