Smarty を ZendFramework の View として利用する(旧)

※この記事は内容が古くなっています。同様の新しい手法は下記ページを参考にしてください。
SmartyをZendFrameworkのビューとして利用する

ZendFrameworkとSmartyのインストール

PHPのテンプレートエンジンとしてかなりメジャーな Smarty を ZendFramework のView として設定するまでの手順を記していきたいと思います。

ZendFrameworkとSmartyのインストール方法は下記の記事を参考に行ってください。
ZendFrameworkのインストール
Smartyのインストール

まず、以下のようなディレクトリ構成でZendFramework とSmarty をインストールします。
パーミッションの変更が必要なディレクトリは application/smarty/cache と application/smarty/templates_c のふたつです。これらは 777 に設定してください。

-application/
  |-controllers/ (アクションコントローラ格納ディレクトリ)
  |-smarty/
     |-cache/       777
     |-config/
     |-templates/
     |-templates_c/ 777
-lib/
-html/(ドキュメントルート)

Smartyラッパークラスの作成

ZendFramework では Zend_View というビュークラスが標準で用意されています。
コントローラがリクエストを処理して適宜変数をセットして、指定されたビュースクリプトを Zend_View が読み込んで出力するという流れになっています。
今回はこのZend_View に互換性を持たせたクラスを作成し、そのクラスにSmartyを組み込んでいくことになります。

ZendFrameworkでは、Zend_View_Interface という、Zend_View との互換性を保ったクラスを作成するための最低限必要なインターフェイスが用意されています。
つまり、Zend_View互換のクラスを定義する場合はこのZend_View_Interfaceが実装されている必要があります。

Zend_View_Interface のメソッドは下表の通りです。

getEngine()テンプレートエンジンオブジェクトを返す
setScriptPath($path)ビュースクリプト/テンプレートへのパスを設定
setBasePath($path, $prefix = 'Zend_View')すべてのビューリソースへのベースパスを設定
addBasePath($path, $prefix = 'Zend_View')ビューリソースへのベースパスを追加
getScriptPaths()現在のスクリプトのパスを取得
assign($spec, $value = null)テンプレート変数を手動で代入したり、複数の変数を一括設定したりする
clearVars()代入済みのテンプレート変数を削除
render($name)指定したテンプレートをレンダリング

第12回 Smartyとフレームワーク(その2:Zend Framework編) - Smarty講座

ZendFrameworkの公式ドキュメントにSmartyのラッパクラスがあるので、今回はそれをそのまま利用します。

Zend_View_Smarty.class.php
<?php
class Zend_View_Smarty implements Zend_View_Interface
{
  /**
   * Smarty object
   * @var Smarty
   */
  protected $_smarty;

  /**
   * コンストラクタ
   *
   * @param string $tmplPath
   * @param array $extraParams
   * @return void
   */
  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;
      }
  }

  /**
   * テンプレートエンジンオブジェクトを返します
   *
   * @return Smarty
   */
  public function getEngine()
  {
      return $this->_smarty;
  }

  /**
   * テンプレートへのパスを設定します
   *
   * @param string $path パスとして設定するディレクトリ
   * @return void
   */
  public function setScriptPath($path)
  {
      if (is_readable($path)) {
          $this->_smarty->template_dir = $path;
          return;
      }

      throw new Exception('無効なパスが指定されました');
  }

  /**
   * 現在のテンプレートディレクトリを取得します
   *
   * @return string
   */
  public function getScriptPaths()
  {
      return array($this->_smarty->template_dir);
  }

  /**
   * setScriptPath へのエイリアス
   *
   * @param string $path
   * @param string $prefix Unused
   * @return void
   */
  public function setBasePath($path, $prefix = 'Zend_View')
  {
      return $this->setScriptPath($path);
  }

  /**
   * setScriptPath へのエイリアス
   *
   * @param string $path
   * @param string $prefix Unused
   * @return void
   */
  public function addBasePath($path, $prefix = 'Zend_View')
  {
      return $this->setScriptPath($path);
  }

  /**
   * 変数をテンプレートに代入します
   *
   * @param string $key 変数名
   * @param mixed $val 変数の値
   * @return void
   */
  public function __set($key, $val)
  {
      $this->_smarty->assign($key, $val);
  }

  /**
   * empty() や isset() のテストが動作するようにします
   *
   * @param string $key
   * @return boolean
   */
  public function __isset($key)
  {
      return (null !== $this->_smarty->get_template_vars($key));
  }

  /**
   * オブジェクトのプロパティに対して unset() が動作するようにします
   *
   * @param string $key
   * @return void
   */
  public function __unset($key)
  {
      $this->_smarty->clear_assign($key);
  }

  /**
   * 変数をテンプレートに代入します
   *
   * 指定したキーを指定した値に設定します。あるいは、
   * キー => 値 形式の配列で一括設定します
   *
   * @see __set()
   * @param string|array $spec 使用する代入方式 (キー、あるいは キー => 値 の配列)
   * @param mixed $value (オプション) 名前を指定して代入する場合は、ここで値を指定します
   * @return void
   */
  public function assign($spec, $value = null)
  {
      if (is_array($spec)) {
          $this->_smarty->assign($spec);
          return;
      }

      $this->_smarty->assign($spec, $value);
  }

  /**
   * 代入済みのすべての変数を削除します
   *
   * Zend_View に {@link assign()} やプロパティ
   * ({@link __get()}/{@link __set()}) で代入された変数をすべて削除します
   *
   * @return void
   */
  public function clearVars()
  {
      $this->_smarty->clear_all_assign();
  }

  /**
   * テンプレートを処理し、結果を出力します
   *
   * @param string $name 処理するテンプレート
   * @return string 出力結果
   */
  public function render($name)
  {
      return $this->_smarty->fetch($name);
  }
}

