{{ foo1 }}とか
{{ foo2|safe }}とか
{{ foo3.func('bar') }}とか
などと書かれたテンプレートを解析して、
foo1とかfoo2とかfoo3を抽出したい、というような場合。
※需要、ないなあ・・・。
パッと思いつくのはpreg_matchとかで
文字列解析する方法ですが、
テンプレートエンジンの場合、
タグの開始・終了文字(*1)をユーザが自由に
変更できたりするなど、
あまり単純な方法ではダメなのではないか、と思い。
でも、twigの場合、parser,lexerが外から操作できたり
簡単に拡張できたりするので、それでやってみよう、と。
・・・ということをやってみました。
抽出する関数
function getAssignVarsFrom($stream)
{
$ret = array();
$bIn = false;
$bInFirst = false;
while(! $stream->isEOF())
{
// get current node
$curr = $stream->getCurrent();
switch ($curr->getType()) {
case Twig_Token::VAR_START_TYPE:
$bIn = true;
$bInFirst = true;
break;
case Twig_Token::NAME_TYPE:
if ($bInFirst) {
$ret[$curr->getValue()] = $curr->getLine();
}
$bInFirst = false;
break;
case Twig_Token::VAR_END_TYPE:
$bIn = false;
$bInFirst = false;
break;
default:
break;
}
// next
$stream->next();
}
return $ret;
}
{
$ret = array();
$bIn = false;
$bInFirst = false;
while(! $stream->isEOF())
{
// get current node
$curr = $stream->getCurrent();
switch ($curr->getType()) {
case Twig_Token::VAR_START_TYPE:
$bIn = true;
$bInFirst = true;
break;
case Twig_Token::NAME_TYPE:
if ($bInFirst) {
$ret[$curr->getValue()] = $curr->getLine();
}
$bInFirst = false;
break;
case Twig_Token::VAR_END_TYPE:
$bIn = false;
$bInFirst = false;
break;
default:
break;
}
// next
$stream->next();
}
return $ret;
}
呼び出し側
$loader = new Twig_Loader_Filesystem('/path/to/template/');
$twig = new Twig_Environment( $loader,
array(
'cache' => '/path/to/cache',
'auto_reload' => true,
)
);
$escaper = new Twig_Extension_Escaper(true);
$twig->addExtension($escaper);
$stream = $twig->tokenize($twig->getLoader()->getSource('sample2.html'), 'sample2.html');
$assigned_vars = getAssignVarsFrom($stream);
$twig = new Twig_Environment( $loader,
array(
'cache' => '/path/to/cache',
'auto_reload' => true,
)
);
$escaper = new Twig_Extension_Escaper(true);
$twig->addExtension($escaper);
$stream = $twig->tokenize($twig->getLoader()->getSource('sample2.html'), 'sample2.html');
$assigned_vars = getAssignVarsFrom($stream);
※かなり手抜きです。
"Twigの使い方"みたいなヤツのサンプルを簡単にイジっただけなので、
余計な処理がテンコ盛りだと思います。
(コンパイルしてないからcacheいらないんじゃないか、とか。
extenssionは関係ないんじゃないか、とか。)
tokenize()が返してくるstreamの中にtokenが格納されているので、
NAME_TYPEだけ引っこ抜く、と。
それだけだと、safeとかfuncだとかも引っこ抜いてきてしまうので、
取り敢えず、VAR_START_TYPEからVAR_END_TYPEの間で
最初に出てきたNAME_TYPEだけ引っこ抜く、と。
これで本当によいのかどうか、かなり怪しいところですが、
取り敢えず、ちゃんとfoo1,foo2,foo3だけ返してきてます。
ちなみに、Twigのバージョンは、0.9.6-DEVを使いました。