在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
header()函数使用说明
Nov 23 PHP
使用PHP导出Word文档的原理和实例
Oct 21 PHP
使用array_map简单搞定PHP删除文件、删除目录
Oct 29 PHP
详解PHP的Yii框架中扩展的安装与使用
Apr 01 PHP
PHP使用stream_context_create()模拟POST/GET请求的方法
Apr 02 PHP
PHP二维数组去重算法
Dec 17 PHP
PHP编程实现阳历转换为阴历的方法实例
Aug 08 PHP
PHP中一个有趣的preg_replace函数详解
Aug 15 PHP
mongodb和php的用法详解
Mar 25 PHP
Codeigniter里的无刷新上传的实现代码
Apr 14 PHP
php实现商城购物车的思路和源码分析
Jul 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 判断是否是中文/英文/数字示例代码
2013/09/30 PHP
php判断文件夹是否存在不存在则创建
2015/04/09 PHP
php简单解析mysqli查询结果的方法(2种方法)
2016/06/29 PHP
基于JQuery的访问WebService的代码(可访问Java[Xfire])
2010/11/19 Javascript
超轻量级的基于jquery的三级展开列表
2011/04/26 Javascript
jquery实现的网页自动播放声音
2014/04/30 Javascript
jQuery内置的AJAX功能和JSON的使用实例
2014/07/27 Javascript
javascript使用appendChild追加节点实例
2015/01/12 Javascript
删除javascript所创建子节点的方法
2015/05/21 Javascript
jQuery仿gmail实现fixed布局的方法
2015/05/27 Javascript
jquery实现通用的内容渐显Tab选项卡效果
2015/09/07 Javascript
深入浅出ES6新特性之函数默认参数和箭头函数
2016/08/01 Javascript
DataTables+BootStrap组合使用Ajax来获取数据并且动态加载dom的方法(排序,过滤,分页等)
2016/11/09 Javascript
使用jquery datatable和bootsrap创建表格实例代码
2017/03/17 Javascript
解决Layui 表单提交数据为空的问题
2018/08/15 Javascript
详解一些适用于Node.js的命名约定
2019/12/08 Javascript
vue-cli创建的项目中的gitHooks原理解析
2020/02/14 Javascript
解决vue.js中settimeout遇到的问题(时间参数短效果不稳定)
2020/07/21 Javascript
python持久性管理pickle模块详细介绍
2015/02/18 Python
关于Python元祖,列表,字典,集合的比较
2017/01/06 Python
用python记录运行pid,并在需要时kill掉它们的实例
2017/01/16 Python
Django2 连接MySQL及model测试实例分析
2019/12/10 Python
Pytest参数化parametrize使用代码实例
2020/02/22 Python
Python通过Pillow实现图片对比
2020/04/29 Python
pytorch中的weight-initilzation用法
2020/06/24 Python
Python 多进程原理及实现
2020/12/21 Python
27个经典Linux面试题及答案,你知道几个?
2013/01/10 面试题
会议开场欢迎词
2014/01/15 职场文书
给校长的建议书300字
2014/05/16 职场文书
小学家长通知书评语
2014/12/31 职场文书
超市员工辞职信范文
2015/05/12 职场文书
springboot拦截器无法注入redisTemplate的解决方法
2021/06/27 Java/Android
SQLServer权限之只开启创建表权限
2022/04/12 SQL Server
解决Windows Server2012 R2 无法安装 .NET Framework 3.5
2022/04/29 Servers
PyCharm 配置SSH和SFTP连接远程服务器
2022/05/11 Python
Win11 22H2 2022怎么更新? 获得Win1122H22022版本升级技巧
2022/09/23 数码科技