[Zend Framework] Zend_Layout: テンプレートをつかってページを表示する

Zend_Layout をつかって、共通のヘッダーやメニューを表示するようなレイアウトを構成します。

参考サイト

レイアウト要素

一般的なページのレイアウトを想定して、下記のような構成要素を用意します。
* ヘッダー
* ナビゲーション
* コンテンツ
* アサイド
* フッター
テンプレートデザインには、Initializr を利用することにします。
Initializr – Start an HTML5 Boilerplate project in 15 seconds!
このようなページになります。
Initializr 2013-06-19 21-07-00

ダウンロードと下準備

responsive をオプションを変更せず、そのまま利用します。
Initializr 2013-06-19 21-07-04
ダウンロードしたファイルを、ひとまずそのまま公開ディレクトリに設置します。

zf enable layout

zf create project で作成したプロジェクトディレクトリ内で、下記コマンドを実行します。

% zf enable layout

下記のファイル・ディレクトリが、追記・作成されました。

application/configs/application.ini
resources.layout.layoutPath = APPLICATION_PATH "/layouts/scripts/"
application/layouts/scripts/layout.phtml
<?php echo $this->layout()->content; ?>

## ディレクトリ構成
Zend_Layout の利用にあたり、ディレクトリ構成を確認し、各ファイルを整えておきます。
ディレクトリの構成は、下記に従って用意します。
<a href="http://framework.zend.com/manual/1.12/ja/project-structure.project.html">推奨されるプロジェクト・ディレクトリ構造 - Zend Framework MVC アプリケーションのために推奨されるプロジェクト構造 - Zend Framework</a>
### 設定ファイル
* application/configs/application.ini
* application/Bootstrap.php
いわゆるリソースプラグインというものでしょうか。
最終的に、application.ini, Bootstrap.php にまとめます。
### レイアウトテンプレート
* application/layouts/scripts/
配下に .phtml をおいていきます。
* layout.phtml (ディレクトリとともに zf で生成済)
* header.phtml
* footer.phtml
アサイドとナビゲーションは、ひとまず layout.phtml に含めておきます。
別途、ビューヘルパーを適用してみたいと思います。
なお、コンテンツは layout.phtml から呼ばれ、Contoroller 内の Action に対応した application/views/scripts/ 以下の .phtml が読み込まれることになります。
* application/views/scripts/index/index.phtml
### HTML関連フォルダ
* application/public/css
* application/public/<s>images</s>img
* application/public/js
* application/public/favicon.ico
ファイルは、Initializr をつかいます。
イメージフォルダ名のみ、推奨構造と異なることになります。
## テンプレートファイルの作成
ひとまず準備が整ったので、テンプレートを作成します。
Initializr のファイル内の要素を各テンプレートに分割していきます。
```html:application/public/index.html
<!DOCTYPE html>
<!--[if lt IE 7]>      <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]>         <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]>         <html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js"> <!--<![endif]-->
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
        <title></title>
        <meta name="description" content="">
        <meta name="viewport" content="width=device-width">
        <link rel="stylesheet" href="css/normalize.min.css">
        <link rel="stylesheet" href="css/main.css">
        <script src="js/vendor/modernizr-2.6.2-respond-1.1.0.min.js"></script>
    </head>
    <body>
        <!--[if lt IE 7]>
            <p class="chromeframe">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> or <a href="http://www.google.com/chromeframe/?redirect=true">activate Google Chrome Frame</a> to improve your experience.</p>
        <![endif]-->
        <div class="header-container">
            <header class="wrapper clearfix">
                <h1 class="title">h1.title</h1>
                <nav>
                    <ul>
                        <li><a href="#">nav ul li a</a></li>
                        <li><a href="#">nav ul li a</a></li>
                        <li><a href="#">nav ul li a</a></li>
                    </ul>
                </nav>
            </header>
        </div>
        <div class="main-container">
            <div class="main wrapper clearfix">
                <article>
                    <header>
                        <h1>article header h1</h1>
                        <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.</p>
                    </header>
                    <section>
                        <h2>article section h2</h2>
                        <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. Proin in est sed erat facilisis pharetra.</p>
                    </section>
                    <section>
                        <h2>article section h2</h2>
                        <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. Proin in est sed erat facilisis pharetra.</p>
                    </section>
                    <footer>
                        <h3>article footer h3</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.</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>
            </div> <!-- #main -->
        </div> <!-- #main-container -->
        <div class="footer-container">
            <footer class="wrapper">
                <h3>footer</h3>
            </footer>
        </div>
        <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
        <script>window.jQuery || document.write('<script src="js/vendor/jquery-1.9.1.min.js"><\/script>')</script>
        <script src="js/main.js"></script>
        <script>
            var _gaq=[['_setAccount','UA-XXXXX-X'],['_trackPageview']];
            (function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];
            g.src=('https:'==location.protocol?'//ssl':'//www')+'.google-analytics.com/ga.js';
            s.parentNode.insertBefore(g,s)}(document,'script'));
        </script>
    </body>
</html>

### header.phtml
`<header class="wrapper clearfix">` から `</header>` の内容。
### footer.phtml
`<footer class="wrapper">` から `</footer>` の内容。
### コンテンツ
`application/views/scripts/index/index.phtml` に、`<article>` から `</article>` の内容。
### layout.phtml
`application/public/index.html` の残り全ての内容。

application/layouts/scripts/layout.phtml
<!DOCTYPE html>
<!--[if lt IE 7]>      <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]>         <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]>         <html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js"> <!--<![endif]-->
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
        <title></title>
        <meta name="description" content="">
        <meta name="viewport" content="width=device-width">
        <link rel="stylesheet" href="css/normalize.min.css">
        <link rel="stylesheet" href="css/main.css">
        <script src="js/vendor/modernizr-2.6.2-respond-1.1.0.min.js"></script>
    </head>
    <body>
        <!--[if lt IE 7]>
            <p class="chromeframe">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> or <a href="http://www.google.com/chromeframe/?redirect=true">activate Google Chrome Frame</a> to improve your experience.</p>
        <![endif]-->
        <div class="header-container">
            <header class="wrapper clearfix">
<?= $this->render('header.phtml'); ?>
            </header>
        </div>
        <div class="main-container">
            <div class="main wrapper clearfix">
                <article>
<?= $this->layout()->content; ?>
                </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>
            </div> <!-- #main -->
        </div> <!-- #main-container -->
        <div class="footer-container">
            <footer class="wrapper">
<?= $this->render('footer.phtml'); ?>
            </footer>
        </div>
        <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
        <script>window.jQuery || document.write('<script src="js/vendor/jquery-1.9.1.min.js"><\/script>')</script>
        <script src="js/main.js"></script>
        <script>
            var _gaq=[['_setAccount','UA-XXXXX-X'],['_trackPageview']];
            (function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];
            g.src=('https:'==location.protocol?'//ssl':'//www')+'.google-analytics.com/ga.js';
            s.parentNode.insertBefore(g,s)}(document,'script'));
        </script>
    </body>
</html>

Zend_View の render メソッドで、ファイルを読み込みレンダリングしています。

<?= $this->render('header.phtml'); ?>

render(‘footer.phtml’); ?>

表示するコンテンツが自動で取得されレンダリングされており、これを書き出すだけでよいそうです。

layout()->content; ?>

スッキリと理解できていないんですが、Zend_Layoutでcontentはディフォルトで設定されており、その他は何を用いるかによってスクリプトが変わってくると言うことのようです。
参考サイト
> * <a href="http://wadslab.net/2008/05/zend_layout-2/">[Zend Framework][php] Zend_Layout ② クイックスタート - wadslog</a>
> * <a href="http://doremi.s206.xrea.com/zend/ref/zend_layout.html">Zend Framework - Zend_Layout編</a>
## 表示
Initializr のファイルを削除しておきます。

% rm application/public/index.html

インデックスページを表示してみます。
<a href="https://www.d-wood.com/wpmt/wp-content/uploads/2013/06/Zend_Layout-2013-06-19-21-07-00.png"><img src="https://www.d-wood.com/wpmt/wp-content/uploads/2013/06/Zend_Layout-2013-06-19-21-07-00.png" alt="Zend_Layout 2013-06-19 21-07-00" width="400" height="247" class="alignnone size-full wp-image-4098" /></a>
sampleという文字を区別しやすいように入れておきました。
設定した各テンプレートがレイアウトされています。
ちなみに、他のコントローラではどうでしょうか?
存在しないURLを指定して、エラーコントローラを呼んでみます。
<a href="https://www.d-wood.com/wpmt/wp-content/uploads/2013/06/Zend_Layout-2013-06-19-21-07-01.png"><img src="https://www.d-wood.com/wpmt/wp-content/uploads/2013/06/Zend_Layout-2013-06-19-21-07-01.png" alt="Zend_Layout 2013-06-19 21-07-01" width="400" height="247" class="alignnone size-full wp-image-4099" /></a>
こちらも問題なくレイアウトが適用されていました。
結果的に、マニュアルにあるような startMvc() をしてないですし、Zend_Loader::loadClass('Zend_Layout'); もしてないんですが、表示がされました。
このあたりスッキリしないんですが、リソースプラグインをつかうとシンプルにできるんでしょうか?
以下の3つは、別の方法で実装してみます。
* ナビゲーション
* アサイド
* favicon.ico
## 補遺
部分的に、別レイアウトを適用する方法です。
### アクション単位

$this->_helper->layout->setLayout(‘error’);

### コントローラ単位
あるコントローラだけ別のレイアウトを適用したい場合、init に設定を用意します。
この場合、application/layouts/scripts/error.phtml が適用されます。
public function init()
{
    $options = array(
        'layout' => 'error',
        'layoutPath' => '../application/layouts/scripts',
        'content' => 'content',
    );
    Zend_Layout::startMvc($options);
}
* <a href="http://framework.zend.com/manual/1.12/ja/zend.layout.options.html">Zend_Layout の設定オプション - Zend_Layout - Zend Framework</a>
init() に下記を設定しても適用できました。

$this->_helper->layout->setLayout(‘error’);
“`
Zend_Layout 2013-06-19 21-07-03

モジュール単位

application.ini に記述することで、設定できるようです。
* Module configuration and layout configuration in zend framework – Stack Overflow
* [Zend Framework]Moduleを利用し個々のLayoutを利用する|プログラム|Nullyのぶろぐ