1、 目录,自动生成,结构熟悉。
2、 配置(php以数组形式,最好大写)
加载顺序:惯例—应用配置—模块配置—动态配置
惯例配置:convention.php
复制数据库部分到模块config.php覆盖,在控制器中用C函数和dump将配置读取出来可看到,数据库的配置已经添加上去。
读取:$model = C('URL_MODEL');
配置:C('DATA_CACHE_TIME',60);
还可以用LOAD_EXT_CONFIG添加当前模块自定义配置文件。
'LOAD_EXT_CONFIG' => 'user,db',会自动加载相应目录下自定义的user.php和db.php配置文件。
3、 模块化设计
典型URL访问规则:
http://serverName/index.php(或者其他应用入口文件)/模块/控制器/操作/[参数名/参数值...]
Common模块是一个特殊的模块,是应用的公共模块,访问所有的模块之前都会首先加载公共模块下面的配置文件( Conf/config.php )和公共函数文件( Common/function.php )。但Common模块本身不能通过URL直接访问,公共模块的其他文件则可以被其他模块继承或者调用。
自动生成模块目录:
define('BIND_MODULE','Admin');生成Admin模块的目录,并生成一个默认的控制器类 Admin\Controller\IndexController。此时Admin变成默认模块!(绑定了,而且原来的Home访问不了)。已经默认绑定了Index控制器:define('BIND_CONTROLLER','Index');
如果需要生成更多的控制器类,可以定义 BUILD_CONTROLLER_LIST 常量
define('BIND_MODULE','Admin');
define('BUILD_CONTROLLER_LIST','Index,User,Menu');
会生成三个控制器类
Admin\Controller\IndexController
Admin\Controller\UserController
Admin\Controller\MenuController
生成模型类
define('BUILD_MODEL_LIST','User,Menu');
设置访问列表
'MODULE_ALLOW_LIST' =>array('Home','Admin','User'),
'DEFAULT_MODULE' => 'Home',
4、 控制器
继承自Controller,有个public的控制器操作方法。
可以用_before_**和_after_**定义前操作和后操作。
可以定义空控制器EmptyController中的_empty()空方法,作为一些错误处理页面。url为空。
可以绑定到类,要配置ACTION_BIND_CLASS为true。
Action参数绑定,配置'URL_PARAMS_BIND'=> true,URL:
http://serverName/index.php/Home/Blog/read/id/5
有多个参数,顺序无所谓:
http://serverName/index.php/Home/Blog/archive/month/11/year/2013
URL四种模式:URL_MODEL
0普通(问号+参数对,用&连接)
1PathInfo(文件夹路径,默认该模式)
2ReWrite(隐藏应用入口文件)
3兼容(前三种)
U函数可生成模式匹配的URL
redict实现跳转,还有success、error内置的。
success和error方法的第一个参数表示提示信息,第二个参数表示跳转地址,第三个参数是跳转时间(单位为秒)。默认的设置模板都是:
THINK_PATH . 'Tpl/dispatch_jump.tpl',
如果要自定义:'TMPL_ACTION_SUCCESS' => 'Public:success',
public function index(){
$this->success('新增成功', '/TPfull/index.php/Admin/Index/index',3);
}
获取输入变量用I函数进行过滤,安全读入。
echo I('get.name'); // 相当于$_GET['name']
param类型支持自动判断当前请求类型,是I函数默认获取的变量类型,因此事实上param变量类型的写法可以简化为:
I('id'); // 等同于 I('param.id')
I('post.email','',FILTER_VALIDATE_EMAIL);
会对 $_POST['email'] 进行格式验证,如果不符合要求的话,返回空字符串。
5、 视图:
视图目录/[模板主题/]控制器名/操作名+模板后缀,默认的视图目录是模块的View目录
在每个模板主题下面,是以模块下面的控制器名为目录,然后是每个控制器的具体操作模板文件,例如:
User控制器的add操作 对应的模板文件就应该是:./Application/Home/View/User/add.html
修改默认视图层:'DEFAULT_V_LAYER' => 'Template', // 设置默认的视图层名称
设置后缀:'TMPL_TEMPLATE_SUFFIX'=>'.tpl'
一个模块如果需要支持多套模板文件的话,就可以使用模板主题功能。'DEFAULT_THEME' => 'default',模板文件只是多了一层目录。这样,在视图渲染输出之前,我们可以通过动态设置来改变需要使用的模板主题。
$this->theme('blue')->display('add');
如果要在模板中输出变量,必须在在控制器中把变量传递给模板,系统提供了assign方法对模板变量赋值,无论何种变量类型都统一使用assign赋值。
$name = 'ThinkPHP';
$this->assign('name',$name);
$this->display();
赋值后,就可以在模板文件中输出变量了,如果使用的是内置模板的话,就可以这样输出: {$name},注意要有大括号,中间不能有空格。
如果要同时输出多个模板变量,可以使用下面的方式:
$array['name'] = 'thinkphp';
$array['email'] = 'liu21st@gmail.com';
$array['phone'] = '12335678';
$this->assign($array);
在模板文件里面输出了:
{$array.name}或者{$array[‘name’]}
模板渲染:
// 不带任何参数 自动定位当前操作的模板文件
$this->display();//若在index()中,则定位到Index/index.html
如果当前没有启用模板主题则定位到:当前模块/默认视图目录/当前控制器/当前操作.html 如果有启用模板主题则定位到:当前模块/默认视图目录/当前主题/当前控制器/当前操作.html
用的时候根据报错提示新建folder即可。
//表示调用当前控制器下面的edit模板
$this->display('edit');
//表示调用Member控制器下面的read模板
$this->display('Member:read');
T函数的返回值是一个完整的模板文件名,可以直接用于display和fetch方法进行渲染输出。
T('Public/menu');
如果需要获取渲染模板的输出内容而不是直接输出,可以使用fetch方法。
$content = $this->fetch('Member:edit');
使用fetch方法获取渲染内容后,你可以进行过滤和替换等操作,或者用于对输出的复杂需求。
如果你没有定义任何模板文件,或者把模板内容存储到数据库中的话,你就需要使用show方法来渲染输出了,show方法的调用格式:
show('渲染内容'[,'字符编码'][,'输出类型'])例如,$this->show($content);
6、 模型:
继承Model
模型名约定对应数据表(假设数据库的前缀定义是 think_)
UserModel think_user
UserTypeModel think_user_type
如果你的规则和上面的系统约定不符合,那么需要设置Model类的数据表名称属性,以确保能够找到对应的数据表。
根据不同的模型定义,我们有几种实例化模型的方法:
$User = new \Home\Model\UserModel();
当我们实例化的时候没有传入任何的数据库连接信息的时候,系统其实默认会获取配置文件中的相关配置参数,包括:
'DB_TYPE' => '', // 数据库类型
'DB_HOST' => '', // 服务器地址
'DB_NAME' => '', // 数据库名
'DB_USER' => '', // 用户名
'DB_PWD' => '', // 密码
'DB_PORT' => '', // 端口
'DB_PREFIX' => '', // 数据库表前缀
'DB_DSN' => '', // 数据库连接DSN 用于PDO方式
'DB_CHARSET' => 'utf8', // 数据库的编码 默认为utf8
D方法实例化:$User =D('User'); // 相当于 $User = new \Home\Model\UserModel();
$User->select();
参数实例化的模型文件(假设当前模块为Home)
User 对应的模型类文件的\Home\Model\UserModel.class.php
UserType 对应的模型类文件的\Home\Model\UserTypeModel.class.php
D方法还可以支持跨模块调用,需要使用:
//实例化Admin模块的User模型
D('Admin/User');
D方法实例化模型类的时候通常是实例化某个具体的模型类,如果你仅仅是对数据表进行基本的CURD操作的话,使用M方法实例化的话,由于不需要加载具体的模型类,所以性能会更高。
$User = M('User'); $User->select();//和用法 $User =new \Think\Model('User'); 等效
如果你的模型类有自己的业务逻辑,M方法是无法支持的,就算是你已经定义了具体的模型类,M方法实例化的时候是会直接忽略。
如果你仅仅是使用原生SQL查询的话,不需要使用额外的模型类,实例化一个空模型类即可进行操作了:
//实例化空模型
$Model = new Model();
//或者使用M快捷方法是等效的
$Model = M();
//进行原生的SQL查询
$Model->query('SELECT * FROM think_userWHERE status = 1');
系统会在模型首次实例化的时候自动获取数据表的字段信息(而且只需要一次,以后会永久缓存字段信息,除非设置不缓存或者删除),如果是调试模式则不会生成字段缓存文件,则表示每次都会重新获取数据表字段信息。字段缓存保存在 Runtime/Data/_fields/ 目录下面。
数据库连接:
全局配置;
如果在某个模型类里面定义了 connection 属性的话,则实例化该自定义模型的时候会采用定义的数据库连接信息,而不是配置文件中设置的默认连接信息,通常用于某些数据表位于当前数据库连接之外的其它数据库。
//在模型里单独设置数据库连接信息
namespace Home\Model;
use Think\Model;
class UserModel extends Model{
protected $connection = array(
'db_type' => 'mysql',
'db_user' => 'root',
'db_pwd' => '1234',
'db_host' => 'localhost',
'db_port' => '3306',
'db_name' => 'thinkphp',
'db_charset' => 'utf8',
'db_params' => array(), // 非必须
);
}
还可用切换的方式:
//数据库配置1
'DB_CONFIG1' => array(
'db_type' => 'mysql',
'db_user' => 'root',
'db_pwd' => '1234',
'db_host' => 'localhost',
'db_port' => '3306',
'db_name' => 'thinkphp',
'db_charset'=> 'utf8',
),
//数据库配置2
'DB_CONFIG2' =>'mysql://root:1234@localhost:3306/thinkphp#utf8'
namespace Home\Model;
use Think\Model;
class UserModel extends Model{
//调用配置文件中的数据库配置1
protected $connection = 'DB_CONFIG1';
}
链式操作:$User->where('status=1')->order('create_time')->limit(10)->select();
连贯操作的方法调用顺序没有先后。
数组条件的where用法是ThinkPHP推荐的用法。
$User = M("User"); // 实例化User对象
$map['name'] = 'thinkphp';
$map['status'] = 1;
// 把查询条件传入查询方法
$User->where($map)->select();
使用table方法的情况通常是为了:
1. 切换操作的数据表;
2. 对多表进行操作;
$Model->table('think_user')->where('status>1')->select();
data方法也是模型类的连贯操作方法之一,用于设置或读取当前要操作的数据对象的值。
$Model = M('User');
$data['name'] = '流年';
$data['email'] = 'thinkphp@qq.com';
$Model->data($data)->add();
Field用于查询:$Model->field('id,title,content')->select();
相当于SELECT id,title,content FROM table
field方法还有一个非常重要的安全功能--字段合法性检测:
$Model->field('title,email,content')->create();无论用户通过什么手段更改或者添加了浏览
器的提交字段,都会直接屏蔽。
fetchSql用于直接返回SQL而不是执行查询,适用于任何的CURD操作方法。
$result =M('User')->fetchSql(true)->find(1);
输出result结果为: SELECT * FROM think_user where id = 1
四个基本操作(CURD):创建、更新、读取和删除的实现是最基本的,也是必须掌握的
创建:
// 实例化User模型
$User = M('User');
// 根据表单提交的POST数据创建数据对象
$User->create();
也可以:
$data['name'] = 'ThinkPHP';
$data['email'] = 'ThinkPHP@gmail.com';
$User->create($data);
如果没有定义自动验证的话,create方法的返回值是创建完成的数据对象数组。
Create方法创建的数据对象是保存在内存中,并没有实际写入到数据库中,直到使用 add 或者 save 方法才会真正写入数据库。因此在没有调用add或者save方法之前,我们都可以改变create方法创建的数据对象。
$User = M('User');
$User->create(); //创建User数据对象
$User->status = 1; // 设置默认的用户状态
$User->create_time = time(); // 设置用户的创建时间
$User->add(); // 把用户对象写入数据库
数据写入:
$User = M("User"); // 实例化User对象
$data['name'] = 'ThinkPHP';
$data['email'] = 'ThinkPHP@gmail.com';
$User->add($data);
读取数据:
$User = M("User"); // 实例化User对象
// 查找status值为1name值为think的用户数据
$data = $User->where('status=1 ANDname="thinkphp"')->find();
dump($data);
读取数据集:
$User = M("User"); // 实例化User对象
// 查找status值为1的用户数据 以创建时间排序 返回10条数据
$list =$User->where('status=1')->order('create_time')->limit(10)->select();
读取字段值:
$User = M("User"); // 实例化User对象
// 获取ID为3的用户的昵称
$nickname =$User->where('id=3')->getField('nickname');
数据更新:
$User = M("User"); // 实例化User对象
// 要修改的数据对象属性赋值
$data['name'] = 'ThinkPHP';
$data['email'] = 'ThinkPHP@gmail.com';
$User->where('id=5')->save($data); //根据条件更新记录
为了保证数据库的安全,避免出错更新整个数据表,如果没有任何更新条件,数据对象本身也不包含主键字段的话,save方法不会更新任何数据库的记录。
更新字段:
$User = M("User"); // 实例化User对象
// 更改用户的name值
$User->where('id=5')->setField('name','ThinkPHP');
数据删除:
$User = M("User"); // 实例化User对象
$User->where('id=5')->delete(); // 删除id为5的用户数据
$User->delete('1,2,5'); // 删除主键为1,2和5的用户数据
$User->where('status=0')->delete();// 删除所有状态为0的用户数据
ThinkPHP实现了ActiveRecords模式的ORM模型,采用了非标准的ORM模型:表映射到类,记录映射到对象。最大的特点就是使用方便和便于理解(因为采用了对象化),提供了开发的最佳体验,从而达到敏捷开发的目的。(可查,略)
自动验证是ThinkPHP模型层提供的一种数据验证方法,可以在使用create创建数据对象的时候自动进行数据验证。
array(
array(验证字段1,验证规则,错误提示,[验证条件,附加规则,验证时间]),
array(验证字段2,验证规则,错误提示,[验证条件,附加规则,验证时间]),
......
);
静态定义:在模型类里面预先定义好该模型的自动验证规则。
namespace Home\Model;
use Think\Model;
class UserModel extends Model{
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'),// 自定义函数验证密码格式
);
}
定义好验证规则后,就可以在使用create方法创建数据对象的时候自动调用:
$User = D("User"); // 实例化User对象
if (!$User->create()){
// 如果创建失败 表示验证没有通过 输出错误提示信息
exit($User->getError());
}else{
// 验证通过 可以进行其他数据操作
}
如果某一条验证规则没有通过,则会报错,getError方法返回的错误信息(字符串)就是对应字段的验证规则里面的错误提示信息。
如果采用动态验证的方式,就比较灵活,可以根据不同的需要,在操作同一个模型的时候使用不同的验证规则:
$rules = 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'),// 自定义函数验证密码格式
);
$User = M("User"); // 实例化User对象
if(!$User->validate($rules)->create()){
// 如果创建失败 表示验证没有通过 输出错误提示信息
exit($User->getError());
}else{
// 验证通过 可以进行其他数据操作
}
自动完成是ThinkPHP提供用来完成数据自动处理和过滤的方法,使用create方法创建数据对象的时候会自动完成数据处理。因此,在ThinkPHP使用create方法来创建数据对象是更加安全的方式,而不是直接通过add或者save方法实现数据写入。通常用来完成默认字段写入,安全字段过滤以及业务逻辑的自动处理等,和自动验证的定义方式类似,自动完成的定义也支持静态定义和动态定义两种方式。
namespace Home\Model;
use Think\Model;
class UserModel extends Model{
protected $_auto = array (
array('status','1'), // 新增的时候把status字段设置为1
array('password','md5',3,'function') , // 对password字段在新增和编辑的时候使md5函数处理
array('name','getName',3,'callback'), // 对name字段在新增和编辑的时候回调getName方法
array('update_time','time',2,'function'),// 对update_time字段在更新的时候写入当前时间戳
);
}
如果你没有定义任何自动验证规则的话,则不需要判断create方法的返回值:
$User = D("User"); // 实例化User对象
$User->create(); // 生成数据对象
$User->add(); // 新增用户数据
动态:
$rules = array (
array('status','1'), // 新增的时候把status字段设置为1
array('password','md5',3,'function') , // 对password字段在新增和编辑的时候使md5函数处理
array('update_time','time',2,'function'),// 对update_time字段在更新的时候写入当前时间戳
);
$User = M('User');
$User->auto($rules)->create();
$User->add();
虚拟模型是指虽然是模型类,但并不会真正的操作数据库的模型。有些时候,我们建立模型类但又不需要进行数据库操作,仅仅是借助模型类来封装一些业务逻辑,那么可以借助虚拟模型来完成。虚拟模型不会自动连接数据库,因此也不会自动检测数据表和字段信息。
两种方法:
namespace Home\Model;
Class UserModel extends \Think\Model {
Protected $autoCheckFields = false;
}
或不继承:
namespace Home\Model;
Class UserModel {
}
模型分层:
数据层:Home\Model\UserModel 用于定义数据相关的自动验证和自动完成和数据存取接口
逻辑层:Home\Logic\UserLogic 用于定义用户相关的业务逻辑
服务层:Home\Service\UserService 用于定义用户相关的服务接口等