用新版的thinkphp3.2.3和新版的smarty3.1.29,配置smarty的自定义function插件,这样,在thinkphp的模板中就可以加载自定义的小功能块了。
先作个介绍,smarty的function插件,类似tp的widget插件的功能,只是widget包含了php逻辑处理部分和模板显示部分,而smarty的function插件只包含php逻辑处理部分,smarty插件经过获取数据、处理数据,并返回处理的结果,根据得到的结果,可以在模板中灵活使用这些返回的数据。
widget插件和function插件各有优缺点。
之前我使用的是TP3.0和smarty2.6,也已经在此基础上配置了smarty的function插件,但现在需要使用到新的smarty3.#,所以就研究了一下新版smarty的代码,看看得怎么修改。
先到网上大概了解了一下smarty2和smarty3的区别,了解到原来smarty3是全新编写的,好,先心里有个底,也许配置新版smarty3的function插件跟旧版的原理差不多吧,经过查看了smarty3的代码,确实是这样子的。
在smarty中有一个关于插件的变量:plugins,它的值是插件的路径,在新版smarty3中这个变量改为使用常量了,它是:SMARTY_PLUGINS_DIR,在默认的情况下,SMARTY_PLUGINS_DIR的是smarty工具包下的plugins子目录,所以在默认情况下,smarty可以识别到默认的smarty/plugins/下的所有插件。
所以,如果我们按smarty的编写一个新的自定义插件以后,并把它保存在默认的smarty/plugins/目录下,就可以在模板中使用自定义的function类型的smarty插件了。(但我没有试验)
虽然把自定义插件放在smarty默认的插件位置下,是可以使用了,但这样并不好,因为,smarty是一个公共的模板引擎,它可能同时给多个项目使用,如果多个项目的多个自定义插进都放在smarty默认的、公共的位置,那么以后就很多个插件跟某个项目是毫无关系的,但又不好剔除它,因为可能别的项目正在使用这个看起来跟本项目不相关的插件,到底谁在用积累了一堆function插件中的某一个,那可搞不清楚,最好还是别动它,即使是个垃圾插件。
在使用tp跟smarty配合的过程中,更是这样子,tp框架跟smarty模板引擎都是公用的,尽量让它们保持原来的样子,作最小的改动,而让变化的部分尽量转移到跟具体某个项目有关的地方,这样就可以为各自的项目编写各自的smarty插件。
要作到smarty可以单另识别到某个项目下的function插件,关键就是让smarty识别到插件的存放路径,也就是让smarty的可搜索插件的路径,包括各自项目的专门放插件的位置,即:
原来smarty可以识别插件的路径是:“smarty/plugins/”
现在smarty可以识别插件的路径是:“smarty/plugins/” 和 “A项目/插件目录”
这样一来,smarty在调用自定义插件时,如果在smarty/plugins/没找到某个自定义的插件,就到 A项目/插件目录/
下去查找,如果找到了,就可以使用这个自定义插件,如果没有找到这个自定义插件smarty就会报错。
关键的部分来了,在smarty3中定义了plugins的路径是一个常量,但smarty调用plugins的路径却是一个smarty的私有变量,这个私有变量就是smarty的$this->plugins_dir,具体在smarty3.1.29工具包中的主文件:Smarty.class.php,在59行,定义了
define('SMARTY_PLUGINS_DIR', SMARTY_DIR . 'plugins' . DS);
,在这里定义了smarty插件的路径,相当于:smarty/plugins/
同时,smarty定义了一个私有变量$plugins_dir,并把插件的路径赋值给这个私有变量,以后smarty获取插件的路径,都是获取$this->plugins_dir的值。
在smarty第一次给$this->plugins_dir赋值的地方有两个位置,它们是:
在922行附近:$this->plugins_dir =
array(SMARTY_PLUGINS_DIR);
在940行附近:$this->plugins_dir =
array(SMARTY_PLUGINS_DIR);
可以看的出来,smarty可以分析的插件的路径是一个数组,每一个数组的值就是一个smarty可搜索的插件路径,这样我们就可以在数组中加上一个新的元素,作为smarty可以增加搜索的插件路径就可以了。
在smarty跟TP结合的时候,正好可以利用TP的某些常量,这些TP常量正好跟项目有关,是随着项目配置而变化的,所以我作了以下改动,就可以让smarty分别识别各个项目下的function插件了。
(既然smarty是在两个地方单独赋值给私有变量的,就需要修改两个地方)
原来的:
$this->plugins_dir = array(SMARTY_PLUGINS_DIR);
修改为:
//$this->plugins_dir =
array(SMARTY_PLUGINS_DIR);
$this->plugins_dir = array(SMARTY_PLUGINS_DIR,
COMMON_PATH);
解释说明:
COMMON_PATH 是 ThinkPHP的常量,用来放置某个项目使用的自定义函数的。COMMON_PATH的值是:
项目目录/Common/,如果项目的名称是home,那么自定义的文件就如同如下目录:
home/Common/common.php (默认的函数)
home/Common/function.load_data.php (smarty插件1)
home/Common/function.load_data2.php (smarty插件2)
home/Common/function.load_data3.php (smarty插件3)
=============================
smarty的function插件的使用例子:
比如,以前需要在模板中显示一组产品类别的时候,需要先在控制器的方法中从数据库提取类别数组,再把获取的类别数组赋值给smarty,最后在模板中循环输出类别名称,如果使用了smarty的插件时,就变化为编写一个自定义的插件,从插件中获取产品类别数据,并赋值给smarty,然后在模板中循环输出类别名称,在这个简单例子中,似乎smarty的function插件的作用不大,但在多次使用类似的功能的时候,就可以体现出smarty的function插件的优势了,因为编写了一个比较通用的插件,就可以一次编写,多此使用,而且逻辑思路简洁。
具体表现:
(注:产品类别表的字段有:类别id,父类别id,类别名称,分别是:cat_id , pid , cat_name
)
以前的情况是:
控制器中获取类别数组,并赋值给smarty:
class ProductAction extends Action {
public function lists(){
$arr = M("category")->where("pid=0")->select();
//从数据库获取类别
$this->assign("arr", $arr);
//把类别数组赋值给smarty模板引擎
$this->display();
}
}
在模板中循环类别名称:
{foreach from=$arr item=list}
{$list.cat_name} //循环显示类别名称
{/foreach}
========================
现在,使用smarty的function插件时,是这样写:
在Common/function.load_data.php 文件中编写:
function smarty_function_load_data($params,
&$smarty){
$pid = intval($params['pid']);
$arr =
M("Category")->where("pid='$pid'")->select();
$smarty->assign($params['assign'], $arr);
}
在模板中获取类别function插件的类别数组:
{load_data assign="arr" pid=0}
{if $arr}
{foreach from=$arr item=list}
{$list.cat_name}
{/foreach}
{/if}
==============================
以上的插件可以进一步丰富,使查询类别的条件可变化:
function smarty_function_load_data($params,
&$smarty){
$where = " 1 ";
if(isset($params['where'])){
$where .= " AND ". $params['where'];
}
$arr =
M("Category")->where($where)->select();
$smarty->assign($params['assign'], $arr);
}
模板变成可变化的查询条件:
{load_data assign="arr" where="pid_id=0"}
{if $arr}
{foreach from=$arr item=list}
{$list.cat_name}
{/foreach}
{/if}
===========================
或者变成一个更通用的查询插件:
function smarty_function_load_data($params,
&$smarty){
$sql = $params['sql']
$sql = str_replace("##__", DB_PREFIX, $sql);
$arr = M()->query($sql);
$smarty->assign($params['assign'], $arr);
}
模板修改为:
{load_data assign="arr" sql="SELECT * from ##__category WHERE pid=0
ORDER BY cat_id DESC LIMIT 10"}
{if $arr}
{foreach from=$arr item=list}
{$list.cat_name}
{/foreach}
{/if}
============================
smarty的function插件的更多用途,还等待我们去发现。
顺便说一下,TP配置smarty,
首先把smarty的工具包复制到TP的插件指定的位置,例如:
ThinkPHP/Extend/Vendor/Smarty/Autoloader.php
ThinkPHP/Extend/Vendor/Smarty/debug.tpl
ThinkPHP/Extend/Vendor/Smarty/Smarty.class.php
ThinkPHP/Extend/Vendor/Smarty/SmartyBC.class.php
ThinkPHP/Extend/Vendor/Smarty/plugins/*.*
ThinkPHP/Extend/Vendor/Smarty/sysplugins/*.*
接着在TP的项目配置文件config.php中配置smarty的相关信息:
'TMPL_ENGINE_TYPE' => 'Smarty',
'TMPL_ENGINE_CONFIG' => array( //
另外注意:一旦定义TMPL_ENGINE_CONFIG,必须定义template_dir,compile_dir,cache_dir这三项
'template_dir'=>TMPL_PATH,
'compile_dir'=>CACHE_PATH,
'cache_dir'=>TEMP_PATH ,
'caching' => false, //是否启用缓存
'left_delimiter' => '{',
'right_delimiter' => '}',
),
就以上两步就可以在TP中配置成功smarty。