thinkphp 杂乱笔记(1)

部署模式可用两个单入口表示前后台
thinkphp
Uploads
public

Home(前台)
Admin(后台)
index.php(前台入口文件)
admin.php(后台入口文件)
上面两个项目目录


也可以用分组开式,此时简化了一个项目目录
Thinkphp
App(Home/Admin)
public
Uploads
index.php(入口文件)

此时的配置目录为
app/Config/Home/config.php
app/Config/Admin/config.php
还得开启用分组配置文件:
'APP_GROUP_LSIT' => 'Home,Admin',//项目分组设定
'DEFAULT_GROUP' => 'Home', //默认分组


Import('@.Action.UserInfo') // APP_NAME/lib/Action/UserInfo.class.php
Import('@.Model.User'); // APP_NAME/lib/Model/User.class.php
Import(APP_NAME'.Model.UserModel'); // APP_NAME/lib/model/UserModel.class.php

Import('Think.Core.test'); // Thinkphp/lib/Core/test.class.php
Import('ORG.Util.Array'); // Thinkphp/Extend/Library/ORG/Util/Array.class.php
Import('COM.Util.Arr'); // Thinkphp/Extend/Library/COM/Util/Arr.class.php
Import('ORG.Util.Pp#ok'); // Thinkphp/Extend/Library/ORG/Util/Pp.ok.class.php

别名导入
在ThinkPHP/Conf/alias.php中定义 如:
return array(
    'rbac' => LIB_PATH . 'Common/Rabc.class.php',
    'page' => LIB_PATH. 'Common/Page.class.php'
);
则:
import('rabc'); // LIB_PATH . 'Common/Rabc.class.php',
import('page'); // LIB_PATH. 'Common/Page.class.php'

手动载入/其中$baseUrl没有起作用
load($name, $baseUrl='', $ext='.php')方法
load('@.user');// APP_NAME/Common/user.php
@.user表示加载当前项目的user函数文件,这样就可以直接user.php扩展函数库中的函数了

load('user');
表示导入 ThinkPHP/Extend/Function/user.php


导入第三方类库
第三方类库统一放置在系统扩展目录下的Vendor 目录,并且使用vendor 方法导入
Vendor('Zend.Filter.Dir'); // ThinkPHP/Extend/Vendor/Zend/Filter/Dir.php
Vendor('Zend.Filter.Dir', dirname(), '.class.php'); // ThinkPHP/Extend/Vendor/Zend/Filter/Dir.class.php

http://www.localhost/index.php/group/m/a/id/1
http://www.localhost/index.php/m,a,id,1/
URL_PATHINFO_DEPR == '/', ','

定义了项目和分组
ITEM = 'app'
GROUP_LIST = 'admin, home'

config.php
'APP_GROUP_LIST' => 'Home,Admin', //项目分组设定
'DEFAULT_GROUP'  => 'Home', //默认分组

http://localhost/index.php/项目/分组/模块/操作/params
http://localhost/index.php/home/user/read/id/1;无项目名

增加了操作方法添加后缀功能,如
config.php
'ACTION_SUFFIX' => 'Act'
localhost/index.php/m/a/变成了访问里面的 aAct方法了

模块定义:UserAction.class.php
class UserAction extends Action
{
  public function add()
  {
    this->display();//没有赋值,则默认加载模板 Tpl/User/add.html
    this->display('Test/add'); // 则加载 Tpl/Test/add.html
  }
}

空操作:
在控制器中定义 _empty() 方法,当在当前控制器中找不到相关的方法时,会自己调用这个方法
class TestAction extends Action
{
   protected function _empty($name)
   {

   }
}
同理可设置空控制器,当不存在时,就调用 class EmptyAction extends Action{}


URL路由
规则路由
在配置文件 config.php中
'URL_ROUTER_ON' => true,
'URL_ROUTE_RULES' = array(
    'news/:id' => 'News/read',
    'news/read/:id' => '/news/:1'
);
当 localhost/index.php/news/1 会去访问 News模块下的 read方法,并传入参数为id = 1,即
localhsot/index.php/News/read/id/1

当localhost/index.php/news/read/10 会重新定向 localhsot/index.php/read/id/8
正则路由
必须是以"/"开始和结束

