Smartyのフィルタ

2008/11/28 | Smarty

携帯サイト等シフトJISでサイトを構築する場合、Smartyを使うことにしている。PHP自体はシフトJISでの記述はNGなのでUTF-8で記述し、テンプレートHTMLをシフトJISで記述して使用している。素でそのまま使ってしまうと文字化けしてしまうので、テンプレートを読み込む際にいったん文字コードをUTF-8に変換し、出力するときに再度シフトJISに変換するような処理をしている。

そのときに便利な機能がSmartyのフィルタだ。フィルタにはプレフィルタ、ポストフィルタ、アウトプットフィルタの3種類があり、用途は以下のとおり。

  • プレフィルタ(prefilter)
    テンプレートをコンパイルする際(コンパイル前)にテンプレートファイルに対して処理が施される。
  • ポストフィルタ(postfilter)
    テンプレートをコンパイルする際(コンパイル後)にテンプレートファイルに対して処理が施される。
  • アウトプットフィルタ(outputfilter)
    コンパイルされたテンプレートに対して出力用の変数がアサイン等され、実際に出力する際に処理が施される。

実は最初勘違いしていた。プレフィルタとポストフィルタだけだと思っていた。テンプレート読み込み時にプレフィルタにかけられ、HTML出力時にポストフィルタにかけられると思っていた。Smartyを使った処理を記述する際に、希望通りの動作をしてくれないのでマニュアルを読み直してみて初めて知った。ちょっと恥ずかしい。

Smarty使用時のダウンロード処理

2008/06/25 | Smarty

ファイルのダウンロード処理をおこないたいときにテンプレートエンジンを使っている場合、どんな具合にプログラムを書けばよいか迷うことがよくある。フレームワークを使っていない場合はプログラム内にダウンロード処理を直書きしてしまうけれど、フレームワーク使用時は直書きするのはなんとなく美しくない。やっぱり通常通りの処理を通過して、テンプレート内だけで処理できればスマートだと思っている。Smartyの場合だが、今回はテンプレートファイルの最初にこんな具合におまじないを記述することでダウンロード処理を実現できた。

{php}
header(“Cache-Control: public”);
header(“Pragma: public”);
header(“Content-Type: application/csv”);
header(“Content-Disposition: inline; filename=data.dat”);
header(“Content-Transfer-Encoding: binary”);
header(“Accept-Ranges: none”);
{/php}

キャッシュ制御系はSSL使用時のIEバグ対策。Content-type、Content-Dispotion、Content-Transfer-Encodingは適宜指定。実際にダウンロードさせたい部分は、この後ろに記述すればよい。

でも、実はヘッダ的には一つ足りないんだと思う。それはダウンロードさせる容量Content-Lengthだ。この記述が必要なら、上記の記述の前に事前にダウンロードデータを以下のように記述して、容量を計算して出力すればいいかもしれない。

{capture name=download}
(ダウンロードさせたいデータを記述)
{/capture}
{header_content_length var=$smarty.capture.download}

いったん出力データを変数に格納して、別途ヘッダ出力用のカスタム関数(header_content_length)を用意しておいてそれに食わせてやればいい。カスタム関数が必要でしたら・・・各自でどうぞ(今回は作らなくても動いてくれたので作らなかった)。

Smartyでフォーム(ラジオボタンとチェックボックス)

2008/06/16 | Smarty

以前は「フォーム作成 = QuickForm」なくらいQuickFormを多用したけれど、近頃はめっきりQuickFormを使用しなくなった。QuickFormにはvalidation機能もあるし、なんといってもfreeze機能が便利なのだが、QuickForm2の安定版が出ないことには、多用する勇気が出ない。
QuickFormに変わってフォーム生成はSmartyのカスタム関数と自作のライブラリを使用している。基本的にはSmartyのカスタム関数だけで十分だけど、エラーを出力したり、確認画面を出したり、Smartyだけでは事足りない部分がいくつかあるからだ。
Smartyの便利なカスタム関数でラジオボタンを生成してくれるhtml_radiosとチェックボックスを生成してくれるhtml_checkboxesの使い方をメモしておく。

