MVCでのビューの多様性について少し考えてみた(たとえばZFで)

Zend FrameworkMVCで多様化しがちなビューを実現するには、Viewスクリプトは表示用テンプレートではなく、Viewをつかさどるコントローラー的に実装し、表示をフォーマットするためのテンプレートは別に用意したほうがいいのではないか。

多様化するビュー

一般的なWebフレームワーク同様、ZFのデフォルトのMVCではビュースクリプトをテンプレートとして扱うことが多いと思います。しかし、近頃のWebアプリケーションでは、さまざまなクライアントに対応しなければならないケースが多く、デバイスの違いや、使用するブラウザやRIAクライアントなどの違い、ユーザーステータス、表示アイテムのステータス毎の見栄えの調整など、ビジネス上のプレゼンテーションロジックもビジネスモデルに依存した多様なビューを必要としがちです。また、最近ではデスクトップアプリ並のインタラクティブ性を求められており、それらの主役はクライアントサイドのJSではあるものの、サーバーサイドでもビューの多様化、高機能化に対応する必要があります。
Zend Frameworkでは、その解の一つとしてContextSwitchというアクションヘルパーを用意しています。

ContextSwitchという選択肢

ZFのContextSwitchアクションヘルパーを使うと、リクエストのコンテキストに応じてビュースクリプトの拡張子を自動的に調整して適切なビュースクリプトを選べるようになっています。確かに、大まかな考え方として、どんなビューを選択するかというのはコントローラーの仕事ですので、選択するだけで済む程度の多様性であれば、ContextSwitchは便利に使えます。デフォルトで用意してある、JsonAjaxに対するコンテキストだけではなく、開発者が定義したコンテキストに対応するようにビュースクリプトを自動選択させることができます。(たとえば、index.phtmlがデフォルトだとすると、index.json.phtmlなどにマップします)
これはビュースクリプト=テンプレートという考えに近いわけですが、多様化したテンプレートの一つ一つを各コントローラー毎に大量に作成する必要があり、それらの選択はコントローラーに分類されることになります。

ビューの高機能化

高機能な画面を構成したいと考えると、デスクトップアプリでの解決方法が参考になります。たとえば、WPFでのM-V-VMパターンやプレゼンテーションモデルです。

WPFM-V-VMパターン

Model-View-ViewModel デザイン パターンによる WPF アプリケーション(MSDN)
Developers Summit 2009
私がつたなく説明するよりも、上記のようなサイトが参考になると思います。高機能な画面を構成するため、表示用ロジックで状態を保持したり、インタラクションに対応するためのビューモデルを用いています。ビューモデルをどこに配置するか。私はそれをビュースクリプトに含めたいと考えています。一方、これまでビュースクリプト=テンプレートとして扱うケースが多かった分、ビュースクリプトからテンプレートを分離して、ビュースクリプトではビューモデルを扱うようにしてみます。するとUIが高度化するにしたがって、Web固有のMVCsmalltalk風なMVCに回帰するのかもしれないとすら思えます。
回顧主義というわけではないので、実務上のメリットも考えておきたいのですが、実モデルに変更を加える操作と、ビューモデル上の変更は別のレイヤーにあるのでコンポーネントを分けるメリットがあります。キャッシュのコントロールやセキュリティの確保を行いやすいというメリットがあります。
もちろん、ビューモデルのうち、テンプレート以外はコントローラーに実装するという設計もありだと思います。ビューの複雑さがコントローラー実装でコントローラーを汚す原因になるかどうかが、どちらの設計を選択するかの頃合いになるような気がします。

Web MVCでのビュー

複雑なビューを必要とするにもかかわらずビュースクリプト=テンプレートで運用しようとすると、ビューモデルのうちインタラクションについてはコントローラー、ビューモデルのデータ保持部分はモデルにと、無理無理にMVCに分散させる必要が出てきます。これでは、MVCのビューに関するロジックがコントローラーに依存することになり、ビュースクリプトも量産しなければならなくなり、なんのためのMVCなのか分からなくなってしまいます。
複雑かつ高度なビューを構成するには、ビューのロジックはコントローラーから切り離してビュースクリプトに含め、ビュースクリプトからビューヘルパーを経由してテンプレートエンジンを使ってテンプレートをパースすることで、ビュースクリプトからテンプレート要素を取り除くぐらいでよいのではないかと考えます。

Zend_Formはそのひとつの解

Zend_Formは、コンポーネント内に、コントローラー的要素とモデル的要素の両方を持っています。そのため、ビューに配置する場合でもMVC分類で言うと??な感じに思われることがあると思いますが、上記のようにビューモデルという考え方をするとまさにZend_Formはビューモデルの解となっていることがわかります。モデル本体とZend_Formにおけるモデルをうまく識別するには、M-V-VM的な理解が背景にあるとわかりやすいような気がします。
実際、Zend_Formでフルカスタマイズした外見を作るためには、独自のデコレーターや、テンプレートを用いたデコレーターを使う必要がありますが、それらの定義ファイルの置き場は自然ビュースクリプトから離れるもののビュー用のディレクトリ内に格納する方が自然で、コントローラーで処理することではないと思われます。それらはZFのMVCで使われるビュースクリプトとは一線を画したテンプレート要件を集約したものとなるでしょう。

テンプレートエンジンをビューヘルパーで使う

ビューヘルパーからテンプレートエンジンを使うようにすると、デフォルトのMVC構造に手を入れることなく、テンプレートエンジンヘルパー内の定義を行うことで柔軟性のあるテンプレートファイル構造を作ることができます。PHPTALでもFlexyでもsmartyでもなんでもよいですが、ヘルパーで実装することでテンプレートエンジンに合った定義方法、ディレクトリ構造を確保することができますし、テンプレートエンジンの初期化も、MVCのコントローラーではなくビュースクリプトで適切に判断して行えばよいことになります。これによりコントローラーの使い回しを向上しビュースクリプト冗長化させずに済むようになります。