标签:smarty

浏览模式: 标准 | 列表 | 图文
Yii2-smarty的一些小坑

Yii2-smarty的一些小坑

在写本文前我不得不说一句,其实我是不想用smarty的,我想尝试一下twig,但是phpstorm的Twig插件真要命,卡成翔,所以我只能用smarty。为什么不用prado了呢?官方说不支持了,我晶啊

在使用smarty的时候官方的代码和例子看上去很美,不过要注意几点

1、用yii2-smarty,还是必须得用layout,如果你不支持layout文件,默认就是/layouts/main.php,天啊,为什么是PHP?而且在这里面也还真的能用PHP代码。整个都崩溃了

2、你可以指定layout文件,比如:main.tpl,OK你必须得象PHP文件一样,得写{$this->head()},{$this->startBody()}{$this->endPage()}等,否则 ClientScript功能就无法使用

3、如果你指定layout=false,那么,就不支持ClientScript了。因为你incude file='xxx.tpl',在每一个独立的文件里都必须要象2中一个个的this->head(),this->endPage全写上

4、再来一个bug:{registerJsFile url=''},这个函数有BUG

原来是:

public function functionRegisterJsFile($params, $template)
{
if (!isset($params['url'])) {
trigger_error("registerJsFile: missing 'url' parameter");
}

$url = ArrayHelper::remove($params, 'url');
$key = ArrayHelper::remove($params, 'key', null);
$depends = ArrayHelper::remove($params, 'depends', null);
if (isset($params['position']))
$params['position'] = $this->getViewConstVal($params['position'], View::POS_END);

Yii::$app->getView()->registerJsFile($url, $depends, $params, $key);
}

改成为:

/**
* Smarty function plugin
* Usage is the following:
*
* {registerJsFile url='http://maps.google.com/maps/api/js?sensor=false' position='POS_END'}
*
* Supported attributes: url, key, depends, position and valid HTML attributes for the script tag.
* Refer to Yii documentation for details.
* The position attribute is passed as text without the class prefix.
* Default is 'POS_END'.
*
* @param $params
* @param \Smarty_Internal_Template $template
* @return string
* @note Even though this method is public it should not be called directly.
*/
public function functionRegisterJsFile($params, $template)
{
if (!isset($params['url'])) {
trigger_error("registerJsFile: missing 'url' parameter");
}

$url = ArrayHelper::remove($params, 'url');
$key = ArrayHelper::remove($params, 'key', null);
$params['depends'] = ArrayHelper::remove($params, 'depends', null);
if (isset($params['position']))
$params['position'] = $this->getViewConstVal($params['position'], View::POS_END);

Yii::$app->getView()->registerJsFile($url, $params, $key);
}

其实就是$params['depends']这个参数。registerJsFile只能接受3个参数,但事实上用了4个参数,所以调整一下即可

using zf and smarty

using zf and smarty

使用zend framework开发时,可以采用第三方模版,比如smarty,在网上找了很多资料,一般来说是两种

1、扩展view

2、使用Zend_Registry,在初始化的时候加载smarty,然后在输出的时候使用Zend_Registry::get('smarty')->display();

使用第二种方式的话,我当然是没有什么说的了。我这里说的是使用第一种方案。

在第一种方案中,官方有例子,页面地址为:http://framework.zend.com/manual/en/zend.view.scripts.html,写上一个类,调用Zend_View_Interface,写上相同的函数就可以了。。

官方有源码,我这里就不贴了。我把官方的例子写一下:

//Example 1. In initView() of initializer.
$view = new Zend_View_Smarty('/path/to/templates');
$viewRenderer =
new Zend_Controller_Action_HelperBroker::getStaticHelper('ViewRenderer'); //使用此例子时,请将new去掉,静态方法不需要new
$viewRenderer->setView($view)
->setViewBasePathSpec($view->_smarty->template_dir)
->setViewScriptPathSpec(':controller/:action.:suffix')
->setViewScriptPathNoControllerSpec(':action.:suffix')
->setViewSuffix('tpl');

