Smarty修飾子にハマり

SmartyでXHTMLテンプレートにアサインする際に、EUC-JPの文字列をUTF-8に変換する必要がある。
この変換を以前はmojaviビューにやらせてたけど、Smarty側に修飾子プラグインとして実装したほうが良いとわかり、以下はその変更の経緯を書いたメモ。

↓これは、修飾子(...を要約したもの)の最初のバージョン。
function smarty_modifier_encoding ($value) {
  return mb_convert_encoding($value, 'utf8', 'euc-jp');
}

この単純なコードだと、配列をアサインしたときにうまくいかない。つまり、mb_convert_encodingがエラーを返す。世の中そんなに甘くない。
# というか、Smarty標準のescape修飾子も、配列に対して使うとエラーになる様な
# 気がするんですが。仕様ですか?

↓この点を修正してみたバージョンが、これ。配列の問題を解決。
function smarty_modifier_encoding ($value) {
  if (is_array($value)) {
    return $value;
  }
  return mb_convert_encoding($value, 'utf8', 'euc-jp');
}

配列がアサインされたときは、アサイン値をそのまま返すことにする。
foreachブロックの中で、配列の各要素がアサインされた時にmb_convert_encodingが実行されるので、このコーディングでも問題はない。

解決したと思ったら、次の問題が出てきた。
↓テンプレートでは以下の様に、foreachタグを使ったループを書いているとしよう。
{foreach from=$entries item=entry}
  <a href="/?module={$module}&action=Detail&entry={$entry.id}">{$entry.id}</a>
{foreachelse}
  該当するエントリーがありません。
{/foreach}

ここで、entries値に何もアサインしない場合にforeachelseが評価されず、何故かループを1回廻してしまう。明示的に、nullや空文字列('')や空配列(array())等をアサインしてみたがダメ。結果は変わらず。
↓今のままでも、テンプレートをこんな風に変えてみると動くけど、かなりショボい。
{if $entries}
{foreach from=$entries item=entry}
  <a href="/?module={$module}&action=Detail&entry={$entry.id}">{$entry.id}</a>
{/foreach}
{else}
  該当するエントリーがありません。
{/if}

仕方がなくて、Smartyのソースやら生成されたキャッシュやらを読んでみたら、アサインされた値が空の場合にもmb_convert_encodingが実行されてしまうのが問題の様だ。よって、
function smarty_modifier_encoding ($value) {
  if (is_array($value)) {
    return $value;
  } else if ($value) {
    return mb_convert_encoding($value, 'utf8', 'euc-jp');
  }
}

てな具合に書き換えれば良いことになる。
$valueが空の場合に修飾子はnullを返し、mb_convert_encodingは実行されない。
これでバッチリ、今のところ問題なし。

これだけのことにえらく手間取ってしまったけど、Smartyのソースを読む良い機会だったから、よしとする。

トラックバック

コメント


コメントはすぐには反映しません。
ほぼ毎日チェックしていますが、翌日以降の反映となることもあります。

Twitter