Yuriko.Net 個別記事

QuickForm + Template_Flexy で動的フォームを作るのに悩む
Yuriko.Net は独自ウェブログシステムに移行しましたが、運営者が使う管理画面はまだ完成していません;-) 記事の作成・編集、カテゴリーの追加・編集、イベントの追加・編集は可能ですが、それ以外のデーターは phpMyAdmin 経由で MySQL データーベースを直接いじっています。phpMyAdmin が優秀なので、自前の管理画面がなくてもウェブログの管理ができてしまうため、開発をあわてる必要がないのです;-)
開発が遅い理由の1つに、わたしの PEAR ライブラリーの理解が十分でないことがあります。とくに、HTML_QuickForm と HTML_Template_Flexy を組み合わせる部分が悩みの種です。どちらも高機能なパッケージで使いこなすのが大変な上に、QuickForm で作ったフォーム部品のレンダリングを Flexy でやらせるという組み合わせ技になると、ドキュメントが非常に少なくて試行錯誤しています。
フォーム部品が固定の場合は使い方がなんとか分かりましたが、「記事一覧」のようにフォーム部品の数が変化する場合は完成していません。フォーム部品を描画させるところはできたのですが、フォームの入力内容を検証するルールの設定が分かりません。そのため、正当な値を入れた場合は先に進みますが、不正な値を入れた場合は処理がおかしくなってします。どうせ管理画面は自分だけが使うものなので、値の検証がええ加減でもいいわけですが、やはりきちんと作りたいものです。
フォーム部品を作る部分のコードは以下のような感じです (説明用に抜粋しています)。
$form = new HTML_QuickForm('ev-mod', 'post'); $rows = array($form->addGroup(array(), 0, NULL, NULL)); // add dummy foreach ($list as $e) { $cols = array(); if (year_of($e['date']) < 1900) { $e['date'] = '2000-01-01'; } $end = $e['end'] ? $e['end'] : $e['date']; $cols[] = $form->createElement('static', 'target', NULL, $e['id']); $cols[] = $form->createElement('date', 'date', '', array('language' => 'ja', 'format' => 'Y年m月d日', 'minYear' => year_of($e['date']) -5, 'maxYear' => year_of($e['date']) +5)); $cols[] = $form->createElement('checkbox', 'has_end', NULL, '終了日を設定'); $cols[] = $form->createElement('date', 'end', '', array('language' => 'ja', 'format' => 'Y年m月d日', 'minYear' => year_of($end) -5, 'maxYear' => year_of($end) +5)); $cols[] = $form->createElement('textarea', 'desc', '説明', array('cols' => 48, 'rows' => 3)); $cols[1]->setValue($e['date']); $cols[2]->setValue(isset($e['end'])); $cols[3]->setValue($end); $cols[4]->setValue($e['description']); $rows[] = $form->addGroup($cols, intval($e['id']), NULL, NULL); } $form->addGroup($rows, 'list', NULL, NULL); $form->addElement('submit', 'back', '戻る'); $form->addElement('submit', 'modify', '修正する'); $rules = array(); foreach($rows as $id => $cols) { $rule[$id]['date'][] = array('開催日を入力してください。', 'required', NULL, 'server'); $rule[$id]['desc'][] = array('説明を入力してください。', 'required', NULL, 'server'); $rule[$id]['desc'][] = array('説明は512文字以内です。', 'maxlength', 512, 'server'); } $form->addGroupRule('list', $rules); $rend =& new HTML_QuickForm_Renderer_ObjectFlexy($page); $form->accept($rend); $page->mod_form = $rend->toObject(); $output = new HTML_Template_Flexy(); $output->compile('events.html'); $output->outputObject($page);
そしてテンプレート (events.html) の抜粋は次の通り。
{mod_form.outputHeader():h} {mod_form.hidden:h} <table class="list" border="1" cellspacing="0"> <caption>イベント修正</caption> <thead> <tr><th>ID</th><th>開催日</th><th>終了日</th><th>説明</th></tr> </thead> <tbody> <tr flexy:foreach="mod_form.list,id,e"> <td class="id">{id}</td> <td class="mod-date">{e.date.html:h} <div class="error" flexy:if="e.date.error">{e.date.error}</div></td> <td class="mod-date">{e.has_end.html:h}<br />{e.end.html:h} <div class="error" flexy:if="e.end.error">{e.end.error}</div></td> <td class="desc">{e.desc.html:h} <div class="error" flexy:if="e.desc.error">{e.desc.error}</div></td> </tr> </tbody> </table> <div class="error" flexy:if="mod_form.errors.list"> {mod_form.errors.list}</div> <div>{mod_form.back.html:h} {mod_form.modify.html:h}</div> </form>
addGroup を2重にすることで、テンプレートは作りやすくなりましたが、ルールが上手く動きません。addGroupRule でうまくいきそうなんですが、これでは動作していません。うーん困った。
なお、QuickForm でのクライアント側検証は使わない主義です;-) (続きはリンク先エントリに移設)