在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 shell命令合并图片的代码
Jun 23 PHP
PHP __autoload()方法真的影响性能吗?
Mar 30 PHP
php递归创建和删除文件夹的代码小结
Apr 13 PHP
php实现telnet功能示例
Apr 08 PHP
Codeigniter校验ip地址的方法
Mar 21 PHP
php使用MySQL保存session会话的方法
Jun 18 PHP
PHP开发Apache服务器配置
Jul 15 PHP
详解PHP中的状态模式编程
Aug 11 PHP
详解PHP的Yii框架中组件行为的属性注入和方法注入
Mar 18 PHP
ThinkPHP和UCenter接口冲突的解决方法
Jul 25 PHP
PHP实现权限管理功能示例
Sep 22 PHP
php中的依赖注入实例详解
Aug 14 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函数解决SQL injection
2006/10/09 PHP
PHP 无限分类三种方式 非函数的递归调用!
2011/08/26 PHP
AJAX的跨域访问-两种有效的解决方法介绍
2013/06/22 PHP
PHP导航下拉菜单的实现如此简单
2013/09/22 PHP
PHP执行Curl时报错提示CURL ERROR: Recv failure: Connection reset by peer的解决方法
2014/06/26 PHP
php实现通用的信用卡验证类
2015/03/24 PHP
php+html5基于websocket实现聊天室的方法
2015/07/17 PHP
php 类中的常量、静态属性、非静态属性的区别
2017/04/09 PHP
使用XHProf查找PHP性能瓶颈的实例
2017/12/13 PHP
js下获取div中的数据的原理分析
2010/04/07 Javascript
JQuery入门——用映射方式绑定不同事件应用示例
2013/02/05 Javascript
深入理解JavaScript中的传值与传引用
2013/12/09 Javascript
jquery库或JS文件在eclipse下报错问题解决方法
2014/04/17 Javascript
使用js实现的简单拖拽效果
2015/03/18 Javascript
jQuery实现的倒计时效果实例小结
2016/04/16 Javascript
JSON字符串转换JSONObject和JSONArray的方法
2016/06/03 Javascript
javascript实现去除HTML标签的方法
2016/12/26 Javascript
JavaScript手风琴页面制作
2017/05/17 Javascript
jQuery实现的页面遮罩层功能示例【测试可用】
2017/10/14 jQuery
加载 vue 远程代码的组件实例详解
2017/11/20 Javascript
基于React Native 0.52实现轮播图效果
2020/08/25 Javascript
Python httplib,smtplib使用方法
2008/09/06 Python
python中类的一些方法分析
2014/09/25 Python
Python性能优化技巧
2015/03/09 Python
Python 导入文件过程图解
2019/10/15 Python
使用BeautifulSoup4解析XML的方法小结
2020/12/07 Python
美国在线珠宝商店:SZUL
2017/02/11 全球购物
校园安全检查制度
2014/02/03 职场文书
药店主任岗位责任制
2014/02/10 职场文书
企业总经理岗位职责
2014/02/13 职场文书
篝火晚会主持词
2014/03/25 职场文书
蟋蟀的住宅教学反思
2014/04/26 职场文书
群众路线组织生活会发言材料
2014/10/17 职场文书
导游词之吉林花园山
2019/10/17 职场文书
解决Python中的modf()函数取小数部分不准确问题
2021/05/28 Python
SpringBoot SpringEL表达式的使用
2021/07/25 Java/Android