2008年4月7日(月曜日)

Smartyのテンプレートの文字列内変数を拡張する

カテゴリー: - sato @ 17時20分49秒

satoです。
XOOPSでは、テンプレートエンジンにSmartyを使うことになります。
このSmartyは便利なのですが、若干使いづらい部分もあったりまします。

まず前提として、Smartyの文字列定数中に変数を混ぜたい場合、バッククォート(`)で囲むとそれが変数として解釈されるようになっています。
例えば、

{"私は`$name`です。"}

として、$nameに"sato"という文字列がassignされていると、

私はsatoです。

と表示されます。

しかし、このバッククォート内にメンバ関数を指定すると、解釈がうまくいかないようです。

例えば、

私は{$my->show('name')}です。

みたいなものは可能なのですが、

{"私は`$my->show('name')`です"}

とすると、

私は`Object id #2->show('name')`です。

のように、$myの部分だけ変数として解釈され、それ以外は普通の文字列として出力されてしまいます。
通常、こういう場合は、

{assign var=name value=$my->show('name')}
{"私は`$name`です"}

のように1段階assignを追加することになり、若干手間がかかります。
今回はこれの簡易的な対応方法を試してみました。

Smartyのassignされた変数というのは、実際にそのスコープに存在するものではなく、Smartyクラスの_tpl_varsメンバ変数に格納されています。このため、テンプレート側で記述した変数は、Smartyの構文解析を通してSmartyクラスのメンバ変数になるように置換処理が入ります。具体的には生成されたテンプレートキャッシュを見ればわかると思います。
そのため、Smartyでは正規表現を利用して構文解析を行っているのですが、この正規表現に手を入れることで、上記の対応が可能になります。

バッククォート内を解釈しているのは、Smarty_Compiler#_expand_quoted_textで、変数の解析をしている正規表現は_obj_ext_regexpに格納されています。
このため、Smarty_Compilerに手を入れればいいのですが、Smarty_CompilerはSmarty#_compile_sourceで生成され、すぐ破棄されるので、途中からアクセスすることはできません。Smarty_Compiler.class.phpを直接書き換えればいいという話もありますが、それでは汚くなってしまいます。
幸い、Smartyクラスが生成するSmarty_Compilerクラスは別のものに変更ができるようになっています。Smartyクラスのcompiler_fileとcompiler_classにそれぞれ読み込むファイルとクラス名が格納されているので、それを自前のものに変更します。

具体的にやってみます。
以下のファイルを作成します。パス等は適宜変更してください。
MySmartyCompiler.class.php


	

require 'Smarty-2.6.19/libs/Smarty_Compiler.class.php';

class MySmartyCompiler extends Smarty_Compiler { function MySmartyCompiler() { parent::Smarty_Compiler();

$this->_obj_ext_regexp = str_replace(’(?:[$?[w.]+])*’, ‘(?:[($?[w.]+)])*(?:(($?[w"’.]+)))*’, $this->_obj_ext_regexp); } }

呼び出し側を作成します。
index.php


	

require 'Smarty-2.6.19/libs/Smarty.class.php';

class myClass {

function show($var) { return 'sato'; }

}

$smarty = new Smarty(); $smarty->compiler_file = ‘MySmartyCompiler.class.php’; $smarty->compiler_class = ‘MySmartyCompiler’;

$smarty->template_dir = ‘templates’; $smarty->compile_dir = ‘templates_c’; $smarty->config_dir = ‘config’; $smarty->cache_dir = ‘cache’; $smarty->plugins_dir = ‘plugins’;

$smarty->assign(’my’, new myClass()); $smarty->display(’index.tpl’);

テンプレートを作成します。
templates/index.tpl

<html>
<body>

{"私は`$my->show('name')`です。"}

</body> </html>

実行すると、

私はsatoです。

のように正常に表示されているのが確認できると思います。
全てのパターンでテストを行っているわけではないので、不具合があったらコメント欄等でよろしくお願いします。

XOOPSからこれを利用する場合は、各RenderSystem内に存在するSmartyオブジェクトを取得して書き換える必要があります。
モジュールの場合は通常はLegacy_RenderSystemなので、

    $root =& XCube_Root::getSingleton();
    $renderSystem = $root->mContext->mModule->getRenderSystem();
    $renderSystem->mXoopsTpl->compiler_file = 'MySmartyCompiler.class.php';
    $renderSystem->mXoopsTpl->compiler_class = 'MySmartyCompiler';

のような感じで対応が可能です。(表示処理の実行前に記述してください)
管理画面はLegacy_AdminRenderSystemなので、mXoopsTplではなくmSmartyを参照することになります。

しかしこの方法でも、

{"私は`$pattern[$foo->bar()]`です"}

のようなパターンには対応できません。このパターンに対応するには_expand_quoted_text自体を大幅に改変する必要がありそうです。興味のある方は挑戦してみてください。


RSS feed for comments on this post.

ƤˤϡޤȤդƤޤ

Ȥ

ʤߥȤդ뤳ȤϽޤ

10 queries. 0.024 sec.
Powered by WordPress Module based on WordPress ME & WordPress

〒104-0061 東京都中央区銀座1丁目3番3号 G1ビル7階
お問い合わせ TEL 03-3524-8860

Copyright(c) 2012 RYUS.All Rights Reserved.