在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 相关文章推荐
一个捕获函数输出的函数
Feb 14 PHP
php mysql索引问题
Jun 07 PHP
linux下删除7天前日志的代码(php+shell)
Jan 02 PHP
匹配csdn用户数据库与官方用户的重合度并将重叠部分的用户筛选出来
Dec 25 PHP
PHP中最容易忘记的一些知识点总结
Apr 28 PHP
在win7中搭建Linux+PHP 开发环境
Oct 08 PHP
新浪微博OAuth认证和储存的主要过程详解
Mar 27 PHP
php+curl 发送图片处理代码分享
Jul 09 PHP
在WordPress中使用wp_count_posts函数来统计文章数量
Jan 05 PHP
PHP strip_tags() 去字符串中的 HTML、XML 以及 PHP 标签的函数
May 22 PHP
深入理解PHP 数组之count 函数
Jun 13 PHP
php5.x禁用eval的操作方法
Oct 19 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
新的一年,新的期待:DC在2020年的四部动画电影
2020/01/01 欧美动漫
PHP基于MySQL数据库实现对象持久层的方法
2015/06/17 PHP
php实现websocket实时消息推送
2018/03/30 PHP
为指定的元素添加遮罩层的示例代码
2014/01/15 Javascript
60个很实用的jQuery代码开发技巧收集
2014/12/15 Javascript
JavaScript动态创建link标签到head里的方法
2014/12/22 Javascript
Ajax中解析Json的两种方法对比分析
2015/06/25 Javascript
jquery动感漂浮导航菜单代码分享
2020/04/15 Javascript
JS+CSS实现的经典tab选项卡效果代码
2015/09/16 Javascript
javascript设计简单的秒表计时器
2020/09/05 Javascript
jquery mobile移动端幻灯片滑动切换效果
2020/04/15 Javascript
js, jQuery实现全选、反选功能
2017/03/08 Javascript
JQuery和html+css实现带小圆点和左右按钮的轮播图实例
2017/07/22 jQuery
使用JS编写的随机抽取号码的小程序
2017/08/11 Javascript
基于复选框demo(分享)
2017/09/27 Javascript
JS实现Cookie读、写、删除操作工具类示例
2018/08/28 Javascript
vue中rem的配置的方法示例
2018/08/30 Javascript
webpack4 处理SCSS的方法示例
2018/09/03 Javascript
Vue+Express实现登录注销功能的实例代码
2019/05/05 Javascript
微信小程序实现星级评价
2019/11/20 Javascript
解决父组件将子组件作为弹窗调用只执行一次created的问题
2020/07/24 Javascript
JS闭包原理及其使用场景解析
2020/12/03 Javascript
python学习手册中的python多态示例代码
2014/01/21 Python
Python随机函数random()使用方法小结
2018/04/29 Python
Python3.5 Pandas模块缺失值处理和层次索引实例详解
2019/04/23 Python
Django app配置多个数据库代码实例
2019/12/17 Python
python判断两个序列的成员是否一样的实例代码
2020/03/01 Python
Python 读取WAV音频文件 画频谱的实例
2020/03/14 Python
python如何导入依赖包
2020/07/13 Python
雅诗兰黛旗下专业男士保养领导品牌:Lab Series
2017/05/15 全球购物
印度购买眼镜和太阳镜网站:Coolwinks
2018/09/26 全球购物
工作会议方案
2014/05/21 职场文书
2014年幼儿园老师工作总结
2014/12/05 职场文书
python图像处理基本操作总结(PIL库、Matplotlib及Numpy)
2021/06/08 Python
MySQL开启事务的方式
2021/06/26 MySQL
Golang的继承模拟实例
2021/06/30 Golang