■html_radios、html_checkboxes共通のオプション(★多用、☆その他)

★name
フォーム要素のname属性に相当。html_checkboxesの場合は名前の後ろに[]を自動で付加して配列形式で受け取ることができるようにしてくれる。

★options(配列で与える)
value値(配列のキー)と表示する値(配列の値)の形式で与える。

★selected
初期で選択されている値(optionsのキーを指定)。html_checkboxesの場合、配列で与えると複数の項目にチェックを入れることができる。

☆separator
それぞれの項目を区切るための文字列を指定できる。<br />を指定すれば改行で区切られる。

☆valuesとoutput
optionsの代用で値と表示をそれぞれ別の配列で指定する。

テンプレート内での文字列の連結

2008/04/22 | Smarty

Smartyテンプレート内で、変数に格納された文字列の結合をしたい場合がある(つまり「変数を結合したい」のだが)。

単に文字列を結合するだけならcat修飾子でいい。
{$str1|cat:’_add’}とか{$str1|cat:$str2}とか

結合した文字列を他の処理で使いまわしたいということはないだろうか。たとえば上記の処理で得られる文字列をキーとした配列中の値を取得したいとか・・・。
そんなときにはassign関数が使えるのだが、たいていの場合は期待通りの動作をしてくれない。しかし記述方法ひとつで、しっかりと動作してくれる。それは「バッククォート(`)」だ。

例えば変数$str1と$str2を結合した$strを作りたいときはこんな具合に記述する。

{assign var=str value=”`$str1“$str2`”}

仮に$str1=’abc’、$str2=’def’だとしたら、$strは’abcdef’になる。
こういうの、マニュアルに書いてあればいいのに。

テンプレート内での分割処理

2008/04/21 | Smarty

テンプレートエンジンSmartyで、割り当てられた変数(配列)を分割するための関数を作ったのでメモ。

例えばリンク集(バナーで表示)を作るって表形式で表示したい場合、表の列数によってテンプレート内で「行の開始かどうか(<tr>タグを出力するかどうか)」「行の終了かどうか(</tr>タグを出力するかどうか)」といったロジックを書くことになる。テンプレート内でのロジックは減らしたいので、上記のように書くのはあまり好きではない。

PHPには便利な関数array_chunkというのがある。配列を指定した個数の配列に分割してくれるというものだ。さらに便利な関数でarray_padというのがある。指定個数に満たない配列を、指定した値で満たしてくれる関数だ。

一番簡単なのはコントローラ(もしくはメイン処理)で、上記の処理を入れることだが、表示を変更したい(例えば表の列数を増減したい)場合は、コントローラのプログラムを変更しなければならず、本来表示側だけで対応したいのに、本末転倒となるわけだ。

んで、Smartyの関数を作って、テンプレート内で分割できるようにした。関数はfunction.array_split.phpという名前で、以下の内容で、しかるべき場所に保存。

<?php
  function smarty_function_array_split($params, &$smarty)
  {
    $paramKey  =$params[‘var’];
    $paramValue  =$params[‘value’];
    if(is_null($paramValue)){
      $paramValue=array();
    }
    $paramSplit  =$params[‘split’];
    
    if($paramValue){
      $paramSplitted=array_chunk($paramValue,$paramSplit,true);
      $lastValue=array_pop($paramSplitted);
      $lastValue=array_pad($lastValue,$paramSplit,NULL);
      array_push($paramSplitted,$lastValue);
    }else{
      $paramSplitted=array();
    }
    $smarty->assign($paramKey,$paramSplitted);
  }

もうちょっとエラー処理を入れなくてはいけないけれど・・・。
もっと早くに関数作ればよかったな。


守谷市(まちの情報ポータル) 無料アンケートレンタルjpForm.net