Twig是一款快速、安全、灵活的PHP模板引擎,它内置了许多filter和tags,并且支持模板继承,能让你用最简洁的代码来描述你的模板。他的语法和Python下的模板引擎Jinjia以及Django的模板语法都非常像。
比如我们在PHP中需要输出变量并且将其进行转义时,语法比较累赘:
1 2 | < ?php echo $var ?> < ?php echo htmlspecialchars(\$var, ENT_QUOTES, 'UTF-8') ?> |
但是在Twig中可以这样写:
1 2 3 | {{ var }}
{{ var|escape }}
{{ var|e }} {# shortcut to escape a variable #} |
遍历数组:
1 2 3 4 5 | {% for user in users %}
* {{ user.name }}
{% else %}
No user has been found.
{% endfor %} |
但是要在Yii Framework集成Twig就会遇到点麻烦了,官方网站中已经有能够集成Twig的方案,所以这里我也不再赘述。但是由于Twig中是不支持PHP语法的,所以在有些表达上会遇到困难,比如我们在写Form的视图时,经常会这么写:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | < ?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,下面直接上代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | < ?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初始化的地方增加我们的语法解析类:
1 | $twig->addTokenParser(new Yii_WidgetBlock_TokenParser); |
然后我们就可以在twig的模板里这么写了:
1 2 3 4 5 6 7 8 9 10 11 12 | {% 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 %} |