CodeIgniterの学習 20 - 標準フォームヘルパの代わりに、XML定義のフォームライブラリを使いフォーム生成とバリデーションを簡略化してみる(調査編1)
(08/10/11追記 http://d.hatena.ne.jp/dix3/20081011/1223725579 の理由によりこの方法は取りやめることにした。)
(08/10/16 追記)
下記のかわりに、ClientServer Validation 改のこっちを使ってみることにした。
(http://d.hatena.ne.jp/dix3/20081013/1223862786)
今日はXML定義のフォームライブラリを使って、自動バリデーション機能付きのフォームを作ってみる。
標準のやり方ではないので、参考にはならないかもしれないが、記録しておく。
(マニュアルのフォームヘルパを使ったやり方とは違い、
http://codeigniter.com/wiki/Form_Library/ のフォームライブラリを試している。
また、今日は枠組みだけで、登録ロジックは入れていない。)
使うに至った理由
フォーム周りの処理は
1)ビュー側:
- フォームヘルパを使って、タグ生成を簡略化する
- テンプレートに直接inputタグを記述してフォームを作る
のどちらかを用いてhtmlタグを作る。
2)コントローラ(又はモデル)側:
- 入力データのバリデーションチェック(最大長、フォーマット、必須チェック、許可しないデータのフィルタリング等)を行う。
- バリデーションエラー時に、POSTされてきた値の再セットを行う。
- トークンキーを持っておき、多重投稿避けと、スクリプトでのURL直指定・フォームデータ決め打ちのPOST避けを行う。
3)コントローラ(又はモデル)側:
- DBへの格納をおこなう。(更新の場合はDBからの読み出しと、事前の値セットも必要)
- トランザクション処理が必要な場合は、トランザクション処理(trans begin,rollback,commit)を掛ける
大体このような処理を作る必要があると思う。
これが結構面倒なので、もっと簡略化/共通化し、毎回記述する量を削減したくなった。
(面倒くさいといっても、CodeIgniterの機能を使うことで相当楽にはなる。
ただ、個人的にはCakePHPのアプローチの方が、標準機能が豊富な分楽なように感じる。)
希望する機能
希望する機能は、以下のような感じ。ものぐさな俺向け仕様。後で楽をするための苦労は厭わない。- フォームのタグを書きたくない。プロパティーだけでフォームを作りたい。
- フォーム構成を構造化して、見渡しを良くしたい。
- プロパティー内に、バリデーションの処理も事前に規定しておきたい。
- 規定しておいたプロパティーを読み込み、呼び出し時には、なるべく1行でバリデーションチェックを完了させたい。
- バリデーションエラー発生時に、POSTされてきた値を、自動的にフォーム側に再セットしたい。
- 出来ればトークンのチェックも自動でやってほしい。
パフォーマンスの観点で言えば、テンプレートに直接タグ記述が一番速いだろうが、
フォーム部分に限っては妥協して以後の生産性を優先する。
また、ウチの場合デザイナーにフォームを弄らせることはまず無いので、
viewをみただけで、何の項目が有るか分からなくても、別に問題無いので、定義がXMLでも構わない。
フォームを1つ2つしか作らない程度ならば、今日の作業は非生産的で不要だと思う。
標準のやり方のほうが速く仕事は終わるはず。
標準以外のライブラリを探してみる
希望するような機能をCodeIgniter wikiを探してみたら、
Form Library - http://codeigniter.com/wiki/Form_Library/
というものがあった。(ライセンスはcreativecommons - http://creativecommons.org/licenses/by-sa/2.5/)
フォームのプロパティをXMLで記述し、これを読み込んでフォーム生成する類のようだ。
XMLを噛ましているので、
- 画面表示のパフォーマンスは直接テンプレートにタグを記述するよりは多少落ちる。
- ビューを開いただけではフォームが想像できない。定義ファイルに慣れる必要がある。
- 小回りが効かない。ビュー側に例外的な処理を直接記述出来なくなるので、状況に応じてライブラリ自体の改造が必要。
といったデメリットもあるだろうが、ひとまず使ってみる事にする。気に入らなかったら別のも試してみる。
ライブラリのインストールと若干の改造
ラベル名とバリデーションエラー時の項目名を日本語で表記させたいので若干改造した。必要なのは、
Form_Library - http://codeigniter.com/wiki/Form_Library/ + ソースの微改造(xmlファイル保存パスの変更、バリデーションエラーメッセージ用拡張) と、
Xml Library - http://codeigniter.com/wiki/Xml_Library/ + ソース微修正(utf8_encodeの箇所を、mb_convert_encodingに変更)
だが、今日は疲れたので、明日以降に書く。
動作画面
こんな感じ、まだ細かい挙動は試していない。明日以降試す。既に一部改造したが、id属性が付けられないっぽいので、さらに手を入れるつもり。
動作確認ソース(昨日からの変更点のみ抜粋)
調査段階なので、後でもう少しまともなのを書くが、
大体こんな感じでバリデーション付きのフォームが作成できる。
ラジオボタンとかプルダウンとかの定義の方法等、未調査項目が多数有り。
1)XML定義ファイル: views/xml/tasklist_edit.xml
設定方法の詳細を現在調査中。
xmlの保存パスは、ライブラリを書き換えて、views/xml/以下に保存するようにした。
バリデーション処理は、rulesに、| で繋げて書いていく。rulesの書き方は、CodeIgniter標準と同じ。
またここでは、バリデーションチェックの文言用に、fieldsを読み込めるように拡張している。
拡張しないと、「name属性 は必須です」みたいに、inputのname属性を主語にしたエラーメッセージが表示されるので、実用にならない。
<?xml version="1.0" encoding="UTF-8" ?> <form action="tasklist/edit/" name="tasklist_edit"> <fieldset name="ここはフィールドセットの名前"> <title rules="trim|required|min_length[10]|max_length[255]|xss_clean" fields="タスク名ですね"> <label>タスク名</label> <type>text</type> <onclick>javascript:window.alert('hoge');</onclick> <onmouseover>javascript:this.select();</onmouseover> <size>40</size> <maxlength>255</maxlength> </title> <note rules="trim|required|min_length[5]|max_length[4096]|xss_clean" fields="内容だよもん"> <label>内容</label> <type>textarea</type> <rows>5</rows> <cols>40</cols> <maxlength>4096</maxlength> </note> <hoge1 fields="パスワードなんだ"> <label>パスワード</label> <type>password</type> </hoge1> <hoge2 fields="ファイルなんだ"> <label>ファイル</label> <type>file</type> </hoge2> <hoge3 fields="プルダウンなんだ"> <label>プルダウン</label> <type>dropdown</type> </hoge3> <submit> <type>submit</type> <value>登録</value> </submit> </fieldset> </form>
2)コントローラ:application/controllers/tasklist.php
こんな感じ。
まだDB周りの処理とかが全然入っていないが、XML定義を作るのに慣れれば、
ロジック側では
1)$this -> load -> library( 'form' );でライブラリを読み込み
2)$this -> form -> load( 'tasklist_edit' );でXML定義を読み込み
3)$this -> form -> post_data();でポストデータのバリデーションチェックが自動的に走り(エラーなら自動的に入力値の再セットとエラーメッセージの格納も走る)
4)$this -> form -> build();
でフォームの生成
といった書き方だけで済み、記述量が少なくなって定型化される。
<?php (上略) // 登録更新処理、まだ枠だけ function edit(){ // XMLフォームライブラリのロード(標準のフォームヘルパでは無い!) $this -> load -> library( 'form' ); // フォーム定義ファイルxmlの読み込み $this -> form -> load( 'tasklist_edit' ); //views/xml/tasklist_edit.xml $data['title'] = "タスクの登録更新、まだ枠組みだけ"; //todo:トークンキーの設置 if ( $post_data = $this -> form -> post_data()){ //todo:DBへの新規登録、更新処理の組み込み $str = "本当はここでデータの登録更新処理をするか、確認画面を出す<br/>"; $str .= "POSTデータ<br/>" . print_r( $post_data, true ); $data['content'] = $str; }else{ // フォームの生成、todo:後でDB or POSTデータから読み込んだ値の初期表示も作る $this -> form -> set( 'title', 'value', "タイトルを入れてね" ); $this -> form -> set( 'hoge3', 'options', array("a"=>"1a","b"=>"2a" )); // フォームの生成 $data['content'] = $this -> form -> build(); } // ビューの生成 $this -> _setTpl( "tasklist_edit" , $data ); } (下略) ?>
3)内側ビュー: application/views/tasklist_edit.php
内側のビューはこれだけ、外側のビューは以前のエントリと同じ。
<h3><?= $title ?></h3> <?= $content ?>
4)css: ドキュメントルート/css/style.css
昨日からの差分のみ
ol.layout{ list-style-type:none; padding-left:5px; } .layout li{ margin-top:10px; } .error p{ margin:0; padding:0px; color:#ff0000; } form fieldset{ border:1px solid #ccc; } form em{ color:#ff0000; } form input , form textarea{ font-size:12px; }
インストールログや、残りの調査結果は明日以降に書く。
ラジオボタンとかプルダウン周りが、まだいまいちつかめないけど、
慣れれば相当楽ができそう。