ビュースクリプト
ビュースクリプトの役割
ビューはMVCにおいてユーザーインターフェイスを担当する概念です。
CurryにおいてはビューはHTMLテンプレートが基本となり、CurryのクラスであるViewAbstractを継承するクラスが裏でテンプレートを制御しています。
モデルで取得したデータをHTMLとして表示する場合に、表示用にデータを加工する必要が有る場合があります。それがテンプレート内で行えてしまう程度の軽微な加工であれば良いですが、PHPのコーディングで対応しなければならないような複雑な処理の場合、コントローラー、またはモデルにそのロジックが入り込みがちです。
MVCを厳格に意識して実装する場合、これは好ましいことではありません。
サイト訪問者への見せ方を調節するコーディングががMやCに入り込んでいる場合、この見せ方を少し変更するとなった場合にMやCのソースを改変しなければならなくなります。
これはMとVとCの分離が不十分な状態と言えます。
そこでCurryではビュースクリプトと呼ぶ専用のクラスを定義することができます。
これはコントローラーと1対1で関連付くクラスで、コントローラーと同じようにアクションメソッドを定義します。すると、アクセスのあったコントローラーのアクションの処理の後、ビュースクリプトクラスのアクションメソッドが実行されます。
このビュースクリプトクラスではコントローラーでビューに対して設定されたビュー変数を参照、再代入することができるため、コントローラーで無加工でビューへ割り当てられたデータを加工する事ができます。
ビュースクリプトクラスの定義
ビュースクリプトクラスの定義については以下のルールに従う必要があります。
- ViewScriptクラスを継承する
- クラス名の末尾をViewとする
- app/views/scriptsディレクトリ内にクラスファイルを配置する
- 必要に応じてコントローラーと同じアクションメソッドを定義する
ビュースクリプトクラスはコントローラークラスと1対1で定義し、アクションメソッドもコントローラークラスと同様に定義します。
ただし、アクセスされたコントローラー・アクションに対して、対応するビュースクリプトのクラス・アクションが定義されている場合のみ実行されます。定義されていない場合は何もしません。つまり、ビュースクリプトとしての処理が必要な場合のみ、コントローラーと同じ名前でアクションメソッドを定義すれば良いということです。
あるコントローラーに対しての、コントローラーとビューの関係をディレクトリ構成的に見ると、例えば以下の様な感じになります。
∟site/
∟app/
∟controllers/
∟cart_controller.php ←コントローラークラス
∟views/
∟scripts/
∟cart_view.php ←ビュースクリプトクラス
∟templates/
∟cart/ ←ビューテンプレート
∟products.php
class CartController extends Controller { public function products() { } public function detail() { } }
class CartView extends ViewScript { public function products() { } }
cartコントローラーに対するコントローラークラスとビュースクリプトクラスの定義の例です。
この例では、productsアクションに対するアクセスの場合はビュースクリプトにもアクションメソッドが存在するため、CartView::productsがCartController::productsの後のタイミングで実行されます。detailアクションの場合はCartViewにメソッドが無いため、ビュースクリプトとしての処理は行われないことになります。
テンプレート変数の加工
ビュースクリプトで行う最も基本的な処理として、テンプレート変数に格納されているデータの加工が考えられます。
通常はコントローラークラスでビューテンプレート用変数にデータを割り当て、テンプレートでそれを表示するという流れになりますが、ビュースクリプトがその間に立ち、コントローラーで割り当てられたデータを加工し、再度割り当て直すような処理になります。
class CartController extends Controller { public function products() { $model = $this->model('Cart'); $products = $model->getProducts(); $this->view->products = $products; } }
class CartView extends ViewScript { public function products() { $products = $this->products; $total = 0; foreach ($products as $key => $product) { $products[$key]['price'] = number_format($product['price']); $total += $product['price']; } $this->products = $products; $this->total_price = number_format($total); } }
<table>
<thead>
<tr>
<th>商品名</th>
<th>価格</th>
</tr>
</thead>
<tbody>
{foreach from=$products item=prd}
<tr>
<td>{$prd.product_name}</td>
<td>{$prd.price}</td>
</tr>
{/foreach}
<tr>
<td>合計</td>
<td>{$total_price}</td>
</tr>
</tbody>
</table>
この例では通販のカートを想定したものですが、コントローラーで商品リストデータを取得してビューへ割り当て、ビュースクリプトでは各商品の価格の表示フォーマットを調整し、同時に合計価格の計算を行なって新たな変数に割り当てています。
例えばこのような合計金額などは処理ロジック上は不要なもので、ユーザーインターフェイス上、ユーザーに必要な情報であるに過ぎず、ビュースクリプトで行うのが妥当と考えられます。
HTML自動生成機能を利用する
Curryにはフォームを含むHTMLの自動生成機能が備わっており、PHPのコーディングによってHTMLを生成し、テンプレートでHTMLを書かなくともHTMLを出力を行うことが可能になっています。特にフォームやテーブルなど動的に表示内容が変わる様なHTMLに対して、部分的にこの機能を利用するのが有効です。
HTMLは紛れもなくユーザーインターフェイスであり、これの生成を行うPHPのコーディングはビュースクリプトに記述すべきです。
例えば上記のカートの商品リストの表示のtableタグをHTML自動生成機能を利用した実装を行う場合は以下の様なコーディングになります。
class CartView extends ViewScript { public function products() { // データ加工 $products = $this->products; $total = 0; foreach ($products as $key => $product) { $products[$key]['price'] = number_format($product['price']); $total += $product['price']; } $products[] = array('product_name' => '合計', 'price' => number_format($total)); // テーブル自動生成 $table = new HtmlTable(); $table->addHeader(array('商品名', '価格')); $table->fromArray($products); $this->products_table = $table->getHtml(); } }
{$products_table}
HTML自動生成の詳細についてはHTML自動生成のマニュアルやフォーム自動生成のマニュアルを参照してください。