URL重写,去index.php,可根据手册即可


URL生成,用U方法
U('[分组/模块/操作]?参数' [,'参数1', '伪静态后缀', '是否跳转', '显示域名']);
U('User/add') // 生成User模块下的 add 操作 URL
U('User/read?id=1') // User 模块下的 read操作,并传入参数 id=1
U('Admin/User/select') // Admin分组下的 User模块 select 操作
第二个参数可以是数组或者是字符串
U('Blog/cate', array('cate_id' => 1, 'status' => 1))
U('Blog/cate', 'cate_id=1&status=1');
U('Blog/cate?cate_id=1&status=1')
以上三个等价

还支持路由功能
如果在模板文件中使用U方法的话,需要用到
{:U('[分组/模块/操作]?参数' [,'参数1', '伪静态后缀', '是否跳转', '显示域名'])}

URL 大小写可配置,让其忽略,用U方法直接自动识别

跨模块调用:
如在 index模块调用 blog模块的 test方法,:
class IndexAction extends Action
{
   public function index()
   {
      $blog = new BlogAction();
      $blog->test();
      //......
   }
}
还可以用A方法来调用:
A('[项目名://][分组/]模块名');
class IndexAction extends Action
{
  public function index()
  {
    $blog = A('Blog');
    $blog->test();
    //....
  }
}
A('User') // 调用当前项目的 User 模块
A('Admin://User') // 调用 Admin项目下的 User模块
A('Admin/User') //Admin分组的 User模块
A('Admin://Tool/User') // Admin 项目 Tool分组下的 User 模块

R表示调用一个模块下的某个操作方法:
R('[项目名://][分组名/]模块名/操作名', array(param1, param2...))

R('User/info', array(15))表示调用 User模块下的 info方法并传入参数 15

页面跳转
成功时:在操作方法中用 $this->success('提示信息', '跳转页面');
失败时:$this->error('fail');可定制,具体看手册


重定向 redirect();
在操作方法中用 $this->redirect('URL', array($params), time, '提示信息');

获取系统变量(可用PHP中的 $_GET,$_POST, $_SESSION, $_COOKIE ...)
也可在 action 中调用如下方法
$this->方法名('变量名'[,过滤方法][,默认值]);
方法名为:_get,_post,_param,_put,_request,_session, _cookie...可看手册
$this->_get('name'); 获取 $_GET['name']的值,同时调用配置文件中默认的过滤方法
$this->_get('id', 'strip_tag', 0); 调用 strip_tags过滤id值,如果没有值,则为0,如果没有设置默认值,则为null.

$this->_get(); 获取全部变量值
$this->_get('name', 'strip_tags, htmlspecialchars', 0);// 先用 strip_tags,再用htmlspecials方法过滤

关闭过滤方法:
$this->_get('name', false); 或者 $this->_get('name', '');

判断请求类型:(GET,POST,PUT,DELETE,HEADE,AJAX)
在Action的操作方法中:
class UserAction extends Action
{
  public function index()
  {
     if($this->isPost()) // 是否为post提交,同时 isGet(),isPut().看手册
     {

     }else
     {

     }

  }
}

获取URL参数
正常情况下.localhost/index.php/User/index/id/1
在UserAction.class.php的index方法中,
$_GET['_URL_'][0] // User
$_GET['_URL_'][1] // Index
$_GET['_URL_'][2] // id
....
也可用
$this->_param(1); // index
$this->_param('id'); // 1


ajax 返回
必须是ajax
调用
$this->ajaxReturn("返回数据", "提示信息", 操作状态 );

Action参数绑定
原理是把URL中的参数(不包括分组,模块,操作)和控制器中的方法参数绑定,URL:
http://serverName/index.php/Blog/read/id/5
http://serverName/index.php/Blog/archive/year/2012/month/03
class BlogAction extends Action
{
  public function read($id = 0)
  {
    // id = 5
    $Blog = M('Blog');
    $Blog->find($id);
  }
 
  public function archive($year=2014, month=07)
  {
        $year = $year; // 2012
    $month = $month; //03
    //.....
  }
}

