ビュー総括:レイアウトや断片化など(2/2)
フラグメンテーション:パーシャル/コンポーネント/コンポーネントスロット/スロット
ここではsymfonyにおけるコードの断片化の方法について紹介します。断片化により同じコードを何度も記述する必要がなくなり、また変更が生じた場合でも一カ所書き換えるだけで全体に反映されるのでメンテナンスなどがしやすくなります。
パーシャル:アクションを必要としないテンプレートの断片

パーシャルでは、モジュールのテンプレートフォルダ内に「_<パーシャル名>.php」というファイルを作りその中に呼び出したいテンプレートの断片を入れておきます。例えば次のような内容になります。
<?php echo $a->getId() ?> <?php mail_to($a->getMail(), 'メールを送る') ?>
これは、複数のモジュールから呼び出す事が可能です。呼び出す時は
include_partial('<モジュール名>/<パーシャル名>', array(<パーシャル内で必要となる変数の配列>))
とします。第一引数は呼び出し元とパーシャルのモジュールが同一の場合、モジュール名を省略できます。また、アプリケーションフォルダ直下の「templates/」フォルダ内に置いたパーシャルは、'global'モジュールの一部分とみなされ、
include_partial('global/<パーシャル名>',array(...))
と呼び出す事になります。第2引数には、例えばarray('a' => $bbsdata)のような感じで、オブジェクトを配列で入れるなどします。
コンポーネント:アクションを必要とするテンプレートの断片と、そのアクション

パーシャルで表示する内容にデータの抽出やソートなどといったロジックが必要な場合、アクションをパーシャルに添える事ができます。これがコンポーネントです。コンポーネントで使用するアクションは、「actions」フォルダ内に「components.class.php」というファイルを作成し、次のように記述します(モジュール名bbsdata、パーシャル名Headlinesとします)。
<?php class bbsdataComponents extends sfComponents { public function executeHeadlines() { ... (ここにアクション/ロジックを配置) } } ?>
クラス名は<小文字モジュール名>Components、関数名はexecute<パーシャル名(最初大文字)>()としてください。さらにパーシャル単独の時同様に「_<パーシャル名>.php」ファイルをテンプレートフォルダに配置します。呼び出しは
include_component('モジュール名', 'パーシャル名')
で行います。パーシャル呼び出し時同様に、配列で変数を渡す事もできます。
以下に、パーシャル・コンポーネントを用いたごく簡単なサンプルを示します(fragmentアクションとします)。
パーシャル使用例 <br /> <?php include_partial('mod1/date', array('f' => 'yyyy年 MM月dd日')) ?> <br /> コンポーネント使用例 <br /> <?php include_component('mod1', 'date2', array('f' => 'yyyy年 MM月dd日')) ?> <br />
<?php use_helper('Date') ?> 今日は:<?php echo format_date(date("Y/n/j"), $f) ?> <br />
<?php use_helper('Date') ?> <?php echo format_date(date("Y/n/j"), $f) ?>現在、 <?php echo $message ?> <br />
「_date.php」「_date2.php」共に、$fに日付のフォーマットを受け取っています。双方のパーシャルで用いられているformat_date()は直前の行で宣言されている「Date」ヘルパーの一つで、サイトの国際化などに関連して日付のフォーマットを整えるためのヘルパーです。第1引数で日付を受け取り、第2引数でフォーマットを指定します。詳細は次回紹介します。
<?php class mod1Components extends sfComponents { public function executeDate2() { $this->message = 'コンポーネントを使用しています。'; } } ?>
アクション「executeDate2()」から、パーシャル「_date2.php」へ$messageを送っています。

コンポーネントスロット:動的なコンポーネントと、その設定(view.yml)

