在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 相关文章推荐
安装APACHE
Jan 15 PHP
用PHP读取flv文件的播放时间长度
Sep 03 PHP
c#中的实现php中的preg_replace
Dec 21 PHP
Zend的AutoLoad机制介绍
Sep 27 PHP
php 无法加载mcrypt.dll的解决办法
Apr 03 PHP
怎么在Windows系统中搭建php环境
Aug 31 PHP
php中生成随机密码的自定义函数代码
Oct 21 PHP
php自定义的格式化时间示例代码
Dec 05 PHP
php全角字符转换为半角函数
Feb 07 PHP
PHP数据分析引擎计算余弦相似度算法示例
Aug 08 PHP
thinkPHP框架动态配置用法实例分析
Jun 14 PHP
Laravel 5.1 框架Blade模板引擎用法实例分析
Jan 04 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防止站外远程提交表单的方法
2014/10/20 PHP
PHP生成及获取JSON文件的方法
2016/08/23 PHP
php和js实现根据子网掩码和ip计算子网功能示例
2019/11/09 PHP
利用location.hash实现跨域iframe自适应
2010/05/04 Javascript
JavaScript类属性的访问方式详解
2014/02/11 Javascript
页面元素绑定jquery toggle后元素隐藏的解决方法
2014/03/27 Javascript
JavaScript之Canvas_动力节点Java学院整理
2017/07/04 Javascript
微信小程序tabBar用法实例详解
2017/12/04 Javascript
nodejs实现爬取网站图片功能
2017/12/14 NodeJs
node.js使用免费的阿里云ip查询获取ip所在地【推荐】
2018/09/03 Javascript
nodejs高大上的部署方式(PM2)
2018/09/11 NodeJs
详解ES6 Promise对象then方法链式调用
2018/10/20 Javascript
使用VScode 插件debugger for chrome 调试react源码的方法
2019/09/13 Javascript
Vue中使用Lodop插件实现打印功能的简单方法
2019/12/19 Javascript
jQuery实现回到顶部效果
2020/10/19 jQuery
从Python的源码来解析Python下的freeblock
2015/05/11 Python
Python实现批量转换文件编码的方法
2015/07/28 Python
Python 网页解析HTMLParse的实例详解
2017/08/10 Python
python互斥锁、加锁、同步机制、异步通信知识总结
2018/02/11 Python
利用Python读取txt文档的方法讲解
2018/06/23 Python
python遍历文件夹,指定遍历深度与忽略目录的方法
2018/07/11 Python
python3 中的字符串(单引号、双引号、三引号)以及字符串与数字的运算
2019/07/18 Python
Pytorch实现神经网络的分类方式
2020/01/08 Python
python使用梯度下降和牛顿法寻找Rosenbrock函数最小值实例
2020/04/02 Python
pycharm远程连接vagrant虚拟机中mariadb数据库
2020/06/05 Python
matplotlib运行时配置(Runtime Configuration,rc)参数rcParams解析
2021/01/05 Python
python和opencv构建运动检测器的实现
2021/03/03 Python
利用canvas实现图片压缩的示例代码
2018/07/17 HTML / CSS
H5离线存储Manifest原理及使用
2020/04/28 HTML / CSS
英国时尚服饰电商:Boohoo
2017/10/12 全球购物
新员工入职感言
2014/02/01 职场文书
师说教学反思
2014/02/07 职场文书
2014最新自愿离婚协议书范本
2014/11/19 职场文书
2015年度企业工作总结
2015/05/21 职场文书
干部培训简讯
2015/07/20 职场文书
Docker 镜像介绍以及commit相关操作
2022/04/13 Servers