多层控制器支持
A('User', 'Event'); // Lib/event/UserEvent.class.php
A('User', 'Api') // Lib/Api/UserApi.class.php

模型相关

规则定义:
假设表前缀为:think_
模型名(类名)  对应的表名
UserModel        think_user
UserTypeModel    think_user_type
如果不符合以上规则,要在模型里面定义相关属性
tableName 不包括前缀的表名
trueTableName 包含前缀的表名
dbName 定义模型当前对应的数据库
如:
class UsersModel
{
   protected $tableName = 'user'; // 表示这个模型其实对应的表为 think_user;
}
class UsersModel
{
  protected $dbName = 'db'; // 定义对应的数据库
  protected $trueTableName = 'top_test'; // 表示对应的是 top_test的表
}

模型实例化
可以无需进行任何模型定义,就可以简单使用CURD了,只有当要实现一些业务逻辑封装时才用到
简单的CURD:
实例化User模型
$User = new Model('User');
$User = M('user');
$User->select();


也可以在model中定义一个继承 model的类,实现相应的逻辑(自定义的或是别的公共类)
class UserModel extends Model
{
  //....
}

$user = new UserModel('Admin');
或者 $user = M("UserModel:Admin"[, '表前缀', '配置文件']);

D方法可支持跨项目和分组调用
D('Admin://User'); // 实例化 Admin项目的 User模型
D('Admin/User');   // 实例化 Admin 分组的 User模型

实例化空模型(使用原生态SQL)
$tt = new Model();
或者 $tt = M();
$res = $tt->query("select * from think_test");可支持多表查询
$res = $tt->query("select * form think_test, think_user");

字段定义:
$fields = $User->getDbFields(); // 获取表的所有字段
如果想每次获取的字段不是从表的结构中获取,或者想得到指定的字段,可在 Model中定义
class UserModel extends Model
{
 //此时用 getDbFields()只获取里面指定的这部分
  protected  $fields = array('id, name', '_pk' => 'id', '_autoinc' => true);
  //...
}

获取主键
$model->getPk();

属性访问:可通过数据或对象属性方式
$User = D('User');
$data = $User->find(1);
print_r($data->name); 或者 print_r($data['name']);


跨库操作
class UserModel extends Model
{
  protected $dbName = 'user'; //对应的是 user数据库下的 user表
  protected $tablePrefix = 'other_'; //不同时,定义前缀
}

class Info Model extends Model
{
  protected $dbName = 'info'; //对应的是 info数据库下的 info表
}

进行查询时,会自动处理
$User = D('User');
$User->select(); // select * from user.think_user

如果没有定义模型,用M方法时,可用:
$user = M('user.User', 'other_');

创建数据:
$User = M('User');
//根据表单的 post创建对象,
$User->create();
$User->add();

或者最好用这种,可过滤
$User = M('User');
$data['name'] = 'lin3615';
$data['pwd'] = 'xxx22';
$User->create($data);
$User->add();

或者
$User = M('User');
$data['name'] = 'lin3615';
$data['pwd'] = 'xxx22';
$User->data($data)->add();

字段映射:
可以在表单中隐藏真实的数据表的字段信息,可以直接提交,会自动转换
class UserModel extends Model
{
  protected $_map = array(
    'name' => 'username', // 表单中的 name 字段映射为数据表的字段 username
    'mail' => 'email'  // 表单中的 mail 字段映射为数据表的字段 email
  );
}

用 parseFieldsMap() 方法了可把从数据表的字段映射为指定的别名字段:
$User = M('User');
$data = $User->find(1); // 此时为数据表的真实字段
$data = $User->parseFieldsMap($data); // 即可映射为 name和mail这段

$User->where('status=1')->order(id desc)->limit(10)->select();
当对表单提交的数据时用
$this->_post(); $this->_param();等时,会自己调用系统配置的过滤函数
用$_POST(); $_REQUEST();则不会自动调用过滤函数

