在Yii框架中使用PHP模板引擎Twig的例子


Posted in PHP onJune 13, 2014

Twig是一款快速、安全、灵活的PHP模板引擎,它内置了许多filter和tags,并且支持模板继承,能让你用最简洁的代码来描述你的模板。他的语法和Python下的模板引擎Jinjia以及Django的模板语法都非常像。 比如我们在PHP中需要输出变量并且将其进行转义时,语法比较累赘:

<?php echo $var ?>
<?php echo htmlspecialchars(\$var, ENT_QUOTES, 'UTF-8') ?>

但是在Twig中可以这样写:
{{ var }}
{{ var|escape }}
{{ var|e }}         {# shortcut to escape a variable #}

遍历数组:
{% for user in users %}
  * {{ user.name }}
{% else %}
  No user has been found.
{% endfor %}

但是要在Yii Framework集成Twig就会遇到点麻烦了,官方网站中已经有能够集成Twig的方案,所以这里我也不再赘述。但是由于Twig中是不支持PHP语法的,所以在有些表达上会遇到困难,比如我们在写Form的视图时,经常会这么写:

<?php $form=$this->beginWidget('CActiveForm'); ?>
    <span>Login</span>
    <ul>
  <li>
    <?php echo $form->label($model,'username'); ?>
                <?php echo $form->textField($model,'username'); ?>
  </li>
  <li>
    <?php echo $form->label($model,'password'); ?>
                <?php echo $form->passwordField($model,'password'); ?>
  </li>
  <li class="last">
    <button type="submit">Login</button>
  </li>
</ul>
    <?php echo $form->error($model,'password'); ?>
<?php $this->endWidget(); ?>

但是这样的语法是没法在twig中表达的,所以想去扩展下Twig的功能,让他能够支持我们自定义的widget标签,然后自动解析成我们需要的代码。 总共需要两个类:TokenParser和Node,下面直接上代码:
<?php
/*
 * This file is an extension of Twig.
 *
 * (c) 2010 lfyzjck
 */
/**
 * parser widget tag in Yii framework
 *
 * {% beginwidget 'CActiveForm' as form %}
 *    content of form
 * {% endwidget %}
 *
 */
class Yii_WidgetBlock_TokenParser extends Twig_TokenParser
{
    /**
     * Parses a token and returns a node.
     *
     * @param Twig_Token $token A Twig_Token instance
     *
     * @return Twig_NodeInterface A Twig_NodeInterface instance
     */
    public function parse(Twig_Token $token)
    {
        $lineno = $token->getLine();
        $stream = $this->parser->getStream();
        $name = $stream->expect(Twig_Token::STRING_TYPE);
        if($stream->test(Twig_Token::PUNCTUATION_TYPE)){
            $args = $this->parser->getExpressionParser()->parseHashExpression();
        }
        else{
            $args = new Twig_Node_Expression_Array(array(), $lineno);
        }
        $stream->expect(Twig_Token::NAME_TYPE);
        $assign = $stream->expect(Twig_Token::NAME_TYPE);
        $stream->expect(Twig_Token::BLOCK_END_TYPE);
        $body = $this->parser->subparse(array($this, 'decideBlockEnd'), true);
        $stream->expect(Twig_Token::BLOCK_END_TYPE);
        return new Yii_Node_WidgetBlock(array(
            'alias' => $name->getValue(),
            'assign' => $assign,
        ), $body, $args, $lineno, $this->getTag());
    }
    /**
     * Gets the tag name associated with this token parser.
     *
     * @param string The tag name
     */
    public function getTag()
    {
        return 'beginwidget';
    }
    public function decideBlockEnd(Twig_Token $token)
    {
        return $token->test('endwidget');
    }
}
class Yii_Node_WidgetBlock extends Twig_Node
{
    public function __construct($attrs, Twig_NodeInterface $body, Twig_Node_Expression_Array $args = NULL, $lineno, $tag)
    {
        $attrs = array_merge(array('value' => false),$attrs);
        $nodes = array('args' => $args, 'body' => $body); 
        parent::__construct($nodes, $attrs, $lineno,$tag);
    }
    public function compile(Twig_Compiler $compiler)
    {
        $compiler->addDebugInfo($this);
        $compiler->write('$context["'.$this->getAttribute('assign')->getValue().'"] = $context["this"]->beginWidget("'.$this->getAttribute('alias').'",');
        $argNode = $this->getNode('args');
        $compiler->subcompile($argNode)
                 ->raw(');')
                 ->raw("\n");
        $compiler->indent()->subcompile($this->getNode('body'));
        $compiler->raw('$context["this"]->endWidget();');
    }
}
?>

然后在Twig初始化的地方增加我们的语法解析类:
$twig->addTokenParser(new Yii_WidgetBlock_TokenParser);

然后我们就可以在twig的模板里这么写了:
{% beginwidget 'CActiveForm' as form %}
<ul>
  <li>
    {{ form.label(model, 'username') }}
    {{ form.textField(model, 'username') }}
  </li>
  <li>
    {{ form.label(model, 'password') }}
    {{ form.passwordField(model, 'password') }}
  </li>
</ul>
{% endwidget %}
PHP 相关文章推荐
session 的生命周期是多长
Oct 09 PHP
关于BIG5-HKSCS的解决方法
Mar 20 PHP
CakePHP去除默认显示的标题及图标的方法
Oct 22 PHP
PHP zlib扩展实现页面GZIP压缩输出
Jun 17 PHP
PHP屏蔽过滤指定关键字的方法
Nov 03 PHP
9条PHP编程小知识及易犯的小错误
Jan 22 PHP
php比较两个字符串长度的方法
Jul 13 PHP
php快速排序原理与实现方法分析
May 26 PHP
PHP url的pathinfo模式加载不同控制器的简单实现
Aug 12 PHP
PHP实现无限分类的实现方法
Nov 14 PHP
关于php几种字符串连接的效率比较(详解)
Feb 22 PHP
PHP lcfirst()函数定义与用法
Mar 08 PHP
ThinkPHP中U方法的使用浅析
Jun 13 #PHP
PHP实现单例模式最安全的做法
Jun 13 #PHP
PHP5.5和之前的版本empty函数的不同之处
Jun 13 #PHP
PHP输出英文时间日期的安全方法(RFC 1123格式)
Jun 13 #PHP
PHP中多维数组的foreach遍历示例
Jun 13 #PHP
PHP根据传来的16进制颜色代码自动改变背景颜色
Jun 13 #PHP
php smarty truncate UTF8乱码问题解决办法
Jun 13 #PHP
You might like
IP攻击升级,程序改进以对付新的攻击
2010/11/23 PHP
CI框架安全类Security.php源码分析
2014/11/04 PHP
php使用ZipArchive函数实现文件的压缩与解压缩
2015/10/27 PHP
10个对初学者非常有用的PHP技巧
2016/04/06 PHP
PHP获取链表中倒数第K个节点的方法
2018/01/18 PHP
ThinkPHP框架获取最后一次执行SQL语句及变量调试简单操作示例
2018/06/13 PHP
[原创]图片分页查看
2006/08/28 Javascript
jQuery学习基础知识小结
2010/11/25 Javascript
html+js实现动态显示本地时间
2013/09/21 Javascript
将json对象转换为字符串的方法
2014/02/20 Javascript
Vue.js每天必学之组件与组件间的通信
2016/09/08 Javascript
node.js部署之启动后台运行forever的方法
2018/05/23 Javascript
使用electron将vue-cli项目打包成exe的方法
2018/09/29 Javascript
详解如何使用koa实现socket.io官网的例子
2018/11/04 Javascript
layer实现登录弹框,登录成功后关闭弹框并调用父窗口的例子
2019/09/11 Javascript
Vue + Scss 动态切换主题颜色实现换肤的示例代码
2020/04/27 Javascript
vue项目实现减少app.js和vender.js的体积操作
2020/11/12 Javascript
[00:35]TI7不朽珍藏III——寒冰飞龙不朽展示
2017/07/15 DOTA
利用python Selenium实现自动登陆京东签到领金币功能
2019/10/31 Python
Python变量作用域LEGB用法解析
2020/02/04 Python
解决python DataFrame 打印结果不换行问题
2020/04/09 Python
Python爬取豆瓣数据实现过程解析
2020/10/27 Python
解决使用Pandas 读取超过65536行的Excel文件问题
2020/11/10 Python
Django中使用Celery的方法步骤
2020/12/07 Python
python中子类与父类的关系基础知识点
2021/02/02 Python
css3 box-shadow阴影(外阴影与外发光)图示讲解
2017/08/11 HTML / CSS
深入浅析HTML5中的SVG
2015/11/27 HTML / CSS
英国领先的品牌珠宝和配件供应商:Acotis Jewellery
2018/03/07 全球购物
XML文档面试题
2015/08/05 面试题
自我评价中英文语句
2013/11/30 职场文书
工作决心书
2014/03/11 职场文书
监督检查工作方案
2014/05/28 职场文书
有关九一八事变的演讲稿
2014/09/14 职场文书
2014年效能监察工作总结
2014/11/21 职场文书
2015年行政人事工作总结
2015/05/21 职场文书
JavaScript流程控制(循环)
2021/12/06 Javascript