Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

Zend FrameworkでのViewクラスの差替・拡張方法まとめ

More than 5 years have passed since last update.

Zend FrameworkはデフォルトではZend_Viewというテンプレートエンジンを使用します。(正確に言うと素のPHPに足りない便利関数集といった感じ。)

SmartyやTwigといったテンプレートエンジンを連携させる場合など、Zend_View以外を使いたい場合のやり方をまとめてみます。

拡張方法の選択

Zend Frameworkは拡張方法がたくさん用意されているフレームワークです。 まずはどう拡張するのかを検討 します。

Viewヘルパーをまず検討

単純な機能拡張であれば、Viewヘルパーを作れないか検討しましょう。要は「関数が足りないので増やしたい」、という場合です。
http://framework.zend.com/manual/ja/zend.view.helpers.html

Viewヘルパーはこのまとめでは扱いません。標準で付属するViewヘルパーが充分高機能なので、標準のViewヘルパーだけで何とかなることが多いでしょう。ヘルパーを作る前に「既に標準でできる内容でないか?」調べたほうがいいです。

ちなみにViewヘルパーを推奨するのは、「継承しなくて済むから」です。Viewクラスの書き換えより簡単に作れますし、拡張性も犠牲になりません。

Viewクラスを直接拡張する

以降は「 Zend_Viewを使いたくない 」「 Zend_Viewの挙動を差し替えたい 」というような場合のやり方です。これらのケースではViewクラスを直接拡張しなくてはなりません。

Zend Frameworkで使うためのViewクラスの条件は、「 Zend_View_Interfaceをimplementsしていること 」だけです。ただし、インターフェースには実装コードは全く書かれていないため、Interfaceから作ると面倒かもしれません。
Zend Frameworkには Zend_View_Abstractという、すでにZend_View_Interfaceをimplementsしているクラスがあり、これは必須メソッドが揃っています。単純なメソッド追加であればこれを使うのも手です。

  1. Zend_View_Interface をimplementsして、必須メソッドをすべて書く
  2. Zend_View_Abstract をextendsして、最低限だけ上書きする
  3. Zend_View をextendsして、最低限だけ上書きする

上に行くほど書くコードは多くなりますが、下に行くほどZend_Viewの複雑な実装を引き継ぐことになります。
ちなみにZend_View_AbstractとZend_Viewの差はごくわずかです。具体的にはソースコードを読みましょう。

「Zend_Viewは全く使いたくない! Twigさえあれば十分だ」ということなら、Zend_View_Interfaceから書いていくのがいいでしょう。

「Zend_Viewの微妙な点が気に食わない!」なら、Zend_Viewを継承して気に食わない部分だけ上書きすればいいです。

ここではZend_Viewをextendsして、escape()メソッドを上書きしてみます。これはhtmlspecialchars()のラッパー関数なのですが、標準のescape()は拡張性の反面、非効率な書き方をしているので、拡張性を捨ててもっとシンプルな実装に差し替えます。

library/My/View.php
<?php
class My_View extends Zend_View
{
  public function escape($str)
  {
    return htmlspecialchars($str, ENT_QUOTES, 'UTF-8');
  }
}

簡単なユニットテストはこんなイメージ。Zend_View_Interfaceのインスタンスだと判定されればOK.

tests/unit/My_ViewTest.php
<?php
require_once 'Zend/Loader/Autoloader.php';
Zend_Loader_Autoloader::getInstance()
  ->registerNamespace('My');

$view = new My_View;
assert($view instanceof Zend_View_Interface);

Zend Frameworkへの組み込み

さて、先程も言ったとおりZend Frameworkは非常に自由度が高いフレームワークで、様々な構成で作ることができます。
ここでは標準的な構成の場合に使えるものを2つ書きますが、構成が違う場合は使えないケースもあるのでご注意ください。

…標準のViewリソースプラグインがクラスの差し替えに対応していれば、こんなややこしいことをしなくてもいいのですが。。。「new Zend_View()」ってハードコーディングされてるんだよね。。

あ、以降のソースコードではオートローダーのコードは省略します。index.phpの先頭あたりにこんなコードが書いてあるものとします。

public/index.php
<?php
require_once 'Zend/Loader/Autoloader.php';
Zend_Loader_Autoloader::getInstance()->registerNamespace('My');
// ...(略

方法1・Bootstrap.phpで初期化する

通常はZend_Application_Resource_Viewが勝手に起動して、勝手にZend_Viewをインスタンス化します。
しかしBootstrap.phpで_initView()というメソッドを作っておけば、リソースプラグインより優先されます。これを使って手動でViewをインスタンス化することができます。

application/Bootstrap.php
<?php
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
  protected function _initView()
  {
    $view = new My_View;
    $viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
    $viewRenderer->setView($view);
    return $view; 
  }
}

方法2・Resourceプラグインを自作する

個人的にはこちらの方法がおすすめ。Bootstrapにベタ書きする手法だと、アプリを作るごとにコードをコピペすることになるので、再利用性が低くなります。

まず、My_Application_Resource_Viewクラスを作成します。これがいわゆるリソースプラグインです。名前が長いのは諦めましょう。

library/My/Application/Resource/View.php
<?php
class My_Application_Resource_View extends Zend_Application_Resource_View
{
    public function getView()
    {
        if (null === $this->_view) {
            $options = $this->getOptions();

            if (isset($options['classname'])) {
                $class = $options['classname'];
            } else {
                $class = 'My_View';
            }   
            $this->_view = new $class;
        }
        return $this->_view;
    }
}

このファイルを配置したら、あとはapplication.iniでpluginpathsに追加するだけ。

application/configs/application.ini
[production]
;..中略..
pluginpaths.My_Application_Resource = "My/Application/Resource"
;..中略..

これで、Zend_Viewの代わりにMy_Viewが使用されるようになります。。長かったw

Hiraku
PHP, Go界隈をうろうろしています。最近はgRPCと戦ってる。 特に明示していなければ、記事中のソースコード片は `CC-0 1.0` とします。出典表示無しで自由にコピペして頂いて構いません。 ただ、記事自体をコピペされるのは嫌なので、ソースコード部分以外の文章は通常通り全ての著作権を私が保持するものとします。 引用を超える範囲のコピペは止めて下さい。
http://blog.tojiru.net/
mercari
フリマアプリ「メルカリ」を、グローバルで開発しています。
https://tech.mercari.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away