Zend Framework: Documentation: ビュースクリプト - Zend Framework Manual

このZend_View_Smarty.phpはlibディレクトリに保存します。

フロントコントローラでの処理

フロントコントローラ(index.php)には下記のように記述します。

index.php
setControllerDirectory(APP . 'controllers');
$view = new Zend_View_Smarty(
    SMARTY_PATH . 'templates', array(
        'compile_dir' => SMARTY_PATH . 'templates_c',
        'config_dir'  => SMARTY_PATH . 'configs',
        'cache_dir'   => SMARTY_PATH . 'cache',
    )
);
$viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper
('ViewRenderer');
$viewRenderer->setView($view)
             ->setViewBasePathSpec($view->getEngine()->template_dir)
             ->setViewScriptPathSpec(':controller/:action.:suffix')
             ->setViewScriptPathNoControllerSpec(':action.:suffix')
             ->setViewSuffix('tpl');

$front->dispatch();

スクリプトの実行

上記の用にSmartyラッパークラスの定義とフロントコントローラでの処理の記述が完了したら、アクションコントローラと今回Smartyのテンプレートディレクトリとして指定したディレクトリにテンプレートを用意します。

今回は、application/smarty/templates/index ディレクトリに以下のテンプレートファイルを設置しました。

index.tpl
<!DOCTYPE HTML>
<html lang="ja">
<head>
	<meta charset="UTF-8">
	<title>Smarty Test</title>
</head>
<body>
	{$str}
</body>
</html>

アクションスクリプトでは変数に適当な値を代入しています。

IndexController.php
<?php
require_once 'Zend/Controller/Action.php';

class IndexController extends Zend_Controller_Action{
    public function indexAction() {
        $this->view->str = 'Hello Smarty';
    }
}

これでブラウザからスクリプトにアクセスすると、'Hello Smarty'と表示されます。


最終更新 2010-06-09

この記事へのコメント

  1. こんばんは。ちょっとおせっかいを。
    Zend with Smarty、結構旬なんですかね。
    上記内容は間違いなく動作する方法ですが、
    Zend_Viewの設計思想を無視していますので
    「これで逝けます」的モノではないです。
    公式マニュアルに堂々と記載されてるリファレンス実装なのに、Zend_LayoutやZend_Formなど、同じZendの他コンポーネントと連携できないという優れモノ。。。
    
    私もまだ検証中ですが、ちゃんと使えるようにするにはZend_ViewとZend_View_Streamを拡張することになるはずです。
    興味と時間があったら、Zend_Viewのレンダリングが本来どのように行われているか調べてみると面白いですよ。

    投稿者 : みなと  |  投稿日時 : 

  2. >みなとさん
    
    コメントいただきまして誠にありがとうございます。
    コメント内容、興味深く拝見させていただきました。
    
    >公式マニュアルに堂々と記載されてるリファレンス実装なのに、Zend_LayoutやZend_Formなど、同じZendの他コンポーネントと連携できないという優れモノ。。。
    
    Zend Frameworkについては最近勉強を開始したばかりで明るくはないですが、参考書などを流し読みしていると、みなとさんが仰るような「他コンポーネントと連携できない」類のものが何点かあるみたいですね。
    
    >Zend_Viewの設計思想
    このあたりを一度詳しく調べて理解する必要がありそうです。

    投稿者 : 管理人  |  投稿日時 : 

  3. こんにちは。検証終わりました。
    stream使わなくてもいいし...orz
    結論をいうとZend_View_Smarty.class.phpで明らかにマズいのは2箇所だけのようです。
    ・Zend_View_Smarty::getEngineでSmartyを返している
    ・Zend_View_Smarty::renderでSmarty::renderを呼んでいる
    
    互換性は気にしないとか、layoutもformも使わないとか、actionControllerでecho使うのは邪道だとかゆう人には関係ない話ですけどね…

    投稿者 : みなと  |  投稿日時 : 

  4. みなとさん、お疲れ様です。
    
    コメント内容非常に参考になります。
    個人的には互換性重視でいきたいと思ってますので、みなとさんからいただいたコメントを手がかりにさせていただき、他のコンポーネントとの連携がしっかりできるクラスを実装したいですね。
    
    自分はまだZendFrameworkを勉強し始めて日が浅く、Zend_LayoutやZend_Formもまだ使ったことはないですが、少しずつ慣れていきたいと思っています。
    
    今後ともよろしくお願い申し上げます。

    投稿者 : 管理人  |  投稿日時 : 

カテゴリー

その他



スポンサードリンク