在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框架Phpbean说明
Jan 10 PHP
php数组应用之比较两个时间的相减排序
Aug 18 PHP
PHP中PDO基础教程 入门级
Sep 04 PHP
深入解析Session是否必须依赖Cookie
Aug 02 PHP
PHP中的str_repeat函数在JavaScript中的实现
Sep 16 PHP
php数组转成json格式的方法
Mar 09 PHP
PHP+Mysql+jQuery中国地图区域数据统计实例讲解
Oct 10 PHP
PHP封装的字符串加密解密函数
Dec 18 PHP
joomla数据库操作示例代码
Jan 06 PHP
PHP实现的最大正向匹配算法示例
Dec 19 PHP
php微信开发之关注事件
Jun 14 PHP
PHP defined()函数的使用图文详解
Jul 20 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 中执行排序与 MySQL 中排序
2009/04/21 PHP
php数组的一些常见操作汇总
2011/07/17 PHP
PHP利用str_replace防注入的方法
2013/11/10 PHP
PHP数组游标实现对数组的各种操作详解
2016/01/26 PHP
php与python实现的线程池多线程爬虫功能示例
2016/10/12 PHP
php分页查询mysql结果的base64处理方法示例
2017/05/18 PHP
解决laravel查询构造器中的别名问题
2019/10/17 PHP
JavaScript网页制作特殊效果用随机数
2007/05/22 Javascript
使用jquery为table动态添加行的实现代码
2011/03/30 Javascript
Extjs4 GridPanel的主要配置参数详细介绍
2013/04/18 Javascript
文本框水印提示效果的简单实现代码
2014/02/22 Javascript
jquery鼠标放上去显示悬浮层即弹出定位的div层
2014/04/25 Javascript
Node.js搭建小程序后台服务
2018/01/03 Javascript
微信小程序用户拒绝授权的处理方法详解
2019/09/20 Javascript
ReactRouter的实现方法
2021/01/25 Javascript
[02:41]DOTA2亚洲邀请赛小组赛第三日 赛事回顾
2015/02/01 DOTA
[07:26]2015国际邀请赛第二日TOP10集锦
2015/08/06 DOTA
[51:10]VP vs VGJ.S 2018国际邀请赛小组赛BO2 第二场 8.19
2018/08/21 DOTA
Python实现根据IP地址和子网掩码算出网段的方法
2015/07/30 Python
python多进程中的内存复制(实例讲解)
2018/01/05 Python
python测试mysql写入性能完整实例
2018/01/18 Python
pycharm打开命令行或Terminal的方法
2019/01/16 Python
使用python制作一个为hex文件增加版本号的脚本实例
2019/06/12 Python
Python Subprocess模块原理及实例
2019/08/26 Python
关于python导入模块import与常见的模块详解
2019/08/28 Python
django框架创建应用操作示例
2019/09/26 Python
Python实现计算图像RGB均值方式
2020/06/04 Python
利用keras使用神经网络预测销量操作
2020/07/07 Python
纯CSS3实现表单验证效果(非常不错)
2017/01/18 HTML / CSS
大学生水文观测实习自我鉴定
2013/09/29 职场文书
先进个人事迹材料
2014/01/25 职场文书
岗位职责怎么写
2014/03/14 职场文书
公司经理聘任书
2014/03/29 职场文书
大学生上课迟到检讨书
2014/10/15 职场文书
使用 Docker Compose 构建复杂的多容器App
2022/04/30 Servers
CSS 左边固定宽右边自适应的6种方法
2022/05/15 HTML / CSS