呼び出し元などによりコンポーネントに変化を期待する場合は、コンポーネントを複数用意して、モジュール内「view.yml」に呼び出すコンポーネント名とそれが存在するモジュール名とを指定することによってそれを実現します。コンポーネントスロットと呼ばれ、
include_component_slot('コンポーネントスロット名')
として呼び出します。これは、呼び出し元モジュールフォルダ内の「view.yml」の設定に従ってコンポーネントを呼び出します。
all:
components:
sidebar: [bar, user]
上記は、コンポーネントスロット「sidebar」についての設定です。include_component_slot('sidebar')として呼び出された場合、barモジュールの「components.class.php」内の関数executeUser()が実行され、同じくbarモジュール内のパーシャル「_user.php」が呼び出されます。
コンポーネントスロットが用いられる場面としては、例えば「layout.php」内で配置したコンポーネントの内容を、呼び出し元により切り替えたい場合などです。
以下にコンポーネントスロットのごく簡単な実例を示します。まず「layout.php」にコンポーネントスロットを配置します。
<i>Copyright(c) 2005-2007, Wings Project. All Right Reserved.</i>
<br />
<hr>
<?php include_component_slot('date3') ?>
</body>
これを2つのモジュール「mod1」「mod2」から呼び出すとします。モジュールごとの「view.yml」は次のようになります。
all:
metas:
title: サンプルアプリケーション
components:
date3: [mod1, date3] (mod1のdate3コンポーネントを呼び出す)
# view.yml mod2
all:
metas:
title: モジュール-2
components:
date3: [mod2, date] (mod2のdateコンポーネントを呼び出す)
モジュールごとに呼び出すコンポーネントを指定できるので、「layout.php」上の同じ位置に、呼び出し元モジュールごとに個別のコンポーネントを呼び出すことが可能になります。次のように2つのコンポーネントを用意します。
<?php use_helper('Date') ?> <?php echo format_date(date("Y/n/j"), 'MM/dd/yyyy') ?>現在、 <?php echo $message ?> <br />
public function executeDate3() { $this->message = 'コンポーネントスロットを使用しています。'; }
<?php use_helper('Date') ?> 今日は:<?php echo format_date(date("Y/n/j"), 'yyyy/MM/dd') ?> <br /> <?php echo $message ?>
public function executeDate() { $this->message = 'mod2のコンポーネントスロットを使用しています。'; }
結果は以下のようになります。


スロット:アクションによる動的なレイアウト生成などに用いるテンプレートコード
スロットは、どこでも定義でき、どこでも呼び出しが行えるという、コンポーネントスロットよりも高速な仕組みです。
ここでチェックしておきたいのは、
- 読み込みはテンプレート(この中でパーシャルが呼び出される)→レイアウトの順
- スロットを定義する前に呼び出す事はできない
という2点です。
例えばスロットをコンポーネントスロットのように使うとすれば、呼び出し元テンプレートでスロットを定義し、レイアウトで呼び出すという流れになります。しかし「view.yml」を必要としないスロットは、アクションごとに定義することもできます。
スロットの定義は「slot('<スロット名>')」と「end_slot()」の間でなされ、「include_slot('<スロット名>')」ヘルパーで呼び出します。
また、「has_slot('<スロット名>')」関数でそのスロットが定義されているかを知る事ができるので、定義されていない場合どうするかといった管理も可能です。
以下に、スロットをindex、fragment各アクションに実装したごく簡単な例を示します。コンポーネントスロット同様に、まず「layout.php」にスロットを配置します。
<body> <?php if(has_slot('actionname')): ?> <?php include_slot('actionname') ?> <br /> <?php endif; ?>
上記では、スロット「actionname」が定義されていれば表示するよう設定しています。
続いてindexSuccess、fragmentSuccessの各テンプレートにそれぞれ以下を追記し、個別にスロットを定義します。
<?php slot('actionname') ?>
これは「index」アクションの結果です。
<?php end_slot() ?>
<?php slot('actionname') ?>
これは「fragment」アクションの結果です。
<?php end_slot() ?>
各アクションのスロット呼び出しの結果は次のようになります。


断片化要素一覧
ここまで一通り断片化の方法を見てきましたので、ここでまとめて表にしておきます。
| 断片 | 構成要素 | 呼び出し方 | 用途 |
| パーシャル | パーシャル | include_partial() | アクションを必要としないテンプレートを断片化したい時 |
| コンポーネント | パーシャル・コンポーネント | include_component() | アクションと共にテンプレートを断片化したい時 |
| コンポーネントスロット | 複数のパーシャルとコンポーネント・view.yml | include_compoment_slot() | 呼び出し元でコンポーネントを使い分けたい時 |
| スロット | (ヘルパーで挟まれた領域) | include_slot() | アクションごとに動的な内容を盛り込みたい時 |
