[Zend Framework] Zend_View: ビューヘルパーをつかって、テンプレートの要素を部品化する

前回、Zend_Layout をつかって、共通のヘッダーやフッターをレイアウトしました。
さらにアサイドを、Widget風に部品化していきます。

参考サイト

アサイドは、前回のようにテンプレートを読み込んで実装できたと思いますが、Widget 機能の場合、ページによって表示内容を変える必要がありそうです。

Placeholder ヘルパー

Placeholder ヘルパー を利用すると良さそうに思えたので試してみることにします。
ひとまず layout.phtml の該当箇所を placeholder で置き換えます。

application/layouts/scripts/layout.phtml
                <aside>
                    <h3>aside</h3>
                    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam sodales urna non odio egestas tempor. Nunc vel vehicula ante. Etiam bibendum iaculis libero, eget molestie nisl pharetra in. In semper consequat est, eu porta velit mollis nec. Curabitur posuere enim eget turpis feugiat tempor. Etiam ullamcorper lorem dapibus velit suscipit ultrices.</p>
                </aside>
application/layouts/scripts/layout.phtml
<?= $this->placeholder('aside'); ?>

置き換えたテキストを、コントローラで capture を使って指定してみます。

application/controllers/IndexController.php
class IndexController extends Zend_Controller_Action
{
    public function init()
    {
        /* Initialize action controller here */
        // aside
        $this->view->placeholder('aside')->captureStart();
echo <<< EOM
                <aside>
                    <h3>aside</h3>
                    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam sodales urna non odio egestas tempor. Nunc vel vehicula ante. Etiam bibendum iaculis libero, eget molestie nisl pharetra in. In semper consequat est, eu porta velit mollis nec. Curabitur posuere enim eget turpis feugiat tempor. Etiam ullamcorper lorem dapibus velit suscipit ultrices.</p>
                </aside>
EOM;
        $this->view->placeholder('aside')->captureEnd();
    }

IndexController ではアサイドが表示されます。

Zend_View 2013-06-21-21-25-10

他のコントローラを呼んだ場合は、アサイドが表示されません。

Zend_View 2013-06-21-21-25-20

参考サイト

Partial ヘルパー

コントローラ毎に表示・非表示を切り替えることはできましたが、Widget のように表示内容を変えたり、個数を変更するには物足りませんでした。
そこで Partial(PartialLoop) ビューヘルパーを試してみます。
実際に開発するとなると、こんな実装イメージになるのではないでしょうか?

  1. 各Widgetの内容は、DBに登録されている
  2. ページ(コントローラ)毎に異なるWidgetデータを呼び出す
  3. 必要なデータのみ抽出して配列に収める
  4. 配列を view に渡す

2.と3.を function aside() で行った想定して、Widget 2つ分の配列を用意しました。
各コントローラでは、init で呼び出すだけでつかえるイメージです。
title にはタイトルを、content には一部HTMLタグを含んだデータが配列に収められています。

application/controllers/IndexController.php
class IndexController extends Zend_Controller_Action
{
    public function init()
    {
        /* Initialize action controller here */
        $this->aside();
    }
    public function aside()
    {
        $aside = array(
            array('id' => 1,
                  'title' => 'aside',
                  'content' => '<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam sodales urna non odio egestas tempor. Nunc vel vehicula ante. Etiam bibendum iaculis libero, eget molestie nisl pharetra in. In semper consequat est, eu porta velit mollis nec. Curabitur posuere enim eget turpis feugiat tempor. Etiam ullamcorper lorem dapibus velit suscipit ultrices.</p>'),
            array('id' => 2,
                  'title' => 'widget',
                  'content' => '<ul><li><a href="">1</a></li><li><strong>2</strong></li><li>3</li><ul>'),
        );
        $this->view->assign('partialdata', $aside);
    }

レイアウトファイル内を placeholder から partialLoop を使う内容に書き換えます。

application/layouts/scripts/layout.phtml
<?php if ($this->partialdata): ?>
<?= $this->partialLoop('partialLoop.phtml', $this->partialdata); ?>
<?php endif;?>

アサイドを表示する部分テンプレートとして partialLoop.phtml を用意します。
Partial ヘルパーを利用すると、このテンプレートに渡した配列を繰り返し表示(foreach)してくれます。

参考サイト

application/layouts/scripts/partialLoop.phtml
<?php
$allowed_tags = array('a', 'href', 'p', 'br', 'strong', 'li', 'ol', 'ul');
$allowed_attributes = array('href');
$filter = new Zend_Filter_StripTags(array(
        'allowTags' => $allowed_tags,
        'allowAttribs' => $allowed_attributes,
    ));
?>
                <aside>
                    <h3><?= $this->escape($this->title) ?></h3>
                    <?=
                        $filter->filter($this->content) . PHP_EOL;
                    ?>
                </aside>

content は、一部のHTMLが使えるようにしたいので、StripTags をフィルターとして使いました。

インデックスコントローラを表示してみます。

Zend_View 2013-06-21-21-25-30

pharetra in. In semper consequat est, eu porta velit mollis nec. Curabitur posuere enim eget turpis feugiat tempor.</p>
                    </footer>
                </article>
                <aside>
                    <h3>aside</h3>
                    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam sodales urna non odio egestas tempor. Nunc vel vehicula ante. Etiam bibendum iaculis libero, eget molestie nisl pharetra in. In semper consequat est, eu porta velit mollis nec. Curabitur posuere enim eget turpis feugiat tempor. Etiam ullamcorper lorem dapibus velit suscipit ultrices.</p>
                </aside>
                <aside>
                    <h3>widget</h3>
                    <ul><li><a href="">1</a></li><li>2</li><li>3</li><ul>
                </aside>
            </div> <!-- #main -->
        </div> <!-- #main-container -->

他のコントローラでは、表示されません。

Zend_View 2013-06-21-21-25-20

なんとか意図したとおりに出力できたではないでしょうか。