yii widget と Zend_View

moca & colonさんの「Yii widgetのひみつ」にyiiのwidget実装の記事があったので関連で。
http://choco-moca.pugpug.org/wp/?p=327

関連:
http://d.hatena.ne.jp/noopable/20090115/1232027664

テンプレートベースを利用したビューに対して、widgetの有用性を考える。

たとえば、Zend_Viewの場合

http://framework.zend.com/manual/ja/zend.view.scripts.html

<?php if ($this->books): ?>
    <!-- 本の一覧 -->
    <table>
        <tr>
            <th>著者</th>
            <th>タイトル</th>
        </tr>
        <?php foreach ($this->books as $key => $val): ?>
        <tr>
            <td><?php echo $this->escape($val['author']) ?></td>
            <td><?php echo $this->escape($val['title']) ?></td>
        </tr>
        <?php endforeach; ?>
    </table>
<?php else: ?>
    <p>表示する本がありません。</p>
<?php endif;

こんな感じのテンプレートになる。
[あくまでもビューを理解するためのサンプルであって実用性を考慮したものでない]
テンプレート内に個別実装を直接書かれると、メンテナンス性が落ちる可能性があるので、partialが使われる。
http://framework.zend.com/manual/ja/zend.view.helpers.html#zend.view.helpers.initial.partial.usage
たとえば、こんな感じ

<?php if ($this->books): ?>
<?php echo $this->partial('model2loop.phtml', $this->book); ?>
<?php else: ?>
<?php echo $this->partial('inlineNotice.phtml', array('message' => '表示する本がありません。')); ?>
<?php endif;

ここでは、$this->bookがmodel2loopという汎用ビュースクリプトの規約に沿っているという前提でそのまま投入している。
これをさらに集約するため、ZendFrameworkではプレースホルダヘルパーが使われる。
主にコントローラー内で実装することになるのだが、コントローラーで各モデルとビューから出力を作成して、プレースホルダーにスタックしておく。
すると、ビュースクリプトでは、

<?php echo $this->placeholder('subcontents'); ?>

としてみたり、必要に応じてプレースホルダー内の要素を取り出す。

<?php echo $this->placeholder('subcontents')->book; ?>

yii widgetなら

widgetを利用すると、この辺の処理はwidgetに丸投げされる。
http://choco-moca.pugpug.org/wp/?p=327
こちらにあるとおり、widgetインスタンスが作成されてwidgetに出力が任される。

テンプレートに対するwidgetの有用性とは

重要なポイントは、Zend_Viewを利用した前節の記述で、model2loopというビュースクリプトに食わせるために、model2loopと$this->bookの仕様は事前に合わせておく必要がある点だ。汎用性は増したが、仕様が分散し、ソースに存在しない規約を強制するのであまり好ましくない。
widgetを使う場合、widgetの個々のクラスはwidgetを継承しているし、さらに拡張した機能を共通で持たせたければそれを定義しておけばいい。仕様はクラス持たせることができるので共通化させても仕様が分散せず、仕様変更につよい構成にできる。
たとえば、先の例でmodel2loop.phtmlはテーブルで書かれるわけだが、これを一部分だけ仕様変更したい場合、model2loop.phtmlを書き変えるか、model2loop.phpを呼んでいるビュースクリプトに変更を加える。
widget構成にしてあると、widget内で完結しているので、他の部分に影響させることなく、出力仕様を変更できる。
単純に仕様変更を題材にしたが、自前でCMSを組む時など、ユーザーによるカスタマイズを受け入れやすいかどうかという部分に痛烈に影響する。

widget構成が失敗してきた(成功しきれない)理由

過去にもwidget形式のCMSフレームワークは多数存在してきたと思うが、その構成には固定的なファン層が形成されている一方で、カスタマイズしにくいという理由で受け入れられにくいことも確か。
実際、過去の事例で、そこ、共通の出力形式でいいんじゃないの?というところで、デザイナーから細かい注文が入ることが多かった。現在は、CSSの仕様が自然になって来たので、プログラム上も合理的な構成にしやすくなったが、以前は、そこにそのソース?っていうHTMLコーダーからの注文が後を絶たなかった。だから、widgetだけで組むことは無理だし、効率的でもなかったのかもしれない。

では、今後

widgetの仕様策定は、テンプレートによる自由度に制約にほかならず、指定された仕様を逸脱することが難しいから、特定のニーズを満たさなければいけない職業人にとっては致命的となりやすい。であれば、自由な仕様策定が可能なコンポーネントベースのフレームワークが、最小限の仕様制約によってwidget構成を可能にすればいいのではないだろうか。