[关闭]
@a5635268 2016-02-11T21:17:16.000000Z 字数 14858 阅读 2100

TP框架之mvc

源码分析与使用笔记


模型

模型定义

定义数据表模型

http://document.thinkphp.cn/manual_3_2.html#define_model

模型实例化

  1. $New = new \Home\Model\NewModel('blog','think_',$connection);
  2. # ↓↓数据库连接信息
  3. new \Home\Model\NewModel('blog','think_','mysql://root:1234@localhost/demo');
  4. $connection = array(
  5. 'db_type' => 'mysql',
  6. 'db_host' => '127.0.0.1',
  7. 'db_user' => 'root',
  8. 'db_pwd' => '12345',
  9. 'db_port' => 3306,
  10. 'db_name' => 'demo',
  11. );
  12. # 3.23支持分布式部署↓↓
  13. $connection = array(
  14. 'db_type' => 'mysql',
  15. 'db_host' => '192.168.1.2,192.168.1.3',
  16. 'db_user' => 'root',
  17. 'db_pwd' => '12345',
  18. 'db_port' => 3306,
  19. 'db_name' => 'demo',
  20. 'db_charset' => 'utf8',
  21. 'db_deploy_type'=> 1,
  22. 'db_rw_separate'=> true,
  23. 'db_debug' => true,
  24. );
  25. //数据库配置2 在配置文件中定义
  26. 'DB_CONFIG2' => 'mysql://root:1234@localhost:3306/thinkphp',
  27. new \Home\Model\BlogModel('blog','think_','DB_CONFIG2');
  28. D方法还可以支持跨模块调用,需要使用:
  29. //实例化Admin模块的User模型
  30. D('Admin/User');
  31. //实例化Extend扩展命名空间下的Info模型
  32. D('Extend://Editor/Info');
  33. // 使用M方法实例化 操作db_name数据库的ot_user表
  34. $User = M('db_name.User','ot_');
  35. $New = M('new','think_',$connection);
  36. // 等效于 $New = new \Think\Model('new','think_',$connection);

字段定义

连接数据库

http://document.thinkphp.cn/manual_3_2.html#connect_db

切换数据库

可以在查询的时候,临时切换数据库,甚至可以切换到远程的数据库

分布式数据库支持

http://document.thinkphp.cn/manual_3_2.html#distributed_database

连贯

  1. //table: think_user
  2. $Model->table('__USER__')->where('status>1')->select();
  3. //alias
  4. $Model->alias('a')->join('__DEPT__ b ON b.user_id= a.id')->select();
  5. //field
  6. $Model->field(array('user_id','content'),true)->select();
  7. $Model->field('title,email,content')->create();
  8. $Model->field('title,email,content')->save($data);
  9. //page
  10. $Article->page('1,10')->select(); // 查询第一页数据,每页10条
  11. //having 只支持字符串
  12. $this->field('username,max(score)')->group('user_id')->having('count(test_time)>3')->select();
  13. //join
  14. $Model->join('__WORK__ ON __ARTIST__.id = __WORK__.artist_id','RIGHT')->select();
  15. $Model->join('RIGHT JOIN __WORK__ ON __ARTIST__.id = __WORK__.artist_id')->select();
  16. //排重
  17. $Model->distinct(true)->field('name')->select();
  18. //数据缓存
  19. //缓存有效期和缓存类型是由DATA_CACHE_TIME和DATA_CACHE_TYPE配置参数决定的
  20. $Model->where('id=5')->cache(true)->find();
  21. $Model->cache(true,60,'xcache')->find(); //也可以单独设置
  22. $result = $Model->cache('key',60)->find(); //甚至可以指定一个key键到用到的时候取出来;
  23. //直接返回sql
  24. $result = M('User')->fetchSql(true)->find(1);
  25. //关闭表单令牌验证,开启??
  26. $model->token(false)->create();

命名范围

http://document.thinkphp.cn/manual_3_2.html#name_range

也就是TP的查询语言进行封装,封装在自定义模型类属性里面;对于一些比较经常刷的表,可以采用这个方式,的确可以让代码重用度比较高;

CURD操作