//Example 2. Usage in action controller remains the same...
class FooController extends Zend_Controller_Action
{
public function barAction()
{
$this->view->book = 'Zend PHP 5 Certification Study Guide';
$this->view->author = 'Davey Shafik and Ben Ramsey'
}
}

//Example 3. Initializing view in action controller
class FooController extends Zend_Controller_Action
{
public function init()
{
$this->view = new Zend_View_Smarty('/path/to/templates');
$viewRenderer = $this->_helper->getHelper('viewRenderer');
$viewRenderer->setView($this->view)
->setViewBasePathSpec($view->_smarty->template_dir)
->setViewScriptPathSpec(':controller/:action.:suffix')
->setViewScriptPathNoControllerSpec(':action.:suffix')
->setViewSuffix('tpl');
}

以上是官方的example。不过,如果按第一个例子测试,是会出错的。。。

请看第4行。。。静态方法居然用了new。(应该是粗心吧。不过我昨天是直接复制的,死活报错,也没有仔细看,丢人啊)写这篇 文章,主要也就是提醒一下,这个例子有点问题。

顺便说一下,由于官方的例子里,是把$_smarty写成了protected,那么,其实在外面是不能够被直接引用的。要么写一个__get方法,要么,把属性改为public吧

不过,在使用smarty后,你会发现,你原来的layout功能不能完全使用了,为什么呢?因为,在原来的layout里面,代码都是类似于这样:

<?php
$this->layout()->title;
?>

大致是这样的代码,这个,可不能用在smarty中。虽然在smarty中也可以用标签来调用PHP代码,但这毕竟不是一个好办法。

不过还好,又有牛人写了一个很牛叉的例子。LOOK:http://anders.tyckr.com/2008/03/12/implementing-zend-layout-and-smarty-using-zend-framework-mvc/,不过这个例子我还没有全部看完,先贴上来。以后慢慢看,应该会用在项目中吧?

不然,我就用不了layout了,除非我放弃这个东西。。哈哈

TP1.5版本中使用smarty模版引擎的技巧

TP1.5版本中使用smarty模版引擎的技巧

从TP1.5开始,对于其他的模版引擎有了原生支持(不再是以前那种插件机制了)。
本文以使用smarty模版为例作点简单介绍,其他的,可以参考一下View.class.php中的fetch方法可知。

TP的SVN中已经含有smarty模版库,因此当你要使用的时候,只需要在项目的config.php里作一点简单的配置:

'TMPL_ENGINE_TYPE' => 'smarty', //这个是设置引擎为smarty


从2009-01-07下午的SVN版本里,流年为又增加了一个TMPL_ENGINE_CONFIG这个数组,即:

'TMPL_ENGINE_CONFIG' = array(
'template_dir' => TMPL_PATH , //这个就是tpl目录了
'compile_dir' => CACHE_PATH . "tplCompile/", //这是我自己设定的,模版编译缓存放在这个目录里
'cache_dir' => CACHE_PATH . "tplCache/", //如果需要生成页面缓存,这个也是必须的
'left_delimiter' => '{',
'right_delimiter' => '}',
'caching' => false,
'force_compile' => true,
'compile_check' => true,
),


备注:如果按照我这样的写法,请到cache目录里手动创建tplCompile和tplCache两个目录,否则程序会报错。
报错信息大致为:

Catchable fatal error: Object of class Smarty could not be converted to string in D:\local\htdocs\ThinkPHP\Album\Temp\~runtime.php on line 145


如果出现这样的报错信息,请先检查这两个目录是否存在

在项目开发的时候,caching 最好设为false,否则你根本看不到效果。

如此设定完毕后,你就可以直接在项目中使用了,下面以Index模块的index方法进行举例:在IndexAction.class.php的index的方法里

$this->assign("test" , "This is a test string");
$this->display();

然后到模版里:

{$test}

就可以看到输出了。不过,这里需要注意的是,如果你$this->display()没有指定文件名,那么默认的模版文件就是default/Index/index.html,这点和原先使用TP默认的模版引擎没有什么区别。
出现问题最大的应该是在include方法里,include的使用方法是:{include file="Public/header.html"},就象我前面所说,smarty的模版路径只指到了tpl目录,但实际上,我们是在默认的default目录下操作,因此正确的写法应该是{include file="default/Public/header.html"}
如果我们写的程序要对应多模版,那么,上面那种直接写死default的方法是不行的,还好,TP为我们留了一个常量:TEMPLATE_NAME,于是我们的写法就可以是现在这样:

{include file="`$smarty.const.TEMPLATE_NAME`/Public/header.html"}

现在试一下,是否公用目录里的header.html被加载了?

最后再报一个warning。如果是在WINDOWS下面开发并且开启了DEBUG_MODE,那么你在读取模版的时候,页面的Trace信息里,偶尔会出现一个注意:

[ 09-01-08 14:36:02 ] 注意:[2] unlink(./Cache/tplCompile/\%%70^706^706C3AFE%%index.html.php) [function.unlink]: No such file or directory core.write_file.php 第 44 行.


这些信息,可以被忽略掉。模版文件还是会正常的生成和编译的。它只会在第一次生成模版编译文件的时候出现

smarty3即将出来

smarty3即将出来

PHP的模版里,smarty一直就是让人又爱又恨的,功能太强大了,以致于美工们看到他也会感觉头疼,毕竟是又要学一门新的语言了。
这么多年,smarty都是在2.x版本里面徘徊,如今,终于要出3了。
以下是官方的change log:

10/6/2008

- completed compilation of {include} tag, variable scoping same as in smarty2

- added compilation of {capture} tag.

- added error message on none existing template files.

10/4/2008
- added comments in the parser definition y file.

- added array of $smarty_token_names to lexer for use in trigger_template_error function

- change handling of none smarty2 style tags like {if}, {for}....

- lexer/parser optimization

10/3/2008

- create different compiled template files depending if caching and/or security is enabled

- cleaned up compiler

- lexer/parser optimization

10/2/2008

- new method trigger fatal error, displays massage and terminates smarty

- compile error status flag added
The compiler will in case of error continue to parse the template(s) to display all errors. No compiled
templates will be written, Smarty terminates after the compiler exits.

- added error message to function __call in Smarty.class.php
smarty中的注释

smarty中的注释

写代码的时候不可避免的会使用到注释。大多数的情况下,我们都是使用<!-- 这里是注释 -->,因为这是HTML自带的注释功能,在这里的代码都不会被显示到浏览器。

然而,使用了smarty之类,我们确实不是很建议这样使用,因为,在<!---->标记里的smarty代码其实还是被解析了,如果是这样的话,那么,我们其实是多做了很多事情,却没有被显示出来,那就是说,我们其实多做了很多无用功。

因此,我们在使用smarty模版的时候,应该根据smarty的规范来。让我们看看手册怎么说:


所有例子中,我们假定你使用缺省的分隔符。Smarty中,所有在分隔符之外的内容被显示为静态内容,或者说不会被改变。一旦Smarty遇见分隔符,它将尝试解释它们,然后在其位置处显示合适的内容。

注释

模板注释由星号包围,继而由分隔符包围,型如:{* 这是一个注释 *}。Smarty注释不会在最终模板的输出中显示,这点和<!-- HTML comments -->不同。前者对于在模板中插入内部注释有用,因为没有人能看到。;-)

