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)コントローラ(又はモデル)側:

  1. 入力データのバリデーションチェック(最大長、フォーマット、必須チェック、許可しないデータのフィルタリング等)を行う。
  2. バリデーションエラー時に、POSTされてきた値の再セットを行う。
  3. トークンキーを持っておき、多重投稿避けと、スクリプトでのURL直指定・フォームデータ決め打ちのPOST避けを行う。


3)コントローラ(又はモデル)側:

  1. DBへの格納をおこなう。(更新の場合はDBからの読み出しと、事前の値セットも必要)
  2. トランザクション処理が必要な場合は、トランザクション処理(trans begin,rollback,commit)を掛ける

大体このような処理を作る必要があると思う。


これが結構面倒なので、もっと簡略化/共通化し、毎回記述する量を削減したくなった。

(面倒くさいといっても、CodeIgniterの機能を使うことで相当楽にはなる。
ただ、個人的にはCakePHPのアプローチの方が、標準機能が豊富な分楽なように感じる。)


希望する機能

希望する機能は、以下のような感じ。ものぐさな俺向け仕様。後で楽をするための苦労は厭わない。

  1. フォームのタグを書きたくない。プロパティーだけでフォームを作りたい。
  2. フォーム構成を構造化して、見渡しを良くしたい。
  3. プロパティー内に、バリデーションの処理も事前に規定しておきたい。
  4. 規定しておいたプロパティーを読み込み、呼び出し時には、なるべく1行でバリデーションチェックを完了させたい。
  5. バリデーションエラー発生時に、POSTされてきた値を、自動的にフォーム側に再セットしたい。
  6. 出来ればトークンのチェックも自動でやってほしい。


パフォーマンスの観点で言えば、テンプレートに直接タグ記述が一番速いだろうが、
フォーム部分に限っては妥協して以後の生産性を優先する。


また、ウチの場合デザイナーにフォームを弄らせることはまず無いので、
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属性が付けられないっぽいので、さらに手を入れるつもり。

バリデーションエラー時:

POST成功時、まだprint_rしているだけ:



動作確認ソース(昨日からの変更点のみ抜粋)

調査段階なので、後でもう少しまともなのを書くが、
大体こんな感じでバリデーション付きのフォームが作成できる。

ラジオボタンとかプルダウンとかの定義の方法等、未調査項目が多数有り。


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;
}



インストールログや、残りの調査結果は明日以降に書く。

ラジオボタンとかプルダウン周りが、まだいまいちつかめないけど、
慣れれば相当楽ができそう。