フォーム値にアクセスする
アクションクラスからフォーム値へのアクセスするイメージは以下のようになっています。
- ブラウザからGETあるいはPOSTにより渡された値が、PHPによって$_GETあるいは$_POST変数に格納されます
- アクションフォームオブジェクトは、フォーム値として定義されている値のみ$_GETあるいは$_POSTから取得して、オブジェクト内のコンテナに格納します*1
- アクションクラスオブジェクトは、アクションフォームのget()/set()メソッドを通じてフォーム値にアクセスし、処理を行います
- ビューオブジェクトは、アクションフォームから必要な値を取得して出力に反映して、
- HTMLを出力します
アクションフォームとは何か
次にアクションフォームとは何か、について簡単にご説明します。
アクションフォームは、Ethnaでは
- フォーム値と
- アクションクラスがビューに渡したい値(強制エスケープ)と
- アクションクラスがビューに渡したい値(エスケープなし)
という3種類の値のコンテナだと考えて下さい。以下のようなイメージです。
- フォーム値にはget()/set()メソッドでアクセスします
- アプリケーション設定値(フォーム値以外で、ビューに表示させたいダイナミックな値)はsetApp()メソッドでアクションフォームに格納します
- アプリケーション設定値(HTMLエスケープさせたくない値)はsetAppNE()メソッドでアクションフォームに格納します
- フォーム値はテンプレートで
{$form.フォーム名}
としてアクセスします。値は常にHTMLエスケープされます。 - アプリケーション設定値(setApp()で格納されたもの)はテンプレートで
{$app.変数名}
としてアクセスします。値は常にHTMLエスケープされます。 - アプリケーション設定値(setAppNE()で格納されたもの)はテンプレートで
{$app_ne.変数名}
としてアクセスします。この値はHTMLエスケープされません(基本的には使用しません)。
なお、アクションフォームはアクションクラスと対になって必ず生成され、アクションクラスのprepare()あるいはperform()メソッド、また、ビューオブジェクトのpreforward()では必ず
$this->action_form // 面倒なら$this->afでも可
でアクセスできることが保証されています。アクションクラスに対応するアクションフォームが未定義の場合は、フォーム値定義の無いデフォルトのアクションフォームが生成されます。
フォーム値を定義する
というわけで、アクションクラスからアクションフォームオブジェクトを利用してフォーム値にアクセスするには、アクションフォームにどのようなフォーム値を受け取るかを定義する必要があります*2。
具体的には、アクションフォームのメンバ変数$formに
'フォーム名' => array(...(属性定義)...),
という形で利用するフォーム値を列挙していきます。例えば'id'と'name'というフォーム値を利用する場合は以下のようになります。
class Sample_Form_Index extends Ethna_ActionForm { /** * @access private * @var array フォーム値定義 */ var $form = array( 'id' => array( 'type' => VAR_TYPE_INT, ), 'name' => array( 'type' => VAR_TYPE_STRING, ), ); }
フォーム名をキーとして、値にはフォーム値の属性を定義した配列を記述します。単純にフォーム値を受け取る場合は必要ありませんが、フォーム値の属性として最大値、使用可能文字を記述しておくことで入力された値を自動で検証することが可能となります*3。ここでは、最低限の属性としてフォーム値の型を指定しています*4。フォーム値の型には
- VAR_TYPE_INT
- VAR_TYPE_FLOAT
- VAR_TYPE_STRING
- VAR_TYPE_DATETIME
- VAR_TYPE_BOOLEAN
- VAR_TYPE_FILE
のどれかを指定します。特に無ければVAR_TYPE_STRINGとしておけば問題ないと思います。
フォーム値にアクセスする
定義が完了したら、あとはアクションクラスのprepare()あるいはperform()メソッド、または、ビュークラスのpreforward()メソッドで以下のようにしてフォーム値を取得/設定するだけです。
function perform() { // フォーム値の取得 $id = $this->af->get('id'); // フォーム値の設定 $this->af->set('id', $id+1); }
アクションフォームへのアクセスに関するポリシー
余計なお世話かもしれませんが、アプリケーションを構築していく上でのアクションフォームへのアクセスに関するポリシーについて少しだけ...。
まず、アプリケーション構築手順(3)に書きましたが、アクションクラス(prepare()perform()メソッド)には最低限必要な処理のみ(必要なオブジェクトを生成してメソッドを実行+エラー処理程度)を記述し、実際のロジックは別途クラスを作成してそこに記述することを推奨します。
それと同様に、アクションフォームへのアクセスもアクションクラス(+ビュー)にでのみ行うことを推奨します。手続き上はアクションフォームオブジェクトはあちこちから参照可能ではありますが、例えばアクションクラス以外のどこかでアクションフォームがあれこれ弄られていると、アプリケーションの規模が大きくなってきたときに、個々のアクションでの独立性が低くなって来てメンテナンス性が低下してしまいます。
例えば、ユーザ情報を更新する以下のようなアクションクラスを考えてみます。
// アクション'user_update' function perform() { // ユーザオブジェクトを生成して情報を更新 $user =& new Sample_User(...); $user->set('name', $this->af->get('name')); $user->update(); // 更新された名前をアプリケーション値として設定 $this->af->setApp('new_name', $user->get('name')); return 'user_update-done'; }
ここで、「どうせだから$user->update()の中で$this->af->setApp()もしちゃえ」ということをすると、$user->update()をあちこち他のアクションクラスで呼び出している(あるいは呼び出すように拡張されてきた)場合に、思わぬバグの原因になったり、前述のように個々のアクションの独立性が落ちてメンテナンス性の低下を引き起こしたりします。
というわけで、アクションフォームへのアクセス(特に更新)はアクションクラス(+ビュー)のみに限定することを結構強く推奨します。
*1 Ethnaでは基本的に、クライアントから送信されアクションフォームに格納されたフォーム値がGET/POST(REQUEST_METHOD)のどちらに由来するかを区別しません。理由は、GET/POSTで振舞いを変えていると思わぬところでダサダサな振舞いをしたり、場合によっては(ここはGETしかこないと思い込んでコードを書いていたりすると)セキュリティホールになる可能性もなくもなくも無いためです
*2 アクションに対応するアクションフォームのファイル名やクラス名についてはアクション定義を省略する、またはアクション定義省略時の命名規則を変更するを参照してください
*3 詳細はフォーム値の自動検証を行う(基本編)を御覧下さい
*4 もちろん省略も可能ですが