読者です 読者をやめる 読者になる 読者になる

すがブロ

sugamasaoのhatenablogだよ

はじめての rhaco3(3)

Advent Calendar[25日](の予定だったもの)

今日の流れ

チュートリアルの掲示板をカスタマイズしてみようと思います。
今回は、入力項目のバリデーション*1をして、バリデーションエラーだったら、その旨を画面に表示してみようという趣旨です。
言い訳を最初に書いておくと、PHPrhaco もほぼ初めてなので、クソみたいな書き方をしていると思います。
「こういう書き方の方が良いよ!」というアドバイスがあればぜひ欲しいです。

とりあえず、コード

以下のような修正を加えています

  • 掲示板のコメント(comment)が空だったら入力エラーにする
  • エラーだった場合は赤文字でエラーを出力する
<?php
include('rhaco3.php');
\org\rhaco\Conf::set('org.rhaco.store.db.Dao'
		,'Board'
		,'{"type":"org.rhaco.store.db.module.Sqlite","dbname":"board"}'
	);

/**
 * @var serial $id
 * @var string $name
 * @var text $comment@{"require":true}
 * @var timestamp $created_at @{"auto_now_add":true}
 */
class Board extends \org\rhaco\store\db\Dao{
	protected $id;
	protected $name;
	protected $comment;
	protected $created_at;
}

$req = new \org\rhaco\Request();
$unko = null;
try {
	if($req->is_post()){
		$obj = new Board();
		$obj->name($req->in_vars("name"));
		$obj->comment($req->in_vars("comment"));
		$obj->save();
	}
} catch(\org\rhaco\Exceptions $e){
	$unko = $e->messages();
}

$paginator = new \org\rhaco\Paginator(5,$req->in_vars("page",1));
$template = new \org\rhaco\Template();
$template
	->set_object_module(new \org\rhaco\flow\module\HtmlFilter())
	->set_object_module(new \org\rhaco\flow\module\Paginator());
$template->vars("object_list"
	,Board::find_all($paginator,\org\rhaco\store\db\Q::order('-id'))
);
$template->vars("unko", $unko);
$template->vars("paginator",$paginator);
$template->output(__FILE__);
?>

<rt:template>
<html>
<head>
	<meta charset='utf8' />
</head>
<body>
	<rt:if param="{$unko}">
		<p style="color:red;">
			{$unko[0]}
		</p>
	</rt:if>
	<form method="post">
		名前:<input type="text" name="name" rt:ref="true" /><br />
		コメント:<textarea name="comment"></textarea><br />
		<input type="submit" value="投稿" />
	</form>

	<rt:loop param="object_list" var="obj">
		<div>
			{$obj.name()} [{$obj.fm_created_at()}]
		</div>
		<pre>
			{$obj.comment()}
		</pre>
		<hr />
	</rt:loop>
	<div class="paginator">
	<rt:paginator />
	</div>
</body>
</html>
</rt:template>

コメントを空で*2ポストすると、以下のようにエラーが表示される。

解説

バリデーション

エラーチェックは(たぶん)rhaco3 の Object クラスが提供しているアノテーション機能なんだと思う。テキトウに rhaco2 での使われ方をパクッてきて追加したのが以下のコメント。

/**
 * @var serial $id
 * @var string $name
 * @var text $comment@{"require":true}
 * @var timestamp $created_at @{"auto_now_add":true}
 */
class Board extends \org\rhaco\store\db\Dao{
(略)
}

"require":true としていると、そのパラメータが空の状態で save() すると \org\rhaco\Exceptions が発生する。
この例外が発生したときに、エラー用の変数……上記のコードだと $unko にエラーメッセージを格納している。

テンプレートへバインド
$template->vars("unko", $unko);

でテンプレートに unko 変数をバインドしている(と思う)。

テンプレートで出力
	<rt:if param="{$unko}">
		<p style="color:red;">
			{$unko[0]}
		</p>
	</rt:if>

Templateの拡張タグを見ると、色々なテンプレートタグが使えるのがわかると思う。今回はその中から if を選んだ。
value の値を省略した場合は、値があるかどうかでよしなにやってくれるので今回の場合は便利。
最初、param="unko" って書いててなんど試しても期待した動きにならなくてファビョったのだけど、よくよくみたら "{$unko}" って書くみたい。Rubyの文字列内で展開するのと似たようなイメージだろうか。

まとめ

実はテンプレートの継承まで行けなかったのは心残りなのだけど、アノテーションについては少し触ることが出来た。というか、モデル周りはすごく思ったとおりに書きやすいんじゃないかなぁと思いました。
テンプレートについてはもう少しちゃんと理解しないと使いこなせなそうな感じだけれども。。。

*1:必須かどうかしか見ないけど

*2:常識的に考えて名前が空の場合もエラーにすべきだろってのはあると思うけど、気にしないでね