Programmer's Reference Guide

コントローラスクリプト

ビュースクリプト

コントローラが変数を代入して render() をコールすると、 指定されたビュースクリプトを Zend_View が読み込み、Zend_View インスタンスのスコープでそれを実行します。したがって、 ビュースクリプトの中で $this を参照すると、 実際には Zend_View のインスタンスを指すことになります。

コントローラからビューに代入された変数は、 ビューインスタンスのプロパティとして参照できます。例えば、 コントローラで変数 'something' を代入したとすると、 ビュースクリプト内ではそれを $this->something で取得できます (これにより、どの値がコントローラから代入されたもので、 どの値がスクリプト内部で作成されたものなのかを追いかけられるようになります)。

Zend_View の導入の部分で示したビュースクリプトの例を思い出してみましょう。

  1. <?php if ($this->books): ?>
  2.  
  3.     <!-- 本の一覧 -->
  4.     <table>
  5.         <tr>
  6.             <th>著者</th>
  7.             <th>タイトル</th>
  8.         </tr>
  9.  
  10.         <?php foreach ($this->books as $key => $val): ?>
  11.         <tr>
  12.             <td><?php echo $this->escape($val['author']) ?></td>
  13.             <td><?php echo $this->escape($val['title']) ?></td>
  14.         </tr>
  15.         <?php endforeach; ?>
  16.  
  17.     </table>
  18.  
  19. <?php else: ?>
  20.  
  21.     <p>表示する本がありません。</p>
  22.  
  23. <?php endif;?>

出力のエスケープ

ビュースクリプトで行うべき仕事のうち最も重要なもののひとつは、 出力を適切にエスケープすることです。これは、 クロスサイトスクリプティング攻撃を防ぐのを助けます。 それ自身がエスケープを行ってくれるような関数、メソッド、 あるいはヘルパーを使用しているのでない限り、 変数を出力する際には常にそれをエスケープしなければなりません。

Zend_View の escape() というメソッドが、このエスケープを行います。

  1. // ビュースクリプトの悪い例
  2. echo $this->variable;
  3.  
  4. // ビュースクリプトのよい例
  5. echo $this->escape($this->variable);

デフォルトでは、escape() メソッドは PHP の htmlspecialchars() 関数でエスケープを行います。しかし環境によっては、 別の方法でエスケープしたくなることもあるでしょう。 コントローラから setEscape() メソッドを実行することで、 エスケープに使用するコールバックを Zend_View に通知できます。

  1. // Zend_View のインスタンスを作成します
  2. $view = new Zend_View();
  3.  
  4. // エスケープに htmlentities を使用するように通知します
  5. $view->setEscape('htmlentities');
  6.  
  7. // あるいは、クラスの静的メソッドを使用するように通知します
  8. $view->setEscape(array('SomeClass', 'methodName'));
  9.  
  10. // あるいは、インスタンスメソッドを指定することもできます
  11. $obj = new SomeClass();
  12. $view->setEscape(array($obj, 'methodName'));
  13.  
  14. // そして、ビューをレンダリングします
  15. echo $view->render(...);

コールバック関数あるいはメソッドは、 エスケープする値を最初のパラメータとして受け取ります。 それ以外のパラメータはオプションとなります。

別のテンプレートシステムの使用

PHP 自身も強力なテンプレートシステムではありますが、 開発者の多くは、デザイナにとっては高機能すぎる/複雑すぎる と感じており、別のテンプレートエンジンをほしがっているようです。 Zend_View では、そのような目的のために二種類の仕組みを提供します。 ビュースクリプトを使用することによるものと、 Zend_View_Interface 実装することによるものです。

ビュースクリプトを使用したテンプレートシステム

