• [Zend Framework] [php]独自のZend_Viewのビューヘルパーの作り方②

    前回で独自のビューヘルパークラスを作る方法がわかったので、今回は実際に作ることにします。 作るヘルパーの内容は、自分も普段よく使っているもので、出力しようとする文字列の長さが指定したものより長い場合に、指定した長さで文字列を切り取って表示する処理を行うものです。 たとえば、「あいうえおかきくけこさしすせそ」という入力があり、最大の文字列長を10文字と指定した場合には、「あいうえおかきくけこ…」として出力されるような処理です。名前はstrcutとしておきます。 ヘルパーはビュースクリプトで以下のように使います。``` < ?php echo $this->strcut($this->text, 10) ?> 早速作ってみます。 strcut.phpというファイルに以下のようにクラスを定義します。 < ?php class Wads_View_Helper_Strcut { public function strcut($str, $len, $omit=’…') { if(!is_string($str)) { $str = (string)$str; } $str = htmlspecialchars($str, ENT\_QUOTES); if((int)$len > 0 && mb\_strlen($str) > (int)$len) { $str = mb\_substr($str, 0, $len-1); if(is\_string($omit) && $omit != "") { $str .= htmlspecialchars((string)$omit, ENT\_QUOTES); } } return $str; } } クラス名のプレフィックスとしてWads\_View\_Helperをつけました。ヘルパーと同じ名前のpublic関数を定義して、この関数内ではechoなどで出力せず、切り取った文字をエスケープして返しています。これで[前回書いたビューヘルパーを作るためのルール](http://wadslab.net/2008/07/zend_view/)すべてをみたしたことになります。 ビューヘルパーの第1引数には出力する文字を、第2引数には切り取る文字列の長さを、第3引数にはもし文字列を切り取った場合に、最後に付加する省略をあらわす文字列を指定します。第3引数は省略できます。 あとはこのファイルがあるディレクトリをスクリプトパスに追加するだけです。たとえば、コントローラ内で $this->view->setHelperPath('/path/to/helpers’, ‘Wads_View_Helper’); のようにセットできます。 以上で最初に書いたように、ビュースクリプト内で < ?
  • [Zend Framework][php] 独自のZend_Viewのビューヘルパーの作り方①

    独自のZend_Viewのビューヘルパーはいくつかのルールをみたせば簡単に作ることができます。 ヘルパー名とビューヘルパーのクラス名の最後の部分は同じにする(ただしMixedCaps方式) ビューヘルパーのクラスにはヘルパー名と同じ名前のpublicメソッドが定義されている メソッド内ではechoとかprintを行ってはいけない。printやechoされる内容をエスケープして返す クラスはヘルパーと同じ名前のファイルに作成する fooというヘルパーを作ると仮定して、上記についてひとつずつ説明します。 1. ヘルパー名とビューヘルパーのクラス名の最後の部分は同じにする fooというヘルパーを作る場合、クラス名の最後にはFooという名前がないといけません。また、クラス名には「_(アンダースコア)」区切りでプレフィックスをつけることができます。というわけで、クラス名の最後にという表現になっています。``` class Foo class My_Foo class My_View_Helper_Foo はどれもクラス名としてOKです。2番目の例だとMyが、3番目の例だとMy\_View\_Helperがプレフィックスになります。 ただし、プレフィックスにはView\_Helperを含めることが推奨されているので、2番目よりも3番目の名前のほうがいいです。 **2\. ビューヘルパーのクラスにはヘルパー名と同じ名前のpublicメソッドが定義されている** つまりこういうことです class My_View_Helper_Foo { … public function foo($input) { … } … } **3\. メソッド内ではechoとかprintを行ってはいけない。printやechoされる内容をエスケープして返す** ビューヘルパー内で出力するのではなく、ビュースクリプトにて < ?php echo $this->foo($this->name); ?> のように出力するようにします。クラスのメソッド内では、エスケープ済みの結果を返すようにするだけです。 class My_View_Helper_Foo { … public function foo($input) { … return htmlspacealchars($output) } … } **4\. クラスはヘルパーと同じ名前のファイルに作成する** 今回の場合は、Foo.phpというファイルにクラスを定義します。 以上の条件をみたしていれば、ビューヘルパーのパスのどこかにファイルを置いておくだけで自動的に読み込み、インスタンス化してくれます。ビューヘルパーのパスを追加するには、Zend\_ViewクラスのsetHelperPath()を使います。 $view = new Zend_View(); $view->setHelperPath('/path/to/helpers’, ‘My_View_Helper’); ?> パスは既存のパスにスタックのように積み重ねられていきます。つまり後から追加されたパスが先に検索されることになります。 setHelperPath()の第2引数ではビューヘルパーのプレフィックスを指定できます(最後の_は省略可です)。もし指定しない場合はデフォルトで’Zend_View_Helper_‘がプレフィックスとなります。
  • [Zend Framework] Zend_ControllerのContextSwitchアクションヘルパーでZend_View_Interfaceが使えない件

    Zend Framework1.5から新しく追加されたZend_ControllerのContextSwitchアクションヘルパーを使ってJSON形式でレスポンスを返そうとしたところ、``` Fatal error: Call to undefined method Lib_ViewSmarty::getVars() in … というエラーが出ました。確かに[ここ](http://framework.zend.com/manual/ja/zend.view.scripts.html#zend.view.scripts.templates.interface)を参考に作ったSmartyのラッパーにはそのような関数はありません。そもそもZend\_View\_Interfaceにそういう関数のインターフェースがないのです。ということで少々Smartyラッパーに手を加えないといけません。 Zend\_View\_AbstractにはちゃんとgetVars()というものがあるので、これを見ることにします。 public function getVars() { $vars = get_object_vars($this); foreach ($vars as $key => $value) { if ('_’ == substr($key, 0, 1)) { unset($vars[$key]); } } return $vars; } この関数では、設定された(assign()された)値をすべて返しているようです。 処理的には、Zend\_Viewクラスのプロパティーをすべて取得して、'\_'で始まるプロパティーを排除しています。このクラスに設定されているプロパティは、もともとクラスに備わっているプロパティとviewに出力する値として設定された(assign()された)プロパティの2種類があります。 前者は'\_'で始まりますのでこれらを排除して、後者の値のみを返す処理になっています。初めて知ったのですが、assign()では、設定する値の名前が'\_'で始まる場合にはExceptionをスローする仕組みになっているので、このgetVars()の設定が可能になるのです。 public function assign($spec, $value = null) { // which strategy to use? if (is_string($spec)) { // assign by name and value if ('_’ == substr($spec, 0, 1)) { require_once ‘Zend/View/Exception.
  • [Zend Framework] Zend_ControllerへSmarty組み込む (続きの続き)

    前回デフォルトのmodifierを設定して、出力に対して自動的にエスケープ処理を行うように設定したのですが、urlエンコードをかけたいときは``` {$hello|smarty:nodefaults|escape:“url”} ### Smarty自作のmodifier で、前回設定したmodifierは自作もできるので、オリジナルで作ってそれをデフォルト設定することにしました。通常はhtmlspecialchars()でエスケープをかけて、ある特定の条件でアサインされた値にはrawurlencode()でURLエンコード処理行うようにします。ちなみに、{$foo|escape:"html"}とした場合にはhtmlspecialchars()で、{$foo|escape|"url"}とした場合にはrawurlencode()でそれぞれエスケープ処理がなされます。 ある特定の条件でというところが迷ったのですが、足りない頭でいろいろ考えた結果、今回はアサインされた値の先頭に特定の文字列があった場合に別のエスケープ処理を施すという方法になりました。%xxx%のように%で囲まれた文字列が先頭にあった場合に、xxxに対応するエスケープ処理を施すという内容です。 アサインされた文字が"foo"の場合 →"foo"に対してhtmlspecialchars()処理を行う アサインされた文字が"%url%foo"の場合 →%url%を切り取った"foo"に対してrawurlencode()処理を行う ### 自作modifierのつくり方 ファイル名はmodifierを含めたプラグインの命名規則に従って付与します。``` < プラグインの型>.<modifier の名前>.php ```プラグインの型はmodifierとなります。プラグインの名前は適当なものを付けます。ここでつけた名前はテンプレートでmodifierを指定するときの名前になります。``` {$foo|escape:"html"} ```ならば、modifierプラグインのファイル名は``` modifier.escape.php ```です。今回はsanitizeというmodifier名にしますので、ファイル名は``` modifier.sanitize.php ```とします。 このファイルをSmarty.class.phpのあるディレクトリのpluginsディレクトリ内に配置してください。もし任意の場所にファイルを配置したい場合は、Smartyのパラメタであるplugins\_dirを設定する必要があります。前出のpluginsディレクトリに加えて、カレントディレクトリ内にあるtestというディレクトリを追加したい場合は以下のようになります(前回、前々回に作ったViewSmartyクラスを想定しています)。``` $this->\_smarty->plugins\_dir=array("plugins", "test"); ※絶対パスでの指定も可能です ```modifier.sanitize.phpには以下の命名規則で関数を定義します。``` function smarty\_modifier\_<modifier 名>(処理対象の値, \[パラメータ1, ...\]) ```modifier名はsanitizeになります。処理対象の値は、通常はアサインされた値で、パラメタは{$foo|sanitize:param1:param2}のparam1、param2の部分になります。今回作成するmodifierではパラメタがないので、``` function smarty\_modifier\_sanitize($string) ```という関数を定義することになります。 以上で自作のmodifierプラグインの作り方は終わりです。 今回作るmodiferの関数の定義は以下のようになります。``` <?php define("SANITIZE\_TYPE", '/%(w+)%/'); function smarty\_modifier\_sanitize($string) { $split = preg\_split(SANITIZE\_TYPE, $string, 2, PREG\_SPLIT\_NO\_EMPTY|PREG\_SPLIT\_DELIM\_CAPTURE); if(count($split) == 2) { switch ($split\[0\]) { case 'url': return rawurlencode($split\[1\]); } } return htmlspecialchars($string, ENT\_QUOTES); } ```これでmodifierは完成です。SANITIZE\_TYPEを変更することで、値の前につける文字列のパターンを変更でき、%xxx%のxxxの部分をcaseに追加することでエスケープの種類を追加することができます。 ### テスト では実際にデータが処理されるか確認してみます。以下のようなデータを用いて検証します。``` $url = "http://wadslab.
  • [Zend Framework] Zend_ControllerへSmarty組み込む (続き)

    前回SmartyをZend_Controllerへ組み込みましたが、このままでは出力はエスケープされません。Smartyでの出力のエスケープ処理は以下のようになります。``` {$hello|escape:“html”} * 面倒くさい * ものにもよるけど、エスケープすべき出力のほうが多いのではないか? * エスケープのもれが怖い などの理由で(特に1番最後)、デフォルトで出力のエスケープをするように設定しておいたほうが安心です。 対応は簡単です。 コンストラクタでdefault\_modifiersというSmarty変数に'escape:"html"'を設定するだけです。``` require\_once 'Zend/View/Interface.php'; require\_once 'Smarty/Smarty.class.php'; class ViewSmarty implements Zend\_View\_Interface { protected$\_smarty; public function \_\_construct($tmplPath = null, $extraParams = array()) { $this->\_smarty = new Smarty; if (null !== $tmplPath) { $this->setScriptPath($tmplPath); } foreach ($extraParams as $key => $value) { $this->\_smarty->$key = $value; } // ↓これ $this->\_smarty->default\_modifiers=array('escape:"html"'); } ... } ```では確認してみましょう。 コントローラの内容``` class FooController extends Zend\_Controller\_Action { public function indexAction() { $this->view->hello = "<strong>Hello World</strong>"; } } ```ビューの内容``` hello {$hello} ```出力は以下のようになりました。<strong>タグがエスケープされているので、強調表示されていません。``` **Hello World** ```HTMLのソースは以下のとおり。成功です。``` <strong>Hello World</strong> ```エスケープしたくないところでは以下のように書けばOKです。``` {$hello|smarty:nodefaults}
  • [Zend Framework][Smarty] Zend_ControllerへSmarty組み込む

    Zend_ViewでSmartyを使う方法は、このページを参考に、Zend_View_Interfaceを実装して、最低限Smartyのプロパティである$template_dirと$compile_dirを設定してあげれば使えます。``` require_once ‘Zend/View/Interface.php’; require_once ‘Smarty/Smarty.class.php’; class ViewSmarty implements Zend_View_Interface { … } 上記のようなviewクラスを作ったら、以下のように初期化します。 // プロパティの設定 $templete_dir = “path/to/tmplete/dir”; $opt = array( “compile_dir"=>"path/to/compile/dir” ); $view = new ViewSmarty($tmplete_dir, $opt); // 以下のような設定も可能 //$opt = array( // “templete_dir” => “path/to/tmplete/dir”, // “compile_dir” => “path/to/compile/dir” //); //$view = new ViewSmarty(null, $opt); 以下のように変数をアサインして画面を描画します。 $view->foo = “foo”; $view->assign(“bar”, “bar”); $view->render(“hello.phtml”); ViewSmartyクラスをViewRendererアクションヘルパーに組み込む法方は以下のとおりです。 $viewRenderer = new Zend_Controller_Action_Helper_ViewRenderer(new My_View_Smarty(null, $option)); Zend_Controller_Action_HelperBroker::addHelper($viewRenderer); これでviewRendererでSmartyを使えるようになりました。 **2008/4/2追記** Zend Framework 1.5 でリファレンスマニュアルのSmartyラッパーの例をそのまま使うと、エラーが出る場合があるので[こちら](http://wadslab.net/2008/04/zend_view_smarty-4/)もご覧ください。 私は以下のようなviewを使っています。 require_once ‘Zend/View/Interface.