在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新手上路(八)
Oct 09 PHP
MySql 按时间段查询数据方法(实例说明)
Nov 02 PHP
PHP n个不重复的随机数生成代码
Jun 23 PHP
过滤掉PHP数组中的重复值的实现代码
Jul 17 PHP
ThinkPHP验证码使用简明教程
Mar 05 PHP
php+MySQL判断update语句是否执行成功的方法
Aug 28 PHP
PHP中addcslashes与stripcslashes函数用法分析
Jan 07 PHP
浅谈Yii乐观锁的使用及原理
Jul 25 PHP
PHP编程实现脚本异步执行的方法
Aug 09 PHP
Laravel中Facade的加载过程与原理详解
Sep 22 PHP
PHP如何将图片文件上传到另外一台服务器上
Aug 26 PHP
PHP中多字节字符串操作实例详解
Aug 23 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 socke 向指定页面提交数据
2008/07/23 PHP
php获取CSS文件中图片地址并下载到本地的方法
2014/12/02 PHP
PHP可变变量学习小结
2015/11/29 PHP
php使用ffmpeg向视频中添加文字字幕的实现方法
2016/05/23 PHP
在Laravel中使用MongoDB的方法示例
2019/11/11 PHP
php+js实现点赞功能的示例详解
2020/08/07 PHP
Prototype源码浅析 String部分(四)之补充
2012/01/16 Javascript
js遍历、动态的添加数据的小例子
2013/06/22 Javascript
jquery 跳到顶部和底部动画2句代码简单实现
2013/07/18 Javascript
Javascript代码实现仿实例化类
2015/04/03 Javascript
JQuery使用index方法获取Jquery对象数组下标的方法
2015/05/18 Javascript
javascript中的五种基本数据类型
2015/08/26 Javascript
Bootstrap每天必学之标签页(Tab)插件
2020/08/09 Javascript
基于Javascript实现的不重复ID的生成器
2016/12/25 Javascript
超简单的Vue.js环境搭建教程
2017/03/17 Javascript
JavaScript操作文件_动力节点Java学院整理
2017/06/30 Javascript
NodeJS加密解密及node-rsa加密解密用法详解
2018/10/12 NodeJs
node.js使用express框架进行文件上传详解
2019/03/03 Javascript
实现vuex与组件data之间的数据同步更新方式
2019/11/12 Javascript
[00:32]2018DOTA2亚洲邀请赛出场——LGD
2018/04/04 DOTA
python之matplotlib学习绘制动态更新图实例代码
2018/01/23 Python
将pandas.dataframe的数据写入到文件中的方法
2018/12/07 Python
python发送多人邮件没有展示收件人问题的解决方法
2019/06/21 Python
keras中的backend.clip用法
2020/05/22 Python
Python Socket TCP双端聊天功能实现过程详解
2020/06/15 Python
pycharm 2020 1.1的安装流程
2020/09/29 Python
python跨文件使用全局变量的实现
2020/11/17 Python
python 基于Apscheduler实现定时任务
2020/12/15 Python
什么是Rollback Segment
2013/04/22 面试题
学校办公室主任职责
2013/12/27 职场文书
入党积极分子思想汇报
2014/01/02 职场文书
致百米运动员广播稿5篇
2014/10/13 职场文书
2019年作为一名实习生的述职报告
2019/09/29 职场文书
SpringBoot+Vue+JWT的前后端分离登录认证详细步骤
2021/09/25 Java/Android
Vertica集成Apache Hudi重磅使用指南
2022/03/31 Servers
我去timi了,一起去timi是什么意思?
2022/04/13 杂记