数据创建

  1. // Model::MODEL_INSERT(或者1)和Model::MODEL_UPDATE(或者2)
  2. create($_POST,Model::MODEL_UPDATE);
  3. //字段过滤
  4. $User->field('name,email')->create($data);
  5. //在自定义模型类中可以通过以下的方式在规定数据库在新增或者更新的时候需要插入的值
  6. namespace Home\Model;
  7. use Think\Model;
  8. class UserModel extends Model{
  9. protected $insertFields = 'name,email'; // 新增数据的时候允许写入name和email字段
  10. protected $updateFields = 'email'; // 编辑数据的时候只允许写入email字段
  11. }

数据写入

http://document.thinkphp.cn/manual_3_2.html#insert_data

  1. # 有就更新,没有就添加?
  2. add($data='',$options=array(),$replace=false)
  3. # creat后调用add或者save都可以自动识别
  4. $User = M("User"); // 实例化User对象
  5. // 根据表单提交的POST数据创建数据对象
  6. if($User->create()){
  7. $result = $User->add(); // 写入数据到数据库
  8. if($result){
  9. // 如果主键是自动增长型 成功后返回值就是最新插入的值
  10. $insertId = $result;
  11. }
  12. }
  13. # 使用过滤方法对要写入的数据进行过滤
  14. $data['name'] = '<b>thinkphp</b>';
  15. $data['email'] = 'thinkphp@gmail.com';
  16. $User = M('User');
  17. $User->data($data)->filter('strip_tags')->add();
  18. # 可以进行批量写入
  19. $User->addAll($dataList);

数据读取

http://document.thinkphp.cn/manual_3_2.html#read_data

  1. //array(`id`=>`nickname`)
  2. $list = $User->getField('id,nickname');
  3. // 获取id数组集
  4. $User->getField('id',true);
  5. //类似于select()方法的结果遍历将id的值设为数组key
  6. $list = $User->getField('id,nickname,email');
  7. //键名是用户id,键值是 nickname:email的输出字符串。
  8. $list = $User->getField('id,nickname,email',':');

更新数据

http://document.thinkphp.cn/manual_3_2.html#update_data

  1. $User-> where('id=5')->setField('name','ThinkPHP');
  2. $User->where('id=5')->setInc('score',3); // 用户的积分加3
  3. $User->where('id=5')->setInc('score'); // 用户的积分加1
  4. $User->where('id=5')->setDec('score',5); // 用户的积分减5
  5. $User->where('id=5')->setDec('score'); // 用户的积分减1
  6. # 3.23支持延迟更新
  7. $Article->where('id=5')->setInc('view',1,60); // 文章阅读数加1,并且延迟60秒更新(写入)

注意:save方法的返回值是影响的记录数,如果返回false则表示更新出错,因此一定要用恒等来判断是否更新失败。

数据删除

http://document.thinkphp.cn/manual_3_2.html#delete_data

delete方法的返回值是删除的记录数,如果返回值是false则表示SQL出错,返回值如果为0表示没有删除任何数据。

  1. $User->delete('1,2,5'); // 删除主键为1,2和5的用户数据

ActiveRecord

创建

  1. $User = M("User"); // 实例化User对象
  2. // 然后直接给数据对象赋值
  3. $User->name = 'ThinkPHP';
  4. $User->email = 'ThinkPHP@gmail.com';
  5. // 把数据对象添加到数据库
  6. $User->add();
  7. $User = D("User");
  8. $User->create(); // 创建User数据对象,默认通过表单提交的数据进行创建
  9. // 增加或者更改其中的属性
  10. $User->status = 1;
  11. $User->create_time = time();
  12. // 把数据对象添加到数据库
  13. $User->add();

查询

  1. $user = M('user');
  2. $user -> find(1);
  3. $user -> getById(1); //getBy字段名(字段值)
  4. //↑↑以上查询结果是保存在内存里面的,可以通过对象属性的方式取出来;
  5. //注意只有find与getby, 才可以;
  6. echo $user -> username;
  7. // 查找主键为1、3、8的多个数据
  8. $userList = $User->select('1,3,8');

更新

  1. # 先查询再更新
  2. $User->find(1); // 查找主键为1的数据
  3. $User->name = 'TOPThink'; // 修改数据对象
  4. $User->save(); // 保存当前数据对象
  5. # 直接更新
  6. $User->id = 1;
  7. $User->name = 'TOPThink'; // 修改数据对象
  8. $User->save(); // 保存当前数据对象