ビュースクリプトを使用して、PHPLIB 形式のテンプレートのような 別のテンプレートオブジェクトのインスタンスを作成し、 それを操作できます。ビュースクリプトをこのように使用する方法は、 以下のようになります。

  1. include_once 'template.inc';
  2. $tpl = new Template();
  3.  
  4. if ($this->books) {
  5.     $tpl->setFile(array(
  6.         "booklist" => "booklist.tpl",
  7.         "eachbook" => "eachbook.tpl",
  8.     ));
  9.  
  10.     foreach ($this->books as $key => $val) {
  11.         $tpl->set_var('author', $this->escape($val['author']);
  12.         $tpl->set_var('title', $this->escape($val['title']);
  13.         $tpl->parse("books", "eachbook", true);
  14.     }
  15.  
  16.     $tpl->pparse("output", "booklist");
  17. } else {
  18.     $tpl->setFile("nobooks", "nobooks.tpl")
  19.     $tpl->pparse("output", "nobooks");
  20. }

関連するテンプレートファイルは、このようになります。

  1. <!-- booklist.tpl -->
  2. <table>
  3.     <tr>
  4.         <th>著者</th>
  5.         <th>タイトル</th>
  6.     </tr>
  7.     {books}
  8. </table>
  9.  
  10. <!-- eachbook.tpl -->
  11.     <tr>
  12.         <td>{author}</td>
  13.         <td>{title}</td>
  14.     </tr>
  15.  
  16. <!-- nobooks.tpl -->
  17. <p>表示する本がありません。</p>

Zend_View_Interface を使用したテンプレート

Zend_View 互換のテンプレートエンジンを使用するほうが簡単だという人もいるでしょう。 Zend_View_Interface では、 互換性を保つために最低限必要なインターフェイスを定義しています。

  1. /**
  2. * テンプレートエンジンオブジェクトを返します
  3. */
  4. public function getEngine();
  5.  
  6. /**
  7. * ビュースクリプト/テンプレートへのパスを設定します
  8. */
  9. public function setScriptPath($path);
  10.  
  11. /**
  12. * すべてのビューリソースへのベースパスを設定します
  13. */
  14. public function setBasePath($path, $prefix = 'Zend_View');
  15.  
  16. /**
  17. * ビューリソースへのベースパスを追加します
  18. */
  19. public function addBasePath($path, $prefix = 'Zend_View');
  20.  
  21. /**
  22. * 現在のスクリプトのパスを取得します
  23. */
  24. public function getScriptPaths();
  25.  
  26. /**
  27. * テンプレート変数をオブジェクトのプロパティとして代入するためのオーバーロードメソッド
  28. */
  29. public function __set($key, $value);
  30. public function __isset($key);
  31. public function __unset($key);
  32.  
  33. /**
  34. * テンプレート変数を手動で代入したり、複数の変数を
  35. * 一括設定したりします
  36. */
  37. public function assign($spec, $value = null);
  38.  
  39. /**
  40. * 代入済みのテンプレート変数を削除します
  41. */
  42. public function clearVars();
  43.  
  44. /**
  45. * $name というテンプレートをレンダリングします
  46. */
  47. public function render($name);

このインターフェイスを使用すると、 サードパーティのテンプレートエンジンをラップして Zend_View 互換のクラスを作成することが簡単になります。 例として、Smarty 用のラッパーはこのようになります。

  1. class Zend_View_Smarty implements Zend_View_Interface
  2. {
  3.     /**
  4.      * Smarty object
  5.      * @var Smarty
  6.      */
  7.     protected $_smarty;
  8.  
  9.     /**
  10.      * コンストラクタ
  11.      *
  12.      * @param string $tmplPath
  13.      * @param array $extraParams
  14.      * @return void
  15.      */
  16.     public function __construct($tmplPath = null, $extraParams = array())
  17.     {
  18.         $this->_smarty = new Smarty;
  19.  
  20.         if (null !== $tmplPath) {
  21.             $this->setScriptPath($tmplPath);
  22.         }
  23.  
  24.         foreach ($extraParams as $key => $value) {
  25.             $this->_smarty->$key = $value;
  26.         }
  27.     }
  28.  
  29.     /**
  30.      * テンプレートエンジンオブジェクトを返します
  31.      *
  32.      * @return Smarty
  33.      */
  34.     public function getEngine()
  35.     {
  36.         return $this->_smarty;
  37.     }
  38.  
  39.     /**
  40.      * テンプレートへのパスを設定します
  41.      *
  42.      * @param string $path パスとして設定するディレクトリ
  43.      * @return void
  44.      */
  45.     public function setScriptPath($path)
  46.     {
  47.         if (is_readable($path)) {
  48.             $this->_smarty->template_dir = $path;
  49.             return;
  50.         }
  51.  
  52.         throw new Exception('無効なパスが指定されました');
  53.     }
  54.  
  55.     /**
  56.      * 現在のテンプレートディレクトリを取得します
  57.      *
  58.      * @return string
  59.      */
  60.     public function getScriptPaths()
  61.     {
  62.         return array($this->_smarty->template_dir);
  63.     }
  64.  
  65.     /**
  66.      * setScriptPath へのエイリアス
  67.      *
  68.      * @param string $path
  69.      * @param string $prefix Unused
  70.      * @return void
  71.      */
  72.     public function setBasePath($path, $prefix = 'Zend_View')
  73.     {
  74.         return $this->setScriptPath($path);
  75.     }
  76.  
  77.     /**
  78.      * setScriptPath へのエイリアス
  79.      *
  80.      * @param string $path
  81.      * @param string $prefix Unused
  82.      * @return void
  83.      */
  84.     public function addBasePath($path, $prefix = 'Zend_View')
  85.     {
  86.         return $this->setScriptPath($path);
  87.     }
  88.  
  89.     /**
  90.      * 変数をテンプレートに代入します
  91.      *
  92.      * @param string $key 変数名
  93.      * @param mixed $val 変数の値
  94.      * @return void
  95.      */
  96.     public function __set($key, $val)
  97.     {
  98.         $this->_smarty->assign($key, $val);
  99.     }
  100.  
  101.     /**
  102.      * empty() や isset() のテストが動作するようにします
  103.      *
  104.      * @param string $key
  105.      * @return boolean
  106.      */
  107.     public function __isset($key)
  108.     {
  109.         return (null !== $this->_smarty->get_template_vars($key));
  110.     }
  111.  
  112.     /**
  113.      * オブジェクトのプロパティに対して unset() が動作するようにします
  114.      *
  115.      * @param string $key
  116.      * @return void
  117.      */
  118.     public function __unset($key)
  119.     {
  120.         $this->_smarty->clear_assign($key);
  121.     }
  122.  
  123.     /**
  124.      * 変数をテンプレートに代入します
  125.      *
  126.      * 指定したキーを指定した値に設定します。あるいは、
  127.      * キー => 値 形式の配列で一括設定します
  128.      *
  129.      * @see __set()
  130.      * @param string|array $spec 使用する代入方式 (キー、あるいは キー => 値 の配列)
  131.      * @param mixed $value (オプション) 名前を指定して代入する場合は、ここで値を指定します
  132.      * @return void
  133.      */
  134.     public function assign($spec, $value = null)
  135.     {
  136.         if (is_array($spec)) {
  137.             $this->_smarty->assign($spec);
  138.             return;
  139.         }
  140.  
  141.         $this->_smarty->assign($spec, $value);
  142.     }
  143.  
  144.     /**
  145.      * 代入済みのすべての変数を削除します
  146.      *
  147.      * Zend_View に {@link assign()} やプロパティ
  148.      * ({@link __get()}/{@link __set()}) で代入された変数をすべて削除します
  149.      *
  150.      * @return void
  151.      */
  152.     public function clearVars()
  153.     {
  154.         $this->_smarty->clear_all_assign();
  155.     }
  156.  
  157.     /**
  158.      * テンプレートを処理し、結果を出力します
  159.      *
  160.      * @param string $name 処理するテンプレート
  161.      * @return string 出力結果
  162.      */
  163.     public function render($name)
  164.     {
  165.         return $this->_smarty->fetch($name);
  166.     }
  167. }

この例では、Zend_View ではなく Zend_View_Smarty クラスのインスタンスを作成し、 それを使用して Zend_View と同じようなことをしています。

  1. //例 1. InitializerのinitView()で
  2. $view = new Zend_View_Smarty('/path/to/templates');
  3. $viewRenderer =
  4.     Zend_Controller_Action_HelperBroker::getStaticHelper('ViewRenderer');
  5. $viewRenderer->setView($view)
  6.              ->setViewBasePathSpec($view->_smarty->template_dir)
  7.              ->setViewScriptPathSpec(':controller/:action.:suffix')
  8.              ->setViewScriptPathNoControllerSpec(':action.:suffix')
  9.              ->setViewSuffix('tpl');
  10.  
  11. //例 2. アクションコントローラでも同様に...
  12. class FooController extends Zend_Controller_Action
  13. {
  14.     public function barAction()
  15.     {
  16.         $this->view->book   = 'Zend PHP 5 Certification Study Guide';
  17.         $this->view->author = 'Davey Shafik and Ben Ramsey'
  18.     }
  19. }
  20.  
  21. //例 3. アクションコントローラでのビューの初期化
  22. class FooController extends Zend_Controller_Action
  23. {
  24.     public function init()
  25.     {
  26.         $this->view   = new Zend_View_Smarty('/path/to/templates');
  27.         $viewRenderer = $this->_helper->getHelper('viewRenderer');
  28.         $viewRenderer->setView($this->view)
  29.                      ->setViewBasePathSpec($view->_smarty->template_dir)
  30.                      ->setViewScriptPathSpec(':controller/:action.:suffix')
  31.                      ->setViewScriptPathNoControllerSpec(':action.:suffix')
  32.                      ->setViewSuffix('tpl');
  33.     }
  34. }

コントローラスクリプト

Comments

Not saying that we need to be spoon fed, but ZF isn't exactly the easiest thing in the world to configure when you're trying to do anything custom. So a little better documentation of how to integrate Smarty would really be appreciated. Your documentation should be the defacto standard when it comes to current information, but when you need something custom, you have to Google it -- and good luck with that when A) all the information is spread out over all the different past versions of ZF, and B) no one will every agree on the right way to do something in ZF since there's so many ways to do it.
Where should i put Zend_View_Smarty class file?
Please let me know.
Step one: Don't use smarty.
Actually, after years of development of live projects on ZF, there are a number or reasons to use different template engines, and development code in ZF2 Zend_View reflects this.