自动验证
对表单的字段验证
在 Model类里面定义 $_validate属性,是一个二维数组
array(验证字段,验证规则,错误提示[,验证条件,附加条件,验证时间]);
class TestModel 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'), //自定义函数验证密码格式(checkPwd)
  );
}
当使用系统 create方法时会自动验证
$User = D('User');
if(!$User->create())
{
  //如果验证失败!
  exit($User->getError());
}else
{
  // 通过
}
可以动态改变验证规则
$User = D('User');
$validate = array(array('verify', 'require', '验证码必须')); // 仅仅需要进行验证码的验证
$User->setProperty('_validate', $validate);
$result = $User->create();
if(!$result)
{
  // 失败
   exit($User->getError());
}else
{
   // 成功验证
}

手动验证
$validate = array(array('verify', 'require', '验证码必须'));
$this->validate($validate)->create();

普通单个可用 check('验证数据', '验证规则', '验证类型');
$model->check($value, 'email');
$model->check($value, '1,2,3', 'in');

命名范围:
就是对一连贯操作进行封装,用_scope属性定义,用scope方法调用
class NewsModel extends Model
{
  protected $_scope = array(
   'normal' => array(
            'where' => array('status' => 1),
            ),

   'latest' => array(
        'order' => 'create_time desc',
        'limit' => 10,
    ),
  );
}
$_scope格式化:是一个数组:
'命名范围标识名' => array('属性名'=>'值', '属性名' => '值', ...);
属性名包括:where,field,order,table ....(看手册)
用scope()方法调用
$model->scope('normal')->select;
// select * from think_news where status = 1;

$model->scope('latest')->select();
// select * from think_new order by create_time desc limit 10

可以调用多个命名范围
$model->scope('normal')->scope('latest')->select(); 或者
$model->scope('normal,latest')->select();
$sql = "select * from think_news where status=1 order by create_time desc limit 10";
如果命名范围存在冲突,后面的会覆盖前面的,如果不存在命名范围,则会忽略

默认命名范围
protected $_scope = array(
    'default' => array(),
    );
调用default时,可以不加default
$model->scope()->select()与 $model->scope('default')->select();相同

命名范围调整
$model->scope('normal,latest', array('limit'=>5))->select();
自定义命名范围
$model->scope(array('field'=>'id,title', 'limit'=>5))->select();

连贯操作混合使用
protected $_scope = array(
    'normal' => array(
        'where' => array(),
        'field'=>'id, title',
        'limit' => 10,
    ),
);

自动完成:
在 model类定义 $_auto属性,可自动完成数据处理功能
array('填充字段',填充内容[,填充条件,附加条件]);
class MessageModel extends Model
{
  protected $_auto = array(
      array('status', 1), // 新增时把status字段为1
      array('password', 'md5', 1, 'function'), //对password字段在新增的时候使md5函数处理
      array('name', 'getName',1, 'callback'), // 对name字段在新增的时候回调getName方法
      ....
     );
}
必须调用 create 方法才生效和自动验证一样,当调用 create()时,会自动调用

可以动态设置:
$auto = array(
    array('password', 'md5', 1, 'function'),    
    );
$user->setProperty('_auto', $auto);
$user->create();

还可动态设置规则
$this->auto($auto)->create();

$user = M('User');
$user->where(type=1 and status = 1)->select();
select * from user where type=1 and status = 1;

$User=M('User');
$condition['name'] = 'thinkphp';
$condition['stauts'] = 1;
$condition['_logic'] = 'OR';
$user->where($condition)->select();
select * from user where name='thinkphp' or status = '1';

使用对象方式
$user = M('User');
$condition = new stdClass();
$condition->name = 'thinkphp';
$condition->status = 1;
$User->where($condition)->select();

表达式查询
$map['字段名'] = array('表达式', '查询条件');
表达式: EQ,NEQ,GT,EGT,LT,ELT,LIKE,[NOT]BETWEEN,[NOT]IN, EXP表达式查询,支持SQL语法

$map['id'] = array('eq', 100);和 $map['id'] = 100等效,表示 id = 100
....
表达式查询  EXP
$map['id'] = array('in', '1,2,3');与 $map['id'] = array('exp', 'in(1,2,3)');等效
exp查询的条件不会被当成字符串,所以后面的查询条件可以使用任何SQL支持的语法,包括使用函数和字段名称。查询表达式不仅可用于查询条件,也可以用于数据更新
$User = M();
$data['score'] = array('exp', 'score+1');
$User->where('id=5')->save($data);

