在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 相关文章推荐
PHP 选项及相关信息函数库
Dec 04 PHP
php SQL之where语句生成器
Mar 24 PHP
PHP下常用正则表达式整理
Oct 26 PHP
深入PHP empty(),isset(),is_null()的实例测试详解
Jun 06 PHP
php网站判断用户是否是手机访问的方法
Nov 01 PHP
PHP+jquery+ajax实现即时聊天功能实例
Dec 23 PHP
php实现在服务器上创建目录的方法
Mar 16 PHP
根据key删除数组中指定的元素实现方法
Mar 02 PHP
PHP实现对文件锁进行加锁、解锁操作的方法
Jul 04 PHP
php获取目录下所有文件及目录(多种方法)(推荐)
May 14 PHP
php写入txt乱码的解决方法
Sep 17 PHP
php多进程中的阻塞与非阻塞操作实例分析
Mar 04 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
收集的php编写大型网站问题集
2007/03/06 PHP
php操作xml入门之xml基本介绍及xml标签元素
2015/01/23 PHP
Laravel框架中实现使用阿里云ACE缓存服务
2015/02/10 PHP
WampServer搭建php环境时遇到的问题汇总
2015/07/23 PHP
PHP数组函数array_multisort()用法实例分析
2016/04/02 PHP
PHP 二级子目录(后台目录)设置二级域名
2017/03/02 PHP
php实现的生成排列算法示例
2019/07/25 PHP
Laravel开启跨域请求的方法
2019/10/13 PHP
走出JavaScript初学困境—js初学
2008/12/29 Javascript
js 判断checkbox是否选中的实现代码
2010/11/23 Javascript
jquery下将选择的checkbox的id组成字符串的方法
2010/11/28 Javascript
JS 获取select(多选下拉)中所选值的示例代码
2013/08/02 Javascript
avascript中的自执行匿名函数应用示例
2014/09/15 Javascript
浅谈Javascript中的Function与Object
2015/01/26 Javascript
浅谈使用MVC模式进行JavaScript程序开发
2015/11/10 Javascript
Jquery实现仿京东商城省市联动菜单
2015/11/19 Javascript
DOM 事件的深入浅出(二)
2016/12/05 Javascript
详解Vue.js Mixins 混入使用
2017/09/15 Javascript
nodejs实现简单的gulp打包
2017/12/21 NodeJs
vue2实现搜索结果中的搜索关键字高亮的代码
2018/08/29 Javascript
Vue.js结合bootstrap前端实现分页和排序效果
2018/12/29 Javascript
Vue CL3 配置路径别名详解
2019/05/30 Javascript
[26:52]LGD vs EG 2018国际邀请赛小组赛BO2 第一场 8.17
2018/08/18 DOTA
Python模拟脉冲星伪信号频率实例代码
2018/01/03 Python
浅谈Python小波分析库Pywavelets的一点使用心得
2019/07/09 Python
docker django无法访问redis容器的解决方法
2019/08/21 Python
浅析PEP572: 海象运算符
2019/10/15 Python
python 求定积分和不定积分示例
2019/11/20 Python
PyTorch中permute的用法详解
2019/12/30 Python
Jupyter Notebook安装及使用方法解析
2020/11/12 Python
WEB控件可以激发服务端事件,请谈谈服务端事件是怎么发生并解释其原理?自动传回是什么?为什么要使用自动传回?
2012/02/21 面试题
介绍一下UNIX启动过程
2013/11/14 面试题
初一体育教学反思
2014/01/29 职场文书
法制教育演讲稿
2014/09/10 职场文书
建设幸福中国演讲稿
2014/09/11 职场文书
Spring Boot 底层原理基础深度解析
2022/04/03 Java/Android