We currently support Smarty, Xtemplate, Textile, PHP, XSLT, and some others for our different users. Compiled templates are stored in a LFU memory cache.

After refactoring over a couple of years, the optimized way seems to be to put the template compiling code into a controller action helper, that way you can call it from any of your controllers, as you need it. Here is a modified version of our live code, w/o all the cloud/cache/sync stuff in it:


define('LFU_CACHE_DIR','/tmpfs_mount');  
define('MY_PLUGINS_DIR','/yourpath');

//path supports Smarty svn version
require_once ('smarty/Smarty.class.php');

//this class wraps Smarty, so you can customize if you need to
class My_Smarty extends Smarty {
    function __construct() {
        parent::__construct ();
        $this->template_dir = array (LFU_CACHE_DIR . DIRECTORY_SEPARATOR . 'templates' . DIRECTORY_SEPARATOR );
        $this->compile_dir = LFU_CACHE_DIR . DIRECTORY_SEPARATOR . 'templates_c' . DIRECTORY_SEPARATOR;
        //if needed: $this->addPluginsDir(MY_PLUGINS_DIR);
        $this->cache_dir = LFU_CACHE_DIR . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR;
    }
}

//standard ZF stuff
class ASF_Controller_Action_Helper_ObjectHelper extends Zend_Controller_Action_Helper_Abstract{
        //$template, $data, $type--from controller code (we use $template and $type from database record, $data from models)
    public function direct($template, $params = array(), $type = 'smarty') {
                //doing switch here to enable support other template engines
        try {
            switch ($type) {
                //just the Smarty code here, likewise for the rest of the template engines
                case 'smarty' :
                    $st = new My_Smarty ();
                    foreach ( $params as $k => $v ) {
                        $st->assign ( $k, $v );
                    }
                    $output = $st->fetch ( 'eval:' . $template );
                    break;
                default : //create a Zend_View and write out template at phtml to use
                    $view = new Zend_View ();
                    //you may want to replace this hack with cache stuff, we do
                    $filename = md5($template).'.phtml';
                    file_put_contents (  LFU_CACHE_DIR . DIRECTORY_SEPARATOR . $filename, $template );
                    //end hack
                    $view->setScriptPath ( LFU_CACHE_DIR . DIRECTORY_SEPARATOR );
                    foreach ( $params as $k => $v ) {
                        $view->$k = $v;
                    }
                    $output = $view->render ( $filename );
                    break;
            
            }
        } catch ( Exception $e ) {
            $output = $e->getMessage ();
        }
        $this->getResponse ()->appendBody ( $output );
    }
}
There are some things wrong with the viewscript.. it should be viewscript as scriptname and not script..

Also it is passed as element and not as $this->form

$form->setDecorators(array(
array('ViewScript',
array(
'viewScript' => '_forms/bulk.phtml',
)
)
));

+ Add A Comment

Please do not report issues via comments; use the ZF Issue Tracker.

If you have a JIRA/Crowd account, we suggest you login first before commenting.

  • BBCode is allowed in the comment markup

  • Select a Version

    Languages Available

    Components

    Search the Manual