快捷查询
$User = M('User');
$map['name|title'] = 'thinkphp';
$User->where($map)->select();
查询条件为 name=thinkphp or title = thinkphp

$user = M();
$map['status&title'] = array(1,'thinkphp', '_multi'=>true);
$user->where($map)->select();
status=1 and title='think'
_multi=>true必须放在最后,能&,|不能同时使用

高级模型
提供更多的查询功能和模型增强功能,但要继承高级的模型或动态模型
class UserModel extends AdvModel
{

}
基础模型类内置有数据自动完成功能,当只有用 create()方法时才生效,用高级模型则不用create(),即可实现
在 Model类中添加 $_filter属性
protected $_filter = array(
    '过滤字段' => array('写入规则', '读取规则',是否传入整个数据对象),
);
其中规则即为一个函数
也可以序列化字段, 用 $serializeField属性
protected $serializeField = array(
    'info' => array('name', 'email', 'address'),    
    );
此时会把 name,email,address的值序列化后保存在 数据表的 info字段中,读取时会自动反序列化
class UserModel extends AdvModel
{
   protected $_filter = array(
    'id' => array('md5', 'md5'),
    );
   protected $serializeField = array(
    'info' => array('name', 'email', 'address'),
    ).    
}

$User = D('User');
$User->name = 'thinkphp';
$User->email = 'ssss@qq.com';
$User->address = 'gd';
$User->add();//自动序列化后保存在数据库

读取时:
$User = D('User');
$data = $User->select()->find(1);
//自动反序列化
$data['name']; //'thinkphp';
$data->['address']; //'gd';

