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

m6uとFuelPHPとPostgreSQLとAndroid

FuelPHPまわりのメモ、初心者に産毛程度を生やす。

FuelPHPでフォーム入力をどう処理するか(概念とか考え方とか処理の流れとか)

 素のPHPの場合、$_POST(や$_GET)から受け皿変数にフォーム入力値を順次取り出しつつ、適正な入力かどうか検証した後、何かしらの処理にかけて、処理結果を出力するなり、フォーム入力に差し戻すなりしていた。

 長ったらしくなるPHPソースファイルの、上からどのあたりがどんな処理みたいな感じで何となく追っかけながらデバッグしていたような気もする。

 FuelPHPを導入していろいろガラリと変わった。

 フォーム入力の受付がControllerクラスのactionメソッドになり、実際にフォーム入力を処理するのがFieldsetクラス*1になって、入力の検証はFieldsetに含まれるValidationクラスが担当して検証し、検証後の値をそのFieldsetからもらって自前Modelクラスで処理して、結果を自前Viewクラスに流す、っていう流れ。

 役割分担というか分業というか、よく出来ているなぁと感心する。

 もちろん、フォーム入力に絡んでセッション切れの対策やSQLインジェクション対策やCSRF保護なども比較的ラクに盛り込める。

 フォーム入力の検証を、$fieldset->add(~, ~)->add_rule(~) のadd_rule()にてクロージャを使う方法がまたしびれるくらいにカッコいい。FuelPHPのCoreで入力項目単品の入力チェックはそこそこルールが事前に用意されているけど、複数の項目を使っての検証やDB問い合わせを組み合わせた検証など凝ったことをやるのにクロージャを使う方法がしっくりきたので、ここに紹介したい。

 「FuelPHPのValidationにクロージャを使う - Qiita」と「FuelPHPを更に使ってみて使えるなと思った拡張ValidationRuleの書き方とCore拡張の小技 - Qiita」。 クロージャを使うとクロージャが報告するエラーメッセージが上書きされてしまうので、クロージャに名前をつけて管理するっていう不思議なテクニックも実に重要。 実際に自分で書いてみたらこれに嵌りそうだったし。 ひとつの$fieldsetの中でクロージャがひとつだけならクロージャの命名管理は不要だけど、複数置くときは命名管理は必須。

 フォーム入力の検証がもしも何箇所でも共通して使うようなことになるなら、「FuelPHPに独自のバリデーションルールを追加する - 暁 [stfuawsc]」のように自前Validationクラスを用意するのも必要になりそう。 毎度毎度同じことを書く手間を省くためにも。

 ところで、ViewForm/Fieldsetクラスについて、「$fieldset->add_date_select('test', '年月日入力', 2003, idate('Y'));*2みたいに書くことが出来るのも嬉しいところ。 不正な年月日入力をさせないために、テキスト入力じゃなくプルダウンリストから入力させることができちゃう。 Viewクラスのほうで「))<?php echo $fieldset->field('test_year')->field_text(); ?>」とすれば年入力欄が、_yearを_monthにすれば月入力欄が、_dayなら日入力欄が生成される仕組み。 省力化しつつ、View側での表現の可能性が広がる。

 $validation = $fieldset->validation();とか書いて、

$validation->add('dummy_1', 'dummy_1')->add_rule(array('closure_1',
 function () use (~~~)
 {
  if (ダメ)
  {
   Validation::active()->set_message('closure_1', 'ダメなときのエラーメッセージ');
   return false;
  }
  else
  {
   return true;
  }
 }
));

とか。 add_rule() の配列キー'closure_1'と、Validation::active()->set_message() の第一引数が同じってところが肝。 ちなみに、検証クロージャの中で複数のエラーを検出した時に、Validation::active()->set_message() を検出回数分呼んでしまうと結局は上書きになってしまうので、エラーメッセージを配列に溜め込むとかして最後の1回 set_message() すれば確実にエラーメッセージを返せる。

 フォーム入力周り、まだまだわからないところもあるけどいろいろ試したい。

*1:Core/Fieldsetでなく、私は「fuelphpのfieldsetがもったいないので拡張してみた | エンジニア開発記」で紹介されている9wickさんのViewForm/Fieldsetクラスを使ってます

*2:年を2003年から現在の年までに制限した例。