タグを自作して、それをTwigに組み込む方法が
少し分かりました。
が、想像以上に面倒ですし、
今でも未だ分からないことがたくさんです。。。
0.概要
(1)作りたいタグ今回、Twig0.9.8で、次のようなタグを作ってみます。
{% sample name as 'my tag' %}
一応、ドキュメントでは当該タグの作り方が記述されてますが、
どうやら内部仕様が変わってしまったようでして、
ドキュメント通りにコーディングしても、うまく動作しません。。。
そこで、実際どうやるの?っていうのを調べてみます。
(2)作成手順
以下を見てもらえれば分かるんですが、
大まかに言うと、タグを新しく作るには、
■TokenParser:構文解析し、Nodeを生成する
■Node:コンパイル時に出力する内容を生成
の2点を新しく作成する必要があるようです。
そして、それらは、
■Extension
↓
■TokenParser
・
・(コンパイラによるコンパイル)
・
■Node
のような手順で実行されるようです。
1.Extension定義
filterやtagを登録するのは、基本的に、Twig_Extensionを継承したクラスから行います。
ここでは、自作したTokenParserを登録します。
<?php
class Twig_Extension_Sample extends Twig_Extension
{
// !! return a handmaid token-parser !!
public function getTokenParsers()
{
return array(
new Twig_TokenParser_Sample(),
);
}
public function getName()
{
return 'sample';
}
}
?>
class Twig_Extension_Sample extends Twig_Extension
{
// !! return a handmaid token-parser !!
public function getTokenParsers()
{
return array(
new Twig_TokenParser_Sample(),
);
}
public function getName()
{
return 'sample';
}
}
?>
2.TokenParser作成
TokenParserを作成するとき、一応、parserの機能を使ってparseできます。しかし、具体的に、どんな機能があるかは、
Twig_Parserクラスのソースを読むしかないようです。。。
<?php
class Twig_TokenParser_Sample extends Twig_TokenParser
{
public function parse(Twig_Token $token)
{
$lineno = $token->getLine();
$stream = $this->parser->getStream();
$exp = $this->parser->getExpressionParser();
// !! analyze token !!
$name = $exp->parseAssignmentExpression();
$stream->expect(Twig_Token::NAME_TYPE, 'as');
list(, $value) = $exp->parseMultitargetExpression();
$stream->expect(Twig_Token::BLOCK_END_TYPE);
return new Twig_Node_Sample($name, $value, $lineno, $this->getTag());
}
// !! this is tag name (in this case, 'sample' tag) !!
public function getTag()
{
return 'sample';
}
}
?>
class Twig_TokenParser_Sample extends Twig_TokenParser
{
public function parse(Twig_Token $token)
{
$lineno = $token->getLine();
$stream = $this->parser->getStream();
$exp = $this->parser->getExpressionParser();
// !! analyze token !!
$name = $exp->parseAssignmentExpression();
$stream->expect(Twig_Token::NAME_TYPE, 'as');
list(, $value) = $exp->parseMultitargetExpression();
$stream->expect(Twig_Token::BLOCK_END_TYPE);
return new Twig_Node_Sample($name, $value, $lineno, $this->getTag());
}
// !! this is tag name (in this case, 'sample' tag) !!
public function getTag()
{
return 'sample';
}
}
?>
3.Node作成
ここでの目玉は、何といってもcompile()ですが、ここもTwig_Compilerクラスのソースを読むしかないようです。。。
<?php
class Twig_Node_Sample extends Twig_Node
{
protected $_name = null;
protected $_value = null;
public function __construct($name, $value, $lineno, $tag = null)
{
parent::__construct(array('name' => $name, 'value' => $value), array(), $lineno, $tag);
$this->_name = $name;
$this->_value = $value;
}
public function compile($compiler)
{
$compiler->subcompile($this->_name, false);
$compiler->raw(' = ');
$compiler->subcompile($this->_value);
$compiler->raw(";\n");
}
}
?>
class Twig_Node_Sample extends Twig_Node
{
protected $_name = null;
protected $_value = null;
public function __construct($name, $value, $lineno, $tag = null)
{
parent::__construct(array('name' => $name, 'value' => $value), array(), $lineno, $tag);
$this->_name = $name;
$this->_value = $value;
}
public function compile($compiler)
{
$compiler->subcompile($this->_name, false);
$compiler->raw(' = ');
$compiler->subcompile($this->_value);
$compiler->raw(";\n");
}
}
?>
これらにより、実際のコンパイル結果には、
次のように出力されます。
$context['name'] = "viva";
たったこれだけ出力するだけで、結構な労力が必要ですね。。。
タグを自作する場合には、どうしても必要な場合だけに
限ったほうがいいと思います
でも、どうしても必要な場合は、果たしてあるんでしょうか・・・?
それよりも、Twigを使う場合のViewクラスなどを工夫したほうが
よさそうな気がしますが、どうでしょう?
0 件のコメント:
コメントを投稿
どうかお気軽にコメント頂ければ幸いです。