多表查询
$model->table(
'think_blog Blog,
think_category Category,
think_user user')
->field(
 'Blog.id, Blog.name,Blog.title,
 Category.title as category_name,
 User.name as username')
 ->order('Blog.id desc')
 ->where('Blog.category_id=Category.id and Blog.user_id = User.id')
 ->select();
)

可用视图查询实现多表查询功能,得继承 ViewModel模型
class BlogViewModel extends ViewModel
{
  public $viewFields = array(
    'Blog' => array('id', 'name', 'title'), // 表示从 blog中取id,name,title字段
    'Category' => array('title'=>'category_name', '_on'=>'Blog.Category_id = category.id'),//表示category表中的title字段别名为 category_name, 连接条件是Blog.Category_id = category.id
    'User'=>array('name'=>'username', '_on'=>'Blog.user_id = User.id'),
  );
}
如果表名不一致,如 blog对应的为myblog,则在 'blog' => array()中添加项:
'_as' => 'myblog'
SQL语句为:
select Blog.id as id,
blog.name as name,
blog.title as title,
category.title as category_name,
User.name as username from think_blog blog join think_category category
join think_user user
where blog.category_id = category.id and user.id = blog.user_id;

实现视图查询结果时:
$model = D('BlogView');
$model->field('id,name,title,category_name,username')->where('id> 10')->order('id desc')->select();

关联模型:
就是一次在多个表实现CURD
四种关联类型 HAS_ONE, BELONGS_TO, HAS_MANY, MANY_TO_MANY,关联的定义格式:
必须继承 RelationModel类
class UserModel extends RelationModel
{
  protected $_link = array(
    '关联1'=>array(
          '关联属性1' => '定义',
          ....
          '关联属性N'=>'定义',
    ),
    '关联2'=>array(
          '关联属性1' => '定义',
          ....
          '关联属性N'=>'定义',
    ),
    ......
  );
}
如在操作 User表时,同时涉及和操作 record,card这两张表时,假如为一对一的关系,即HAS_ONE:
HAS_ONE关联的属性有:
mapping_type:关联类型,此为 HAS_ONE
class_name:要关联的模型名,如 record,card(分别定义为 class RecordModel extends Model{} ..),即会自动关联到相应的数据表 User(id,name,pwd), record(id, score, userid), card(id, userid, accout)
mapping_name:关联映射名,用于获取数据,如果省略,则用 关联1那个定义来取值
foreign_key:关联外键,此为这个型的键,即 User表中的键
condition:关联条件
mapping_fields:要关联的字段,即这个关联表的字段
as_fields:如果设置了,直接把里面的字段值和User的字段作为同级数据项,不然就是作为下一级数组项
class UserModel extends RelationModel
{
    protected $_link = array(
        'test1' => array(
            'mapping_type' => HAS_ONE,
            'class_name' => 'Record',
            'mapping_name' => 'Record', // 当作为二级数组项时,表示的下标同 User字段同一级别
            'foreign_key' => 'id',
            'condition' => 'id>0',
            'mapping_fields' => 'score',
            'as_fields' => 'score:uus',
            ),
        'Yes' => array(
                'mapping_type' => HAS_ONE,
                'class_name' => 'card',
                'mapping_name' => 'aa',
                'foreign_key' => 'id',
                'mapping_fields' => 'id,accout',
                //'as_fields' =>'id:cardid',
            ),

    );
}
$User = D('User');
$User->relation(true)->select();
以上是 HAS_ONE的查询应用,CURD其实差不多
如增加时
$User = D('User');
$data = array();
$data['user'] = 'xx';
$data['test1'] = array(
            'score' => 100,
        );
//以下的关联下标一定是mapping_name 的值,如果这个没有设,则用 上级的关联名
$data['aa'] = array(
            'id' => '',
            'accout' => '90',
        );

$result = $User->relation(true)->add($data);
BELONGS_TO与MANY_TO_MANY看手册

动态切换模型(如从基础到高级模型,视图模型)
$User = M('User'); // 实例化User对象 是基础模型类的实例
//动态切换到高级模型类
$User->switchModel('Adv')->select();
//动态切换到视图模型类
$User->switchModel('View')->select();

可以写成:
$User->M('AdvModel:User'); // 实例化User对象 是基础模型类的实例
$User->select();

如果要传入参数:
$User = D('User');
// 动态切换到视图模型类 并传入viewFields属性
$UserView = $User->switchModel('View', array('viewFields'));

动态赋值:
$User = M('User');
// 动态切换到关联模型类 并传入data属性
$advUser = $User->switchModel('Relation');
// 或者在切换模型后再动态赋值给新的模型
$advUser->setProperty('_link', $link);
// 查找关联数据
$user = $advUser->relation(true)->find(1);

多层模型支持:
支持自定义分层,但是其中还中继承基类 Model
D("User");//实例化的是 Lib/Model/UserModel.class.php
D('User', 'Logic'); //实例化是 Lib/Logic/UserLogic.class.php
可以配置 DEFAULT_M_LAYER修改模型名(该参数默认值为Model)

视图
默认的模板文件定义规则:
模板目录/[分组名/][模板主题/]模块名/操作名+模板后缀
模板目录默认是项目目录下的Tpl,默认模板主题为空,是为切换多模板矶设计,多模板时,有 DEFAULT_THEME参数中设置默认模板
在每个模板主题下面,是以项目的模块名为目录,然后是每个模块的具体操作模板文件,如:
User模块下的 add操作,对应的模板文件默认就是
Tpl/User/add.html
默认后缀为 .html,可在 TMPL_TEMPLATE_SUFFIX来配置成其他的
如果项目启动了分组功能,如 User模块属于 Home 分组,则默认模板对应是:
Tpl/Home/User/add.html
也可以配置模板目录层次分隔符: TMPL_FILE_DEPR,如 TMPL_FILE_DEPR => '_'
Tpl/Home/User_add.html

模板赋值,用 assign();方法

模板输出:用display();
当前模块其它操作,如当前的edit操作模板;
$this->display('edit'); //不用模板文件路径和后缀

调用其它模块的操作:(Member模块下的read操作模板)
$this->display("Member:read");

display('主题名:模块名:操作名');
如 Xp主题的User模块的edit操作模板
$this->display('Xp:User:edit');

直接全路径输出模板
display('模板文件名');要指定后缀名
如:当前的 Public 目录下面的Menu.html模板文件;
$this->display('./Public/menu.html');

$this->display('Member:read', 'utf-8', 'text/html');

模板替换(看手册)

获取内容:
$this->fetch([模板:操作]);
用法与$this->display();相似,但是其是获取 display();渲染后的模板内容,控制器中来操作

模板引擎
内置和原生的PHP,可在 TMPL_ENGINE_TYPE => 'PHP'以达到最佳的效率

模板引擎:
变量输出(看手册)
{$name}
{$user['username']}  {$user['email']}
{$user->username} {$user->email} {$user.username}
{$user['sub']['name']] // 三级数组

系统变量,(看手册)
{$Think.}以$Think. 开头的,如:
{$Think.server.script_name}

使用函数:
{$varname|function1|function2=arg1,arg2,###}
{$webTtitle|md5|strtoupper|substr=0,3}
编译后:
<?php echo substr(strtoupper(md5($webTitle)), 0, 3); ?>
注意函数的定义和使用顺序的对应关系,通常来说函数的第一个参数就是前面的变量或者前一个函数调用的返回结果,如果你的变量并不是函数的第一个参数,需要使用定位符号
如上面:
md5()的参数是 $webTitle;
strtoupper();的参数是 md5($webTitle);
substr();参数是 strtoupper(md5($webTitle));

{$create_time|date="Y-m-d", ###}
date的第二个变量才是函数的参数,则用 ###表示,则编译后为:
<?php echo date('Y-m-d', $create_time); ?>
还提供了在模板文件中直接使用PHP文件定义的函数方法
格式:{:function(...)}
{:U('User/insert')} ==> <?php echo U('User/insert'); ?>
还可以执行函数,但不输出
格式:{~function(..)}
{~say_hell('tp')} ==> <?php say_hell('tp'); ?>

默认值输出,当不存在时就会输出默认值
{$变量|default="默认值"}
{$lin|default="hi,lin3615"}当$lin没有值时,则输出 hi,lin3615

使用用运算符:
+ {$a+$b}
- {$a-$b}
....
综合运算 {$a+$b*10/5+$c-$d}
不支持点法和常规函数用法
{$user['score']+10}
{$user['score']*$user['score']}

内置标签(看手册)

包含文件(include)
可以使用Include标签来包含外部的模板文件,
文件名要用完整的,相对项目根目录
<include file="完整模板文件名" />
<include file="./Tpl/Public/header.html" />

<include file="操作名" />
<include file="read" />
相当于包含于同一模块下的read操作中的模板,如:
class UserAction extends Action
{
  public function index()
  {

  }

  public function read()
  {
    $this->display();
  }
}
<include file="read" />
此时相当于包含 Tpl/User/read.html

<include file="模块名:操作名" />都是相对的模板模块
<include file="Blog:read" />
即为 Tpl/Blog/read.html

包含其它模板主题的模块操作模板
<include file="主题名:模块名:操作名" />
<include file="blue:User:read" />

也可用变量
<include file="$tplName" />

也可传递变量
<include file="read" title="this is title" keyword="keyword..." />
read.html代码
[title]
[keyword]
可被替换

可引入多个文件
<include file="file1, file2" />

导入文件:
<import type="js" file="js" />
<import type="css" file="stysheet" />
type:默认值为 js.还可以是css
此时相当于(根目录)
<script type="text/javascript" src="Public/js.js"></script>
<import type="js" file="js" basepath="./Common/javascript" />
相对于
<script type="text/javascript" src="./Common/javascript/js.js"></script>

load标签导入 js/css文件
<load href="Public/js/js.js" />
<load href="Public/css/style.css" />
自动识别,直接根目录
<js href="Public/js.js" />
相当于
<script type="text/javascript" src="Public/js/js.js"></script>

<css href="Public/style.css" />
相当于
<link rel="stylesheet" type="text/css" href="Public/style.css" />

Volist标签主要用于在模板中循环输出数据集或者多维数组。(看手册)
<Volist name="list" id="vo" offset="5" length="10" key="i" mod="5" empty="不存在">
   {$vo.name}
   {$vo.id}
   <eq name="mod" value="4"></eq>
</Volist>

foreach标签 也是用于循环输出
<foreach name="list" item="vo" key="i">
{$vo.name}
</foreach>

For标签用于实现for循环
<for start="开始值" end="结束值" comparison="" step="" name="">

</for>

<for start="1" end="100">
{$i]
</for>
相当于
for($i=1; $i < 100; $i++)
{
   echo $i;
}

switch标签:
<switch name="变量">
  <case value="" break="0或1">输出内容</case>
  <case value="">输出内容2</case>
  <default />内容
</switch>

比较标签(eq,equal,notequal,neq,gt,lt,....)
<比较标签 name="变量" value="值">内容</比较标签>
<eq name="name" value="value">value</eq>
<equal name="name" value="value">value</equal>

<eq name="name" value="value">相等<else />不相等</eq>

<compare name="name" value="5" type="eq">value</compare>

三元运算
{$status ? 'yes' : 'no'}

范围标签
<in name="id" value="1,2,3">xxx</in>
<notin name="id" value="1,2,3">yyy</notin>
<between name="id" value="1,2">xxx</between>// 其中value只有是两个值之间
<notbetween name="id" value="1,10">aaaaa</notbetween>

<range name="id" value="1,2,3" type="in"></range>

present 标签,判断是否赋值
<present name="name">name已经赋值</present>
<notpresent name="name">name还没有赋值</notpresent>

empty标签,判断是否为空,同理defined
<empty name="name">name为空</empty>
<notempty name="name">name不为空</notempty>

Define 标签,进行常量定义
<define name="LIN" value="3615" />
在运行模板的时候 定义了一个LIN的常量

assign标签赋值
<assign name="var" value="lin3615" />
在运行模板的时候 赋值了一个var的变量,值是lin3615

if标签,条件判断,不能用传统的 <,>=,!=...
<if condition="($name eq 1) or ($name gt 100)">
xx
<else if condition="$name eq 2" />
222
<else />
ssss
</if>

标签嵌套,一般的标签都可以嵌套,默认嵌套时最多为三级,通过TAG_NESTED_LEVEL配置参数设置嵌套级别

使用php代码,在里面的非PHP标签不起作用
php标签
<php>
echo 'hi, lin3615';
</php>
原生态 php
<?php echo 'hi,lin3615';?>
如果设置了TMPL_DENY_PHP参数为true,就不能在模板中使用原生的PHP代码,但是仍然支持PHP标签输出

模板布局
其实就是把相应的内容放在模板里面作渲染输出(只输出模板里面的)
两种布局模板
第一种方式是 以布局模板为入口的方式
该方式需要配置开启LAYOUT_ON 参数(默认不开启),并且设置布局入口文件名LAYOUT_NAME(默认为layout)。
class UserAction extends Action
{
  public function add()
  {
    $this->display('add');
  }
}
在不开启LAYOUT_ON布局模板之前,会直接渲染Tpl/User/add.html 模板文件,开启之后,把add.html内容会渲染Tpl/layout.html 模板中,并把layout.html中的{__CONTENT__}替换为add.html中的内容
layout.html
其它内容(如引入头部内容,样式表....)
{__CONTENT__}

如果不需要使用布局模板,可在模板文件add.html中包含 {__NOLAYOUT__}即可

第二种方式是以当前输出模板为入口的方式
这种方式的入口还是在User/add.html 模板,但是我们可以修改下add模板文件的内容,在头部增加下面的布局标签:
<layout name="layout" />
layout.html中的内容与第一种的内容一样

模板继承
其实就是定义一个基础模板(或是布局),相关内容用<block>标签来区分,每个区块由<block name=""></block>组成,name属性一定要唯一
如定义一个基础的模板:
base.html
<block name="title"><title>the header</title></block>
............
<block name="jsfiel"><include file="js.js" /></block>

在index.html中引用上面的块时(用到继承):
<extend name="base" />
<block name="title"><title>{$title}</title></block>
<block name="jsfile"></block>

literal标签:原样输出(防止模板解析)
<literal>
    <if condition="" >
    sssss
    </if>
</literal>

<php><literal><if condition=""></if></literal></php>

模板注释
格式:{/* 注释内容 */} 或 {// 注释内容}

避免JS混淆(即解析)
1.{}在分隔符之间留空格
2.<literal>JS代码</literal>
3.修改默认分隔符

原文地址:https://www.cnblogs.com/lin3615/p/3172788.html