删除

  1. $User->delete(8); // 删除主键为8的数据
  2. $User->delete('5,6'); // 删除主键为5、6的多个数据

字段映射

http://document.thinkphp.cn/manual_3_2.html#field_map

作用:在表单中隐藏真正的数据表字段的一种安全处理方式,比如在数据表中是username,然后在表单中为name;

查询语言

查询方式

可以支持数组创建where条件

表达式查询

http://document.thinkphp.cn/manual_3_2.html#express_query

  1. # 模糊搜索配置
  2. C('DB_LIKE_FIELDS','nickname|remark');
  3. $where['nickname'] = '周'; //由于配置了DB_LIKE_FIELDS,所以这里的nickname是like模糊搜索
  4. $user -> where($where) -> find();
  5. # 区间查询
  6. $map['id'] = array('between',array('1','8'));
  7. # EXP:表达式
  8. $map['id'] = array('exp',' IN (1,3,8) ');
  9. // exp查询的条件不会被当成字符串,所以后面的查询条件可以使用任何SQL支持的语法,包括使用函数和字段名称。查询表达式不仅可用于查询条件,也可以用于数据更新
  10. $User = M("User"); // 实例化User对象
  11. // 要修改的数据对象属性赋值
  12. $data['name'] = 'ThinkPHP';
  13. $data['score'] = array('exp','score+1');// 用户的积分加1
  14. $User->where('id=5')->save($data); // 根据条件保存修改的数据

快捷查询

http://document.thinkphp.cn/manual_3_2.html#fast_query

  1. # 可读性非常差,不推荐使用
  2. $map['status&score&title'] =array('1',array('gt','0'),'thinkphp','_multi'=>true);

区间查询

http://document.thinkphp.cn/manual_3_2.html#region_query

  1. $map['id'] = array(array('gt',1),array('lt',10)) ; // ( id > 1) AND ( id < 10)
  2. $map['id'] = array(array('gt',3),array('lt',10), 'or') ;
  3. $map['id'] = array(array('neq',6),array('gt',3),'and'); //默认是and
  4. # 区间查询的条件可以支持普通查询的所有表达式
  5. $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')

组合查询

  1. # 字符串模式查询
  2. $User = M("User"); // 实例化User对象
  3. $map['id'] = array('neq',1);
  4. $map['name'] = 'ok';
  5. $map['_string'] = 'status=1 AND score>10';
  6. $User->where($map)->select();
  7. //( `id` != 1 ) AND ( `name` = 'ok' ) AND ( status=1 AND score>10 )
  8. # 请求字符串查询方式
  9. $map['id'] = array('gt','100');
  10. $map['_query'] = 'status=1&score=100&_logic=or';
  11. # 复合查询
  12. $where['name'] = array('like', '%thinkphp%');
  13. $where['title'] = array('like','%thinkphp%');
  14. $where['_logic'] = 'or';
  15. $map['_complex'] = $where;
  16. $map['id'] = array('gt',1);
  17. //( id > 1) AND ( ( name like '%thinkphp%') OR ( title like '%thinkphp%') )
  18. //一个数组一个括弧

统计查询

http://document.thinkphp.cn/manual_3_2.html#stat_query

Count, Max, Min, Avg, Sum

sql查询

http://document.thinkphp.cn/manual_3_2.html#sql_query

  1. # query
  2. // 表前缀处理
  3. $Model->query("select * from __PREFIX__user where status=1");
  4. $Model->query("select * from __USER__ where status=1");//3.22版本
  5. # execute
  6. $Model->execute("update think_user set name='thinkPHP' where status=1");
  7. // 表前缀处理同上

如果当前采用了分布式数据库,并且设置了读写分离的话,以上内部已经实现了读写分离

动态查询

  1. $user = $User->getByName('liu21st');
  2. $userId = $User->getFieldByName('liu21st','id');//表示根据用户的name获取用户的id值。

