Zend Framework と Smarty と Layout 機能その2

前回の続き。

Smarty での Layout 機能の使用方法は今回はウノウラボで紹介されている方式を使う。
つまりコンンテンツファイルを fetch メソッドを使用して、
取得したコンテンツを Layoutのテンプレートにアサインする。

Zend Framework と連携

Zend FrameworkSmarty との連携は Zend_Controller_Action_Helper_ViewRenderer() を使用する。
Zend Framework と Smarty を連携 - Memo を参照。
※ ViewRender を使用しなくても出来るけど。。。

ブートストラップ

<?php
// $this->_smartyConfig には template_dir などの Smarty の設定値が入っている
$view = new Smarty_View(null, $this->_smartyConfig);
$viewRender = new Zend_Controller_Action_Helper_ViewRenderer();
$viewSuffix = 'tpl';
$viewRender->setView($view)
                       ->setViewSuffix($viewSuffix);
Zend_Controller_Action_HelperBroker::addHelper($viewRender);

まずはブートストラップファイルで Smartyインスタンスを生成し、
各種 Smarty の設定を行う。

コントローラ

コントローラでの流れは以下のようになる。

  • init() でコンテンツとなるテンプレートを取得する
  • postDispatch() で取得したコンテンツを Layout のテンプレートにアサインする
  • Layout テンプレートを fetch し表示する。
<?php
class My_Controller_Action extends Zend_Controller_Action
{
    protected $_request;
    protected $_module;
    protected $_controller
    protected $_dirs;
    protected $_controllerPath;
    protected $_action;
    protected $_layout;
    protected $_contents;    

    /**
     * init
     * 
     * @access public
     * @return void
     */
    public function init()
    { 
        $this->_request             = $this->getRequest();
        // 現在のモジュール名
        $this->_module             = $this->_request->getModuleName();
        // 現在のコントローラ名
        $this->_controller         = $this->_request->getControllerName();
        // コントローラのパス
        $this->_dirs                   = $this->getFrontController()->getControllerDirectory(); 
        // モジュール名をキーにコントローラのパスを取得する
        $this->_controllerPath = $this->_dirs[$this->_module];
        // 現在のアクション名
        $this->_action               = $this->_request->getActionName();

         // レイアウトのパスを設定する
         // root のパス(本来はブートストラップで設定して、Zend_Registry に保存している)
         $rootDir = "ルートディレクトリのパス";
         $layout = "Layout ファイルのあるディレクトリパス";
         
         // コンテンツファイルのパス
         $this->_contents = $root . $this->_module . '/view/' . $this->_controller . '/' . $this->_action . '.tpl';
         // 自動的にレンダリングしないようにする
         $this->_helper->viewRenderer->setNoRender();
    }
    /**
     * postDispatch 
     * 
     * @access protected
     * @return void
     */
    public function postDispatch()
    {   
        parent::postDispatch();
        $contents   = $this->view->render($this->_contents);
        
        $this->view->setScriptPath($layout);
        $this->view->assign('contents', $contents);
        //echo $this->view->render($layout);
        $this->getResponse()
            ->setBody($this->view->render($layout));
    }
}

コントローラの init() でLayout テンプレートのファイルを取得し、
属性に保持する。同じくコンテンツのテンプレートも取得して、
属性に保持する。

Zend_Controller_Action_Helper_ViewRenderer() を使用すると、
自動的に /モジュール名/views/コントローラ名/ が
Smarty オブジェクトの templates_dir に設定される。


その為このままだと、Layout テンプレートが表示されず、
コンテンツのテンプレートが表示されてしまうので、
$viewRenderer->setNoRender() を使用し、自動レンダリング
オフにする。


自動レンダリングがオフになったので、postDispatch() で
レンダリングする必要がある。で、レンダリングする前に、
setScriptPath() で Layout テンプレートを指定し、取得した
コンテンツをアサインすれば良い。
そして、echo でレンダリングしてやる。

ちなみに、各コントローラで値をアサインすると、
コンテンツの方のテンプレートに値がアサインされる。


今回あげた例では色々省略してあるけど、実際には Layout の
場所を各コントローラと同一のディレクトリに layout という
ディレクトリを作り、そこに コントローラ独自で使用する場合の
Layout を設置している。

また、各コントローラごとではなく、もっとグローバルに使いたい
場合もあるだろうから、その場合は、共通の Layout ファイルを
設置するディレクトリ作っている。

コントローラ独自の Layout を使用したい場合は、
コントローラで、setLayout('ファイル名'); とすれば、
Layout ファイルを置き換えるようにしている。


ちょっと泥臭いやりかたになってしまったけど、やりたいことが実現できたので良いかw


※ 2007/12/24 14:54 追記
レンダリングの方法が間違ってたので修正。
詳しくは、Zend Framework で Smarty をレンダリングする方法 - Memo 参照。。。