SYSTEM238 / NOTES1 / Zend Framework1 / ZF1でSmartyを使う

NOTES1 PROG1
ZF1でSmartyを使う
Zend Framework1(ZF1)からSmarty3を使うためのノート。

概要

Zend_View_Interfaceを継承する方法もありますが、このノートでは違うアプローチで実現します。

Zend_View_Interfaceを拡張するのが本筋なんでしょうが、この書き方もアリかな?と個人的には思ってます。Smartyをずっと使ってきた人がZF1に移行するときはこっちの方が取っ付きやすいんじゃないかと思います。

フロントコントローラを修正する

まずやる事はフロントコントローラ(index.php)を以下のように修正してZF1のZend_Viewによるレンダリングを無効にします。

    :
    省略
    :
require_once 'Zend/Controller/Front.php';
$front = Zend_Controller_Front::getInstance();
$front->setControllerDirectory(APP_BASE_PATH. '/application/controllers');
$front->setParam('noViewRenderer', true);  //Smartyを使うので標準view機構を無効にする
$front->dispatch();

「setParam('noViewRenderer', true)」する事で標準View機構が無効になるので、あとは普通にSmartyが使えます。簡単ですね。

これだけだとなんなんで更に拡張してではZF1の標準ディレクトリ構成っぽいファイル配置ができるように、ZF1の標準のビュー使用法から違和感の少ないようにZend_Controller_ActionとSmartyを拡張してみます。

ディレクトリ構成

想定しているディレクトリ構成です。modelは説明に直接関係ないので省略しています。

/[APP_BASE_PATH]/
  ├application/
  │  ├ controllers/
  │  │ └ SmartyTest1Controller.php ... コントローラ
  │  └ view/
  │      ├ common/
  │      └ scripts/
  │         ├ smarty-test1/   ... コントローラに対応したディレクトリ
  │         │ └ index.tpl    ... アクションに対応したテンプレート
  │         └ error/
  │            └ error.tpl    ... エラーコントローラのテンプレート
  ├ index.php   ... フロントコントローラ
  ├ library/
  │  ├ MySmarty.php
  │  ├ MyZendControllerAction.php
  │  ├ Smarty/  ... Smarty-3.1.xx/libs/
  │  └ Zend/    ... ZendFramework-1.11.xx-minimal/library/Zend/
  └ temp/
     ├ cache/
     └ templates_c/

フロントコントローラ [index.php]

define('APP_BASE_PATH',       dirname(__FILE__));
define('SMARTY_TEMPLATE_DIR', APP_BASE_PATH. '/application/views/scripts');
define('SMARTY_CONFIG_DIR',   APP_BASE_PATH. '/application/views/common');
define('SMARTY_COMPILE_DIR',  APP_BASE_PATH. '/temp/templates_c');
define('SMARTY_CACHE_DIR',    APP_BASE_PATH. '/temp/cache');
define('SMARTY_EXTENSION',    'tpl');

set_include_path(get_include_path(). PATH_SEPARATOR. realpath(APP_BASE_PATH. '/library'));

require_once 'Zend/Controller/Front.php';

$front  = Zend_Controller_Front::getInstance();
$front->setControllerDirectory(APP_BASE_PATH. '/application/controllers');
$front->setParam('noViewRenderer', true);  //Smartyを使うので標準view機構を使用しない
$front->dispatch();

Zend_Controller_Action [MyZendControllerAction.php]

require_once 'MySmarty.php';
require_once 'Zend/Controller/Action.php';

class MyZendControllerAction extends Zend_Controller_Action
{
    protected $TPL;    //smarty

    /**
     * init
     */
    public function init()
    {
        $param = $this->getRequest()->getParams();

        //smarty
        $this->TPL = new mySmarty(
            SMARTY_TEMPLATE_DIR,
            $param['controller'],
            SMARTY_CONFIG_DIR,
            SMARTY_COMPILE_DIR,
            SMARTY_CACHE_DIR
        );
    }
}

Smarty [MySmarty.php]

require_once('Smarty/Smarty.class.php');

final class MySmarty extends Smarty
{
    /**
     * コンストラクタ
     * @param String $templateDir   テンプレートディレクトリ
     * @param String $controllerDir コントローラディレクトリ
     * @param String $configDir     設定&共通
     * @param String $compileDir    コンパイルディレクトリ
     * @param String $cacheDir      キャッシュ
     */
    function __construct($templateDir, $controllerDir, $configDir, $compileDir, $cacheDir)
    {
        parent::__construct();

        $this->template_dir = $templateDir. '/'. $controllerDir;
        $this->compile_id   = $controllerDir; //コンパイル済みファイル名が衝突しないためにセット
        $this->config_dir   = $configDir;
        $this->compile_dir  = $compileDir;
        $this->cache_dir    = $cacheDir;
    }

    /**
     * dispaly
     * @param String $method メソッド名(クラス名::メソッド名)
     * @param String $suffix テンプレート名の末尾付加文字
     */
    public function myDisplay($classMethod, $suffix=null)
    {
        //メッソッド名からテンプレート名を生成
        list($class, $method) = explode('::', $classMethod);
        $tplName = strtolower(ltrim(preg_replace("/([A-Z])/", "-$1", str_replace('Action', '', $method)), "-"));
        $tplName .= ($suffix)? "_{$suffix}": '';

        //errorだけテンプレートの呼出し元を変える
        if ($class == 'ErrorController') $this->template_dir = SMARTY_TEMPLATE_DIR. '/error';

        parent::display($tplName. '.'. SMARTY_EXTENSION);
    }
}

コントローラ [SmartyTest1Controller.php]

require_once 'MyZendControllerAction.php';

class SmartyTest1Controller extends MyZendControllerAction
{
    public function indexAction()
    {
        $this->TPL->assign('title', 'ZF1 & Smarty');
        $this->TPL->assign('testStr', 'こんにちは');
        $this->TPL->display(__METHOD__);
    }
}

テンプレート [index.tpl]

<html>

<head>
    <title>{$title}</title>
</head>

<body>
    {$testStr}
</body>

</html>

エラーコントローラ [ErrorController.php]

require_once 'MyZendControllerAction.php';

class ErrorController extends MyZendControllerAction
{
    public function errorAction()
    {
        $errors = $this->_getParam('error_handler');

        //エラーの種類毎にメッセージを変える
        switch ($errors->type){
            // コントローラ〜メソッドが見つからない場合
            case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ROUTE:
            case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER:
            case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ACTION:
                $this->getResponse()->setHttpResponseCode(404);
                $this->TPL->assign('title', 'Page not found');
                break;

            // その他のエラーの場合
            default:
                $this->getResponse()->setHttpResponseCode(500);
                $this->TPL->assign('title', 'Application error');
                break;
        }

        $this->TPL->assign('exception', $errors->exception);
        $this->TPL->assign('request',   var_export($errors->request, true));
        $this->TPL->myDisplay(__METHOD__);
    }
}

エラーテンプレート [error.tpl]

<!DOCTYPE html>
<html>

<head>
    <meta http-equiv="content-type" content="text/html;charset=UTF-8">
    <title>{$title}</title>
</head>

<body>
    <h1>SYSTEM ERROR:{$title}</h1>

    <div>
    <b>ErrorMessage:</b>
    <hr>
    {$exception->getMessage()|nl2br}
    </div>

    <div>
    <b>Stack trace:</b>
    <hr>
    {$exception->getTraceAsString()|nl2br}
    </div>

    <div>
    <b>Request Parameters:</b>
    <hr>
    {$request|nl2br}
    </div>
</body>

</html>