YiiフレームでPHPテンプレートエンジンTwigを使用した例

5613 ワード

Twigは高速で安全で柔軟なPHPテンプレートエンジンで、多くのfilterとtagsを内蔵し、テンプレートの継承をサポートし、最も簡潔なコードでテンプレートを説明することができます.彼の文法はPythonの下のテンプレートエンジンJinjiaやDjangoのテンプレート文法とよく似ています.たとえば、PHPで変数を出力し、それをエスケープする必要がある場合、構文は煩雑です.
 
  


しかし、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のビューを書くときによくこのように書くなど、表現に困難があります.
 
  
beginWidget('CActiveForm'); ?>
    Login
   

     

  •     label($model,'username'); ?>
                    textField($model,'username'); ?>

     

  •  


  •     label($model,'password'); ?>
                    passwordField($model,'password'); ?>

     

  •  


  •    

     


    error($model,'password'); ?>
endWidget(); ?>

しかし、このような文法はtwigでは表現できないので、Twigの機能を拡張して、私たちがカスタマイズしたwidgetラベルをサポートして、自動的に必要なコードに解析したいと思っています.TokenParserとNodeの2つのクラスが必要です.次は直接コードします.
 
  
/*
 * 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("
");

        $compiler->indent()->subcompile($this->getNode('body'));

        $compiler->raw('$context["this"]->endWidget();');
    }
}
?>


その後、Twig初期化の場所で文法解析クラスを追加します.
 
  
$twig->addTokenParser(new Yii_WidgetBlock_TokenParser);

twigのテンプレートにこう書くことができます
 
  
{% beginwidget 'CActiveForm' as form %}

     

  •     {{ form.label(model, 'username') }}
        {{ form.textField(model, 'username') }}
     

  •  

  •     {{ form.label(model, 'password') }}
        {{ form.passwordField(model, 'password') }}
     


{% endwidget %}