前回はHTML_QuickFormの基礎を勉強したので、今回は応用。Smartyとの連携ってのをやってみる。
********************************************************************************
大きな流れ
********************************************************************************
addElement:オブジェクト設定
↓
addRule:検証ルール設定
↓
applyFilter:フィルタ設定。trimしたりとか
↓
(やっぱここでやるんでしょ?)
setDefaults:デフォルト値設定
setConstants:定数設定(上書きできない値。使いどころがイメージできない...)
↓
validate:検証実施
↓
freeze:凍結実施(検証がOKだったら)
↓
Smartyにデータを渡して表示
HTML_QuickForm利用の手引き
http://www.is.titech.ac.jp/~yanagis0/kei/quickform.html
を参考に、まずはPEARについているサンプルソースを見てみる。場所はPEARディレクトリ内の「doc/HTML_QuickForm/docs/renderers/SmartyStatic_example.php」。SmartyDynamic_example.phpもある。スタティックとダイナミックでどう違うかはよくわからんが、まずはスタティックの方のソースを追ってみることに。非Smartyとの違いは、99行目「// setup a template object」以降の処理だけっぽい。
validate&freeze以降の流れはこんな感じ。
Smartyオブジェクト生成
↓
生成したSmartyを渡しながらrendererオブジェクト生成
↓
初期設定(必須とかエラーとか。なんかよくわからん)
↓
HTML_QuickFormオブジェクトにrendererオブジェクトを渡す(accept())
↓
Smartyオブジェクトにテンプレート変数を登録
↓
Smarty->display();
なのだそうな。
テンプレート変数については、例えば
$form->addElement('header', 'MyHeader', 'QuickFormのテスト'); $form->addElement('text', 'name', 'あなたのお名前は?'); $form->addElement('submit', 'btnSubmit', '送信'); //(略) $tmpl->assign('form', $renderer->toArray());
と登録すれば、テンプレートの方からは{$form.header.MyHeader}で「QuickFormのテスト」にアクセスできる。ただしこれはヘッダに限った話で、その他のフォームオブジェクトへのアクセス方法としては{$form.name.label}で「あなたのお名前は?」に、{$form.name.html}でフォームオブジェクトのHTMLにアクセスできる模様。
ただしsubmitボタンについては、{$form.btnSubmit.label}とやっても「送信」とは表示されない。resetボタンも同様({$form.btnSubmit.value}か?)。
一番重要な<form>タグへ設定する属性値へは{$form.attributes}でアクセスできる。つまり<form {$form.attributes}>と書けばいいみたい。まあとにかくやってみる。
■PHPコード
<?php require_once "HTML/QuickForm.php"; require_once "HTML/QuickForm/Renderer/ArraySmarty.php"; require_once "smarty.php"; $form = new HTML_QuickForm('formtest', 'post'); // オブジェクト設定 $form->addElement('header', 'MyHeader', 'QuickFormのテスト'); $form->addElement('text', 'name', 'あなたのお名前は?'); $form->addElement('password', 'password', 'パスワード'); $form->addElement('reset', 'btnClear', 'クリア'); $form->addElement('submit', 'btnSubmit', '送信'); // 検証 if ($form->validate()) { // 凍結 $form->freeze(); } // smartyオブジェクト $tmpl =& new Tmpl; // rendererオブジェクト。第2引数は不明。 $renderer =& new HTML_QuickForm_Renderer_ArraySmarty($tmpl, true); // HTML_QuickFormオブジェクトにrendererオブジェクトを渡す $form->accept($renderer); // テンプレート変数登録 $tmpl->assign('form', $renderer->toArray()); //出力 ob_start(); print_r($renderer->toArray()); $tmpl->assign('static_array', ob_get_contents()); ob_end_clean(); // 表示 $tmpl->display('member_regist.tmpl'); ?>
■Smartyテンプレート(member_regist.tmpl)
<h1>{$form.header.MyHeader}</h1> <form {$form.attributes}> {$form.name.label}:{$form.name.html}<br> {$form.password.label}:{$form.password.html}<br> {$form.btnClear.html}{$form.btnSubmit.html}<br> </form> <pre> {$static_array} </pre>
■実際の出力
<h1>QuickFormのテスト</h1> <form action="/index.php" method="post" name="formtest" id="formtest"> あなたのお名前は?:<input name="name" type="text" /><br> パスワード:<input name="password" type="password" /><br> <input name="btnClear" value="クリア" type="reset" /><input name="btnSubmit" value="送信" type="submit" /><br> </form> <pre> Array ( [frozen] => [javascript] => [attributes] => action="/form2.php" method="post" name="formtest" id="formtest" [requirednote] => <span style="font-size:80%; color:#ff0000;">*</span><span style="font-size:80%;"> denotes required field</span> [errors] => Array ( ) [hidden] => [header] => Array ( [MyHeader] => QuickFormのテスト ) [name] => Array ( [name] => name [value] => [type] => text [frozen] => [required] => [error] => [label] => あなたのお名前は? [html] => <input name="name" type="text" /> ) [password] => Array ( [name] => password [value] => [type] => password [frozen] => [required] => [error] => [label] => パスワード [html] => <input name="password" type="password" /> ) [btnClear] => Array ( [name] => btnClear [value] => クリア [type] => reset [frozen] => [required] => [error] => [label] => [html] => <input name="btnClear" value="クリア" type="reset" /> ) [btnSubmit] => Array ( [name] => btnSubmit [value] => 送信 [type] => submit [frozen] => [required] => [error] => [label] => [html] => <input name="btnSubmit" value="送信" type="submit" /> ) ) </pre>
なるほど、{$static_array}を見れば大体どんな値が{$form}に入ってくるかは確認できる。次は、先ほどは意味がわからなくて無視してたsetErrorTemplate()とsetRequiredTemplate()について調べてみる。マニュアルを読んだだけではイマイチピンとこなかったけど、多分こんな感じだ。
********************************************************************************
setErrorTemplate()
********************************************************************************
validateがfalseだった(エラーではじかれた)時に表示するエラーメッセージをテンプレート化して表示させる。
You can use {$label} or {$html} placeholders to let the renderer know where where the element label or the element html are positionned according to the error message. They will be replaced accordingly with the right value. The error message will replace the {$error} placeholder. For example: {if $error}<span style="color: red;">{$error}</span>{/if}{$html} will put the error message in red on top of the element html.
If you want all error messages to be output in the main error block, use the {$form.errors} part of the rendered array that collects all raw error messages.
If you want to place all error messages manually, do not specify {$html} nor {$label}.
Groups can have special layouts. With this kind of groups, you have to place the formated error message manually. In this case, use {$form.group.error} where you want the formated error message to appear in the form.
つまり、この関数で指定したテンプレートに従って、エラーメッセージを出すことができると。
指定するテンプレート内では、{$label}と{$html}と{$error}のテンプレート変数が使える。
例えば
$form->addElement('text', 'name', 'あなたのお名前は?');
のラベルへアクセスするには{$form.name.label}を、フォームオブジェクトのHTMLへアクセスするには{$form.name.html}を使うけれど、例えば
{if $error}<span style="color:#ff0000;">{$error}</span>{/if}{$html}
としておけば、{$form.name.html}の表示が
<span style="color:#ff0000;">エラーメッセージ</span>[フォームオブジェクトのHTML]
っていう風に置き換わるらしい。さらに全エラーメッセージは{$form.errors}に格納されると。グループオブジェクトの時は{$form.group.error}、か?さらに{$form.name.error}で各フォームオブジェクトのエラーメッセージに直接アクセスすることもできるけど、その場合は{$html}とか{$label}とかは使っちゃいけないらしい。
********************************************************************************
setRequiredTemplate()
********************************************************************************
こっちは必須項目のメッセージ(エラーメッセージではない)の表示テンプレートの設定。setErrorTemplate()とほぼ同じ使い方。でもこっちは{$requied}のほかに{$error}も使えるらしい。
You can use {$label} or {$html} placeholders to let the renderer know where where the element label or the element html are positionned according to the required tag. They will be replaced accordingly with the right value. You can use the full smarty syntax here, especially a custom modifier for I18N. For example: {if $required}<span style="color: red;">*</span>{/if}{$label|translate} will put a red star in front of the label if the element is required and translate the label.
ex)
{if $required}<span style="color: red;">*</span>{/if}{$label|translate}
よし、ためしにやってみよう。
<?php require_once "HTML/QuickForm.php"; require_once "HTML/QuickForm/Renderer/ArraySmarty.php"; require_once "smarty.php"; $form = new HTML_QuickForm('formtest', 'post'); // オブジェクト設定 $form->addElement('header', 'MyHeader', 'QuickFormのテスト'); $form->addElement('text', 'name', 'あなたのお名前は?'); $form->addElement('password', 'password', 'パスワード'); $form->addElement('reset', 'btnClear', 'クリア'); $form->addElement('submit', 'btnSubmit', '送信'); // 検証ルール設定→ここを追加 $form->addRule('name', 'お名前は4文字以下にしてください', 'maxlength',4); $form->addRule('password', 'パスワード入力が必要です', 'required',null); // 検証 if ($form->validate()) { // 凍結 $form->freeze(); } // smartyオブジェクト $tmpl =& new Tmpl; // rendererオブジェクト。第2引数は不明。 $renderer =& new HTML_QuickForm_Renderer_ArraySmarty($tmpl, true); $renderer->setRequiredTemplate( '{$html}{if $required}(必須){/if}'); $renderer->setErrorTemplate( '{if $error}<p style="color:#ff0000;">{$error}</p>{/if}{$html}'); // HTML_QuickFormオブジェクトにrendererオブジェクトを渡す $form->accept($renderer); // テンプレート変数登録 $tmpl->assign('form', $renderer->toArray()); ob_start(); print_r($renderer->toArray()); $tmpl->assign('static_array', ob_get_contents()); ob_end_clean(); // 表示 $tmpl->display('member_regist.tmpl'); ?>
おう、なんとなくわかってきたぞ。
setErrorTemplateでは{$html}や{$label}は使わず、直接{$form.name.error}ってテンプレートに書いた方がテンプレート見てるだけで出力結果がイメージしやすくて楽かも。
次回はもそっと実践的なやつを作ってみよう。