{* 这是Smarty注释,不出现在编译后的输出中 *}
<html>
<head>
<title>{$title}</title>
</head>
<body>

{* 另一个单行Smarty注释 *}
<!-- HTML注释将发送到浏览器 -->

{* 这是一个多行
Smarty注释
并不发送到浏览器
*}

{*********************************************************
多行注释块,包含了版权信息
@ author: bg@example.com
@ maintainer: support@example.com
@ para: var that sets block style
@ css: the style output
**********************************************************}

{* 包含了主LOGO和其他东西的头文件 *}
{include file='header.tpl'}


{* 开发注解:$includeFile变量在foo.php脚本中赋值 *}
<!-- 显示主内容块 -->
{include file=$includeFile}

{* 该<select>块是多余的 *}
{*
<select name="company">
{html_options options=$vals selected=$selected_id}
</select>
*}

{* 模板的cvs标记。下面的36应该是美元符号。
但是在CVS中被转换了。 *}
{* &#36;Id: Exp &#36; *}
{* $Id: *}
</body>
</html>
smarty中的变量使用

smarty中的变量使用

smarty中的变量和平时使用有点区别,比如$aa.bb其实代表的是$aa['bb'],具体如何个使用法,其实在手册里已经有详细说明了

Smarty可以识别嵌入在双引号中赋值的变量,只要变量名只包含数字,字母,下划线和方括号[](参见命名)。如果有其它字符(如句点,对象引用等),变量必须由反引号对`backticks`包含。你不可以嵌入修饰符,它们必须永远在引号之外使用。

实际使用中应该是这样的:

语法例子:
{func var="test $foo test"} <-- 使用$foo
{func var="test $foo_bar test"} <-- 使用$foo_bar
{func var="test $foo[0] test"} <-- 使用$foo[0]
{func var="test $foo[bar] test"} <-- 使用$foo[bar]
{func var="test $foo.bar test"} <-- 使用$foo(不是$foo.bar)
{func var="test `$foo.bar` test"} <-- 使用$foo.bar

{func var="test `$foo.bar` test"|escape} <-- 修饰符在引号外!

实际例子:
{include file="subdir/$tpl_name.tpl"} <-- 将以实际值替换$tpl_name
{cycle values="one,two,`$smarty.config.myval`"} <-- 必须有反引号!

看清楚哦。平时在使用的时候应该是感觉不出问题的,只有用在函数、循环里面,这才会成为使用中的问题。

ThinkPHP怎么样更好的使用Smarty第三方插件

如果你在使用ThinkPHP框架的时候不想采用TP自带的模版系统,而使用第三方的模版系统,你有很多其他的选择,在这里我仅介绍Smarty这种比较官方,而且比较强大的模版系统。

由于Smarty兼容PHP4,因此,它的效率会相对低一点点,这个低只是相对的,估计等Smarty啥时候正式放弃PHP4的时候,效率可能会上很大一个台阶。


官方标准使用方法:

在TP框架的PlugIns目录下面,有一个SmartTemplate目录,里面就是系统自带的Smarty插件。

使用方法如下:

1、在项目的Conf/Config.php文件里加上:

return array(
'THINK_PLUGIN_ON' => true,
'TMPL_ENGINE_TYPE'=>'smarty',
);

2、下载好Smarty,并将smarty的libs目录整个拷至项目的PlugIns目录下(说明一下,PlugIns目录可能会不存在,需要自己建立),同时将libs目录改名为SmartTemplate(希望没有记错,其实也就是与THINKPHP的PlugIns目录里的SmartyTemplate目录同名即可),如果你不愿意把目录改成这个名字,那么,你必须到TP的插件目录里修改插件文件,使之包含路径正确。

3、注意修改每次修改action或模板文件后删除Temp下的html文件

说明一下:上面的内容来自于官方,由lin_chaoqi朋友解答的,网址为:http://bbs.thinkphp.cn/viewthread.php?tid=305&highlight=smarty


在这里我要提的方法是于上面不一样的,黑黑

因为我在使用第三方模版插件的时候,特地看了TP的view.class.php发现了一些很重要的问题,那就是,如果采用第三方模版插件,那么第三方模版插件的效率可能不能保证,因为View类的fetch方法在判断是否为第三方插件之间,作了很多TP模版插件的自有处理,而这些对于使用第三方模版插件来说,几乎是完全无效的,这些处理可能会给第三方插件带来影响,同时也影响了第三方插件的执行效率。问题已经与流年沟通过,但由于改动可能会很大,或许最近几个版本里,流年都不会尝试作改进吧,一是怕影响了那些已经使用第三方插件的程序,二来如果去除掉这些处理,那么View类可能就不需要了。流年对于这样的情况应该是不愿意看到的。毕竟这也影响了原有系统的架构,估计流年得仔细考虑了……[当然从流年个人来说,肯定是希望大家都使用TP自有的模版插件,只是我目前对于smarty则是更加熟悉而己],但对于我这个使用者来说,我需要的是临时解决方法,所以,就有了下面的内容。

为了解决这个问题,我只有从View.class.php里下手,因为Action.class.php里有一行:

$this->tpl = View::getInstance();

那么,也就是说 tpl 这个变量是 View 的单例模式,检查了一下View.class.php中的这个getInstance方法,发现里面使用了 get_instance_of 这个函数(这个函数是有一点小BUG的,这里不作解释,但我目前也没有更好的解决方法),于是我对getInstance和__construct两个方法进行了改动,删除了__construct方法,加上了init方法,改动代码如下:

static function getInstance() {
return get_instance_of(__CLASS__,'init');
}

public function init ($type=''){
if(!empty($type)) {
$this->type = strToUpper( $type );
}else{
$this->type = strtoupper(C('TMPL_ENGINE_TYPE'));
}
if ( !in_array( $this->type, array('PHP','THINK') ) ){
$type = ucfirst( strToLower( $this->type ) );
vendor( $type );
return new $type();
}
return $this;
}

也就是让View类在实例化的时候,同时调用init方法。在这个方法里,我将我自己的模版插件放到了第三方插件的目录(Vendor)下。

切记切记:千万不可漏掉最后一句return $this;,其实这就是我所说的get_instance_of的BUG,如果不加这句,那么当type变量为PHP或THINK时,getInstance是无法返回实例的。

新的使用方法步骤如下:

1、修改项目的Conf/Config.php文件:

return array(
'THINK_PLUGIN_ON' => true,
'TMPL_ENGINE_TYPE'=>'TpSmarty',
);

2、在TP的Vendor目录下面,创建TpSmarty.php,内容如下:

<?php
include_once(PLUGIN_PATH."smarty/Smarty.class.php");

class TpSmarty extends Smarty {
public function __construct (){
parent::Smarty();
$this->caching = true;
$this->template_dir = TMPL_PATH;
$this->compile_dir = CACHE_PATH ;
$this->cache_dir = TEMP_PATH ;
}
}
?>

上面是最简单的写法,实际使用中,这些变量请改为与你自己的站点相配合。

3、根据上面的文件里的include_once函数,将smarty的libs目录拷贝至项目的PlugIns目录下,改名为:smarty(只需要与include_once中的目录相匹配即可)

4、然后,在项目的方法里就可以直接使用:

class IndexAction extends Action{
public function index(){
$this->assign('test','testss');
$this->display('default/index.html');
}
}

只是,使用了插件后,display方法的参数是模版的全路径,而且不能留空(并非不能解决,只是要改动的代码就会更多,目前这个方法是改动最少的)。

测试一下,是否正常了?呵呵 。

现在,我们把Config里的模版引擎换回Think,同时在Tpl/default/目录下建立Index目录,里面放上index.html,并修改上面的index()方法,将原来的$this->display('default/index.html'); 改为$this->display(); ,试一下,是不是也正常了?

测试一下:

<?php

if( !emptyempty( $test )){
echo 'test fck empty';
}
果然。不是我的错。。。哈哈是自动生成两个empty的。。。