子查询

  1. // 首先构造子查询SQL
  2. # type 1:
  3. $subQuery = $model->field('id,name')->table('tablename')->group('field')->where($where)->order('status')->select(false);
  4. // type 2:
  5. $subQuery = $model->field('id,name')->table('tablename')->group('field')->where($where)->order('status')->buildSql();
  6. // 利用子查询进行查询
  7. $model->table($subQuery.' a')->where()->order()->select()

自动验证

http://document.thinkphp.cn/manual_3_2.html#auto_validate

array(
     array(验证字段1,验证规则,错误提示,[验证条件,附加规则,验证时间]),
     array(验证字段2,验证规则,错误提示,[验证条件,附加规则,验证时间]),
     ......
);

验证条件 (可选)

验证时间(可选)

  1. protected $_validate = array(
  2. array('verify','require','验证码必须!'), //默认情况下用正则进行验证
  3. array('name','','帐号名称已经存在!',0,'unique',1), // 在新增的时候验证name字段是否唯一
  4. array('value',array(1,2,3),'值的范围不正确!',2,'in'), // 当值不为空的时候判断是否在一个范围内
  5. array('value','checkValue','当前类方法验证',1,'callback'), //当前的类方法验证
  6. array('repassword','password','确认密码不正确',0,'confirm'), // 验证确认密码是否和密码一致
  7. array('password','checkPwd','密码格式不正确',0,'function'), // 自定义函数验证密码格式
  8. );
  1. $User->validate($rules)->create();

自动完成

http://document.thinkphp.cn/manual_3_2.html#auto_operate

参数绑定

http://document.thinkphp.cn/manual_3_2.html#param_bind

模型分层

http://document.thinkphp.cn/manual_3_2.html#multi_model_layer

ThinkPHP支持模型的分层 ,除了Model层之外,我们可以项目的需要设计和创建其他的模型层。

例如在Home模块的设计中需要区分数据层、逻辑层、服务层等不同的模型层,我们可以在模块目录下面创建Model、Logic和Service目录,把对用户表的所有模型操作分成三层:

同样是继承\Think\Model, 只是其名称不同,用于业务逻辑分层处理

虚拟模型

http://document.thinkphp.cn/manual_3_2.html#virtual_model

虚拟模型是指虽然是模型类,但并不会真正的操作数据库的模型;

一般用不到;

视图模型

http://document.thinkphp.cn/manual_3_2.html#view_model

