Smartyのテンプレートの文字列内変数を拡張する
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.
ƤˤϡޤȤդƤޤ
Ȥ
ʤߥȤդ뤳ȤϽޤ