powered by nequal

rhaco1-doc :: 100-blog-tutorial/07-template-model-association.txt

http://wikihub.org/wiki/rhaco1-doc/100-blog-tutorial/07-template-model-association

Table of contents:

collapse all expand all

Updates:

テンプレートとモデルの連携

さて,テンプレートの差し替えができるようになりましたので,一覧画面から記事の新規投稿や編集,削除を行えるようにします.

まずは,一覧画面から各処理へのリンクを作成します.

その前に,それぞれの処理のリンクは,次のようになることを確認しておきましょう.

  • 投稿 http://localhost/blog/posts/add
  • 詳細 http://localhost/blog/posts/view/1
  • 更新 http://localhost/blog/posts/update/1
  • 削除 http://localhost/blog/posts/delete/1

では, resources/templates/post_list.html をエディタで開きます.

<rt:extends href="./main.html" />
 
<rt:block name="title">
	<title>_("list")</title>
</rt:block>
 
<rt:block name="content">
	<fieldset>
		<form method="get" name="views_search_form" rt:reference="true">
			<input type="hidden" name="page" value="1"  rt:reference="false" />
			<input type="hidden" name="o" />
			<input type="hidden" name="a" />			
			<input type="text" name="q" />
			<input type="submit" value="_('search')" />
		</form>
 
		<div class="paging_field">
			<rt:pager param="pager" />
		</div>
		<table border="1" width="80%">
			<thead>
			<tr>
				<rt:loop param="{$tableObject.models('views','list_display')}" var="column">
				<th align="center" scope="col"><a href="{$rhaco.uri()}?{$sortorder.query($key)}">{$tableObject.label($column)}</a></th>
				</rt:loop>
			</tr>
			</thead>
			<tbody>
			<rt:loop param="object_list" var="obj" counter="counter">
			<tr class="{$f.evenodd($counter)}">
				<rt:loop param="{$tableObject.models('views','list_display')}" var="column">
				<td>{$f.text2html($obj.value($column,true))}&nbsp;</td>
				</rt:loop>
			</tr>
			</rt:loop>
			</tbody>
		</table>
		<div class="paging_field">
			<rt:pager param="pager" />
		</div>
 
		<rt:invalid />
	</fieldset>
	<br />
</rt:block>

さて,大量に見たことの無いタグがありますね!

ここでは,さらっと流して,あまり詳しいことは説明しません.

テンプレート構文

rhaco のテンプレートエンジンは XML をベースとしていますので,テンプレートの制御はは全て "rt:" という名前空間付きのタグが用いられます.

こんなのです.

<rt:extends href="./main.html"/>

テンプレートパーサに格納されている変数へのアクセスは,次のような構文です.

{$hoge}

詳しくは,参考サイトを見てください.

記事投稿画面へのリンク作成

検索フォームの次あたりに,記述してください.

<a href="{$rhaco.url('posts/add')}">投稿</a>

この際に,"{$rhaco.url('posts/add')}" は, 実際の描画の際には, "http://localhost/blog/posts/add" となります.

汎用 Views を用いた際には,このように必ず使うであろうヘルパーがデフォルトで組み込まれています.

モデルとの連携を利用した一覧表示項目の調整

現在,一覧画面には,post テーブルの全列情報が出ていますが,id,title,created の順で表示したいと思います.

この場合に修正する箇所は,テンプレート...ではありません.モデルを修正します.

次のように,Post モデルに views メソッドを実装し,"list_display" をキーとする連想配列を返します.

<?php
Rhaco::import("model.table.PostTable");
/**
 * 記事モデル
 */
class Post extends PostTable{
	/**
	 * 表示列制御
	 *
	 * @return hash
	 */
	function views(){
		return array(
			"list_display"=>"id,title,created"
		);
	}
}
 
?>

じっくりテンプレートと見比べてください.ここで対応づけられている箇所は,次の箇所です.

<rt:loop param="{$tableObject.models('views','list_display')}" var="column">

このようにテンプレートでは何をどこに表示するかを制御するだけで,どのように表示するかはモデルから取得する形になります.

単純な目的の一覧表示でしたら,順番の変更等もあっという間にできますね!

各画面へのリンク

さて,次はタイトルに詳細画面へのリンクを張りたいと思います.

リンクはエスケープしたらまずいので,先ほど行った自動的に表示項目を調整が無駄になってしまいました.