tp的模拟视图,这里的视图与mysql中的视图是两个概念;

  1. namespace Home\Model;
  2. use Think\Model\ViewModel;
  3. class BlogViewModel extends ViewModel {
  4. public $viewFields = array(
  5. 'Blog'=>array('id','name','title'),
  6. 'Category'=>array('title'=>'category_name', '_as' => 'cate', '_on'=>'Blog.category_id=Category.id','_type' => 'left',
  7. 'User'=>array('name'=>'username', '_on'=>'Blog.user_id=User.id'),
  8. );
  9. }
  10. # 获取表名称;
  11. '_table'=>"test_user"
  12. // 3.2.2版本以上还可以使用简化定义(自动获取表前缀)
  13. '_table'=>"__USER__"
  14. # 还可以定义特殊字段
  15. 'Category'=>array('title'=>'category_name','COUNT(Blog.id)'=>'count','_on'=>'Category.id=Blog.category_id')
  16. # 定义完之后可以让其和普通模型一样操作
  17. D("BlogView")->field('id,name,title,category_name,username')->order('id desc')->group('id')->select();

关联模型

http://document.thinkphp.cn/manual_3_2.html#relation_model

高级模型

http://document.thinkphp.cn/manual_3_2.html#adv_model

高级模型提供了更多的查询功能和模型增强功能,利用了模型类的扩展机制实现。

  1. namespace Home\Model;
  2. use Think\Model\AdvModel;
  3. class UserModel extends AdvModel{
  4. }
  1. protected $_filter = array(
  2. '过滤的字段'=>array('写入回调方法','读取回调方法','是否传入整个数据对象(默认为改字段)'),
  3. )
  1. protected $serializeField = array(
  2. 'info' => array('name', 'email', 'address'), //把name,email,address,序列化之后存储到info字段中
  3. );
  4. // 查询的时候,其实可以通过属性值读取出来的;
  5. $User->find(8);
  6. echo $User->name;
  1. protected $readonlyField = array('name', 'email'); //对于一些一旦写入就无法更改的字段

不是很理解,后续通过一个例子来看

返回类型更改

  1. $User = M("User"); // 实例化User对象
  2. // 返回结果是一个数组数据
  3. $data = $User->find(6);
  4. // 返回结果是一个stdClass对象
  5. $data = $User->returnResult($data, "object");
  6. // 还可以返回自定义的类
  7. $data = $User->returnResult($data, "User");
  8. // 是对data数据做了处理,然后再返回的类;
  9. Class User {
  10. public function __construct($data){
  11. // 对$data数据进行处理
  12. }
  13. }

mongo模型

http://document.thinkphp.cn/manual_3_2.html#mongo

  1. $Model = new Think\Model\MongoModel("User");
  2. $Model->field("name,email,age")->order("status desc")->limit("10,8")->select();

视图

模板定义

http://document.thinkphp.cn/manual_3_2.html#template_define

通过配置定义:

模板主题

可以定义多主题模板

http://document.thinkphp.cn/manual_3_2.html#template_theme

模板赋值

渲染模板

http://document.thinkphp.cn/manual_3_2.html#template_display

display('[模板文件]'[,'字符编码'][,'输出类型'])
  1. $this->display('Member:read'); //表示调用Member模块下面的read模板。
  2. $this->display('./Template/Public/menu.html'); //直接渲染指定目录的模板

获取模板地址

http://document.thinkphp.cn/manual_3_2.html#get_template_file

T函数的返回值是一个完整的模板文件名,可以直接用于display和fetch方法进行渲染输出;

很少用到这个东西

获取内容

http://document.thinkphp.cn/manual_3_2.html#template_fetch

  1. # 返回渲染后的内容
  2. $content = $this->fetch('Member:edit');
  3. # 渲染输出
  4. show('渲染内容'[,'字符编码'][,'输出类型'])

模板引擎

http://document.thinkphp.cn/manual_3_2.html#template_engine

  1. 'TMPL_ENGINE_TYPE' =>'PHP' # 支持原生的PHP模板或者其他模板引擎;

变量输出

http://document.thinkphp.cn/manual_3_2.html#var_output

  1. # 可输出对象
  2. {$data:name}
  3. {$data->name}

系统变量

http://document.thinkphp.cn/manual_3_2.html#system_var

  1. # 支持输出 $_SERVER、$_ENV、 $_POST、 $_GET、 $_REQUEST、$_SESSION和 $_COOKIE变量
  2. {$Think.server.script_name}
  3. # 常量输出
  4. {$Think.const.MODULE_NAME}
  5. {$Think.MODULE_NAME}
  6. # 配置输出
  7. {$Think.config.db_charset}
  8. # 语言变量
  9. {$Think.lang.page_error}

使用函数

http://document.thinkphp.cn/manual_3_2.html#use_function

默认值输出

http://document.thinkphp.cn/manual_3_2.html#default_val

使用运算符

http://document.thinkphp.cn/manual_3_2.html#use_operate

标签库

http://document.thinkphp.cn/manual_3_2.html#taglib

  1. # 对于非内置标签库,都要提前导入
  2. <taglib name="html,article" />
  3. # 可以配置内置标签库
  4. 'TAGLIB_BUILD_IN' => 'cx,article'
  5. # 可以预加载标签库
  6. 'TAGLIB_PRE_LOAD' => 'article,html'

模板继承

http://document.thinkphp.cn/manual_3_2.html#template_extend

在父模板中定义一些需要再子模板赋值的block数据块,然后再在子模板中通过extend标签,把这些数据块给到父模板,一般在后台应用中使用;

修改定界符

http://document.thinkphp.cn/manual_3_2.html#modify_edlim

标签和变量的定界符可以修改

三元运算

  1. {$info['status']?$info['msg']:$info['error']}; //三元运算符中暂时不支持点语法。

文件包含

http://document.thinkphp.cn/manual_3_2.html#include

模版表达式的定义规则为:模块@主题/控制器/操作
<include file='模版表达式或者模版文件1,模版表达式或者模版文件2,...' />
  1. <include file="Public/header" /> // 包含头部模版header
  2. <include file="Blue/Public/menu" /> // 包含blue主题下面的menu模版
  3. <include file="./Application/Home/View/default/Public/header.html" /> <include file="Public/header" title="ThinkPHP框架" keywords="开源WEB开发框架" /> // 包含header模板的时候传入了title和keywords变量

内置标签

http://document.thinkphp.cn/manual_3_2.html#compare

原样输出

http://document.thinkphp.cn/manual_3_2.html#literal_output

可以使标签不被解析

模板注释

  1. {/* 注释内容 */ } {// 注释内容 } //注意{和注释标记之间不能有空格。

模板布局

http://document.thinkphp.cn/manual_3_2.html#template_layout

设置了模板布局之后,就是先解析模板布局文件,然后再把display的渲染的模板作为一个特定变量放在布局模板中,这个特定变量可以设置;

通过以下三种方式可以使用模板布局

  1. 'LAYOUT_ON'=>true,
  2. 'LAYOUT_NAME'=>'layout',
  1. <layout name="layout" />

模板替换

在进行模板渲染之前,系统还会对读取的模板内容进行一些特殊字符串替换操作,也就是实现了模板输出的替换和过滤。

__ROOT__: 会替换成当前网站的地址(不含域名) 
__APP__: 会替换成当前应用的URL地址 (不含域名)
__MODULE__:会替换成当前模块的URL地址 (不含域名)
__CONTROLLER__(__或者__URL__ 兼容考虑): 会替换成当前控制器的URL地址(不含域名)
__ACTION__:会替换成当前操作的URL地址 (不含域名)
__SELF__: 会替换成当前的页面URL
__PUBLIC__:会被替换成当前网站的公共目录 通常是 /Public/
  1. # 可以进行以下配置
  2. 'TMPL_PARSE_STRING' =>array(
  3. '__PUBLIC__' => '/Common', // 更改默认的/Public 替换规则
  4. '__JS__' => '/Public/JS/', // 增加新的JS类库路径替换规则
  5. '__UPLOAD__' => '/Uploads', // 增加新的上传路径替换规则
  6. )

控制器

控制器定义

http://document.thinkphp.cn/manual_3_2.html#define_controller

前置和后置操作

http://document.thinkphp.cn/manual_3_2.html#before_after_action

Action参数绑定

http://document.thinkphp.cn/manual_3_2.html#action_bind

url中的查询字符串可以作为方法的参数传进去

我们一般不这样做;

伪静态

可以设置伪静态后缀

http://document.thinkphp.cn/manual_3_2.html#url_suffix

URL大小写

系统本身提供了一个不区分URL大小写的解决方案,可以通过配置简单实现。

其实不建议这么搞;

url生成

http://document.thinkphp.cn/manual_3_2.html#url_build

U('地址表达式',['参数'],['伪静态后缀'],['显示域名'])
地址表达式: [模块/控制器/操作#锚点@域名]?参数1=值1&参数2=值2...
  1. U('Admin/User/select') // 生成Admin模块的User控制器的select操作的URL地址
  2. U('Blog/cate',array('cate_id'=>1,'status'=>1))
  3. U('Blog/cate','cate_id=1&status=1','xml');
  4. # ↓↓ 可以生成路由地址
  5. 'news/:id\d'=>'News/read'
  6. U'/news/1'); // http://serverName/index.php/Home/news/1
  7. # ↓↓ 支持域名
  8. U('Blog/read@blog.thinkphp.cn','id=1');
  9. # ↓↓支持描点;
  10. U('Blog/read#comment?id=1');

AJAX返回

http://document.thinkphp.cn/manual_3_2.html#ajax_return

跳转和重定向

http://document.thinkphp.cn/manual_3_2.html#page_jump_redirect

输入变量

http://document.thinkphp.cn/manual_3_2.html#input_var

请求类型

http://document.thinkphp.cn/manual_3_2.html#request_method

空操作与空控制器

http://document.thinkphp.cn/manual_3_2.html#empty_action
http://document.thinkphp.cn/manual_3_2.html#empty_controller

插件控制器

3.2.2版本开始支持插件控制器的调用

http://document.thinkphp.cn/manual_3_2.html#addon_controller

操作绑定到类

把操作绑定到一个类当中的run方法来运行;

http://document.thinkphp.cn/manual_3_2.html#action_bind_class

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注