ヘッダ部分は同じなので,views メソッドはそのままで結構です.

記事を表示しているテンプレートを次のように変更してください.

		<table border="1" width="80%">
			<thead>
			<tr>
				<rt:loop param="{$tableObject.models('views','list_display')}" var="column">
				<th align="center" scope="col"><a href="{$rhaco.uri()}?{$sortorder.query($key)}">{$tableObject.label($column)}</a></th>
				</rt:loop>
				<th>更新</th>
				<th>削除</th>
			</tr>
			</thead>
			<tbody>
			<rt:loop param="object_list" var="obj" counter="counter">
			<tr class="{$f.evenodd($counter)}">
				<td>{$f.text2html($obj.value("id",true))}</td>
				<td><a href="{$rhaco.url('posts/view/')}{$obj.id}">{$f.text2html($obj.value("title",true))}</a></td>
				<td>{$f.text2html($obj.value("created",true))}</td>
				<td><a href="{$rhaco.url('posts/update/')}{$obj.id}">更新</a></td>
				<td><a href="{$rhaco.url('posts/delete/')}{$obj.id}">削除</a></td>
			</tr>
			</rt:loop>
			</tbody>
		</table>

モデルへのリンク出力の移動

※ この節は,開発スタイルや考え方によって大きく異なってきますので,必ずしも参考にはならないかもしれません.

モデルに対して,詳細,更新,削除などのアクションが存在する場合,それらの URL は,そのモデルの ID と紐付きになります.

先ほどは,テンプレート側にこの URL の生成コードを書きましたが,突き詰めた考え方をすると,テンプレート側で URL を生成するロジックを記述しているといえます.

さらに,この URL は,モデルが保持している ID に依存するので,この URL もしくは,リンクをモデルが持っているべきと考えることもできます.

rhaco では,このような考え方に基づいた構築も可能としています.

まず,project.xml に,更新と削除のリンクを生成する仮想列 ( extra ) を記述します.

<table name="post">
	<description>記事</description>
	<column name="id" type="serial" label="記事番号"/>
	<column name="created" type="timestamp" default="sysdate" label="投稿日"/>
	<column name="modified" type="timestamp" default="sysdate" label="最終更新日"/>
	<column name="title" type="string" require="true" max="50" label="タイトル"/>
	<column name="body" type="text" require="true" label="本文"/>
	<extra name="update_link" label="更新"/>
	<extra name="delete_link" label="削除"/>
	<default>
 
		<data>
			<column name="title" value="タイトル"/>
			<column name="body" value="これは,記事の本文です."/>
		</data>
		<data>
			<column name="title" value="またタイトル"/>
			<column name="body" value="そこに本文が続きます."/>
		</data>
		<data>
			<column name="title" value="タイトルの逆襲"/>
			<column name="body" value="こりゃ本当に面白そう!うそ."/>
		</data>
	</default>
</table>

次に,二箇所テンプレートを変更します.

<td>{$viewutil.columnString($obj,"update_link")}</td>
<td>{$viewutil.columnString($obj,"delete_link")}</td>

考え方に依りますが,URL の生成でとどめるもよし,HTML を含めた出力までさせるもよしかと思います.

リンクを生成するように,モデルを変更します.

<?php
Rhaco::import("model.table.PostTable");
/**
 * 記事モデル
 */
class Post extends PostTable{
	/**
	 * 表示列制御
	 *
	 * @return hash
	 */
	function views(){
		return array(
			"list_display"=>"id,title,created"
		);
	}
 
	/**
	 * update_link 仮想列の HTML 表現
	 *
	 * @return string
	 */
	function toStringUpdateLink(){
		return sprintf('<a href="%s">更新</a>',Rhaco::url("posts/update/".$this->getId()));
	}
 
	/**
	 * delete_link 仮想列の HTML 表現
	 *
	 * @return string
	 */
	function toStringDeleteLink(){
		return sprintf('<a href="%s">削除</a>',Rhaco::url("posts/delete/".$this->getId()));
	}
}
 
?>

このようにして仮想的な列をモデルに付与できるというのも,rhaco の非常に大きな特徴ともいえます.

つまり,テンプレートはモデルに対して,「ここに,XXX を表示したい.ここに,XXX の HTML 表現を表示したい.」という問い合わせを行うだけとなります.

必然的にロジックはモデルに集中することになります.

タイトルはどうするの?っていうのは残りますが,それはまた後で説明します.

参考