HTML_QuickForm_Page のコンストラクタで action 属性を設定できないようになっている唯一の理由は、 間違って自分の足を撃ちぬいてしまうようなミスをしないようにすることです。 どうしても属性を変更したければ、HTML_QuickForm_Page クラスの setAttribute() メソッドあるいは updateAttributes() メソッドを使用します (これらは HTML_Common から継承したものです。このクラスの API についても知っておく必要があります)。
混乱を避けるため、ここでは アクションの名前を表す文字列のことを「アクション」、 HTML_QuickForm_Action のサブクラスのことを「アクションハンドラ」と表記します。
独自のアクション名を使用してそのハンドラを作成することも可能ですが、 まずはデフォルトのアクション名およびそのハンドラを理解する必要があります。
デフォルトのアクション名
このアクションのデフォルトハンドラは HTML_QuickForm_Action_Display で、これはデフォルトのレンダラを使用してフォームを表示します。 出力内容を変更したい場合は、このハンドラのサブクラスを 作成する必要があります。 このアクションは、ページを表示する必要がある際に自動的にコールされます。 getButtonName() でボタンに関連付けられるべきでは ありません。
このアクションは、フォームの "グローバル" な送信ボタンに 関連付けなければなりません。単一ページのフォームや タブ形式の複数ページフォームでは "submit" ボタン、 あるいはウィザードでは "finish" ボタンに 関連付けることができます。このアクションのデフォルトハンドラは HTML_QuickForm_Action_Submit で、フォームの全ページの入力内容を検証したあとで、 'process' ハンドラをコールするか 無効な入力用のページを表示します。
このアクションは、(通常は) モーダルな複数ページフォーム (ウィザード) の "Next" ボタンに関連付けなければなりません。 このアクションのデフォルトハンドラは HTML_QuickForm_Action_Next で、現在のページの入力内容の妥当性を検証した後で、もし内容に問題がなければ (あるいはフォームがモーダルでなければ) 次のページにリダイレクトします。 モーダルな複数ページフォームの最後のページにいる場合は、 デフォルトの 'submit' ハンドラと同じように動作します。
このアクションは、(通常は) モーダルな複数ページフォーム (ウィザード) の "Back" ボタンに関連付けなければなりません。 このアクションのデフォルトハンドラは HTML_QuickForm_Action_Back で、前のページが存在する場合にそのページにリダイレクトします。 QFC 0.9.3 以降では、'back' アクションの際にはフォームの検証は行われなくなりました。
このアクションのデフォルトハンドラは HTML_QuickForm_Action_Jump で、単にフォーム内の指定したページへの HTTP リダイレクトを行います。 このアクションは getButtonName() でボタンに関連付けられるべきでは ありません。
このアクションは、デフォルトの 'submit' および 'next' (ウィザードの 最終ページの場合のみ) のハンドラとして、 フォームの送信処理が成功した (つまり、入力にエラーがなかった) 際に コールされます。このアクションにはデフォルトのハンドラが存在しません。 独自のハンドラを定義して、フォームの値を処理するために必要な すべてのロジックを実装する必要があります。
これ以外にも HTML_QuickForm_Action_Direct というデフォルトのハンドラがあり、これはデフォルトのアクションを 持っていません。 これはフォームの指定したページに移動する際に使用され、 Page::addAction() あるいは Controller::addAction() を使用して明示的に追加しなければなりません。その際には、 移動先のページの名前を $actionName に指定し、getButtonName() を使用して同じ名前でボタンにバインドします。
Page の handle() メソッドを使用しなければなりません。
$page->handle('action'); |
HTML_QuickForm_Action のサブクラスを作成し、必要な処理を perform() メソッドに追加します。作成したクラスを、addAction() で適切な名前を指定して Page あるいは Controller に追加します。
getButtonName() でこのアクションを何らかのボタンに バインドしたい場合は、 container() の中の値を保存することに注意しなければなりません。
フォームを作成する。
コンテナへの参照を取得する。
コンテナの ['values'][$pageName] および ['valid'][$pageName] 要素を指定する。
いつものように、 使用例はデフォルトのアクションハンドラのソースを参照ください。
コントローラは、<input type="image" /> コントロールにバインドしたアクションも正しく処理することができます。 何も特別なことをする必要はなく、単に getButtonName() でコントロールの名前を指定すればよいのです。
ハイパーリンクなどにアクションをバインドしたい場合には、 次のことを考慮する必要があります。フォームの値を取得するためには、 フォームを送信しなけらばなりません。 そのため、javascript などでフォームを送信する処理を記述し、 何らかの方法でコントローラにアクション名を渡す必要があります。
コントローラは、フォームのデータや検証状態を、 セッション内のコンテナに保持します。このコンテナには container() メソッドを使用してアクセスできます。 フォームをリセットするためには、このコンテナを消去する必要があります。 そのためには、container() に TRUE を渡します。
答えはきわめて簡単です。HTML_QuickForm_Controller の container() メソッドを使用して、このようにしなければなりません。
// 参照であることに注意 $data =& $page->controller->container(); $data['_my_stuff'] = $stuff; |
$data =& $page->controller->container(); $stuff = $data['_my_stuff']; |
Controller は、あなたが追加したデータについては 何も知らないことに注意しましょう。 exportValues() メソッドや類似のメソッドでこのデータが返されることを期待しないでください。 container() メソッドを使用し、自分でデータを抽出しなければなりません。 しかし、コンテナがリセットされる際には あなたが追加したデータも削除されます。
まず最初に、HTML_QuickForm_Page が HTML_QuickForm のサブクラスであること、 そのため親クラスの変更内容はすべて子クラスにも適用されるということを 理解してください。 HTML_QuickForm の レンダラについての節 および使用したいレンダラのドキュメントを 読むことをお勧めします。QuickForm 配布物の docs/renderers/ ディレクトリの中に、使用例があります。
すでに説明したとおり、もしページの出力内容をカスタマイズして ページの 'display' アクションの ハンドラとしてこのサブクラスのインスタンスを追加したいのなら、 HTML_QuickForm_Action_Display クラスのサブクラスを作成しなければなりません。 レンダラ固有のコードは、すべてその _renderForm() に含めます。
Controller によって発生する唯一の新しい問題は、 getButtonName() を使用してアクションにバインドしたボタンです。 動的なレンダラを使用している場合は、これは問題にはなりません。 というのも、要素の名前に気を使う必要がないからです。しかし、 静的なレンダラを使用してフォームを出力する場合には、 要素の名前を知っておく必要があります。
ここでは ITStatic レンダラを使用すると仮定しますが、 それ以外の静的レンダラでも同じようになります。 基本的に、3 つの選択肢があります。
getButtonName() で自動生成された名前を使用して、ボタン/プレースホルダを フォームに手動で追加します。この方法は 推奨されません。なぜなら、名前を気にするのは Controller 自身のみであるべきで、 直接使用すべきものではないからです。
自動的に命名されたボタンを グループ に追加します。グループにはお好みの名前をつけることができますが、 $appendName を false に設定することを忘れないでください。 ITStatic は、プレースホルダ {form_element_html} を発見すると、グループの HTML をそこに代入します。
テンプレートの中から getButtonName() をコールします。 テンプレートに次の内容を追加し、
<input type="submit" value="Bla-bla" name="func_buttonName('action')" ... /> |
$tpl->setCallbackFunction('buttonName', array(&$page, 'getButtonName')); |
この質問に貢献してくれた Donald Lobo に感謝します。
3 つのページからなるウィザードがあるとしましょう。
ページ 1 には、ユーザに次のページを選択させるコントロールがあります。
入力内容に応じて、ユーザはページ 2A あるいはページ 2B のどちらかに移動します。
ページ 2A および 2B のどちらからもページ 3 に移動します (これは、プログラミングに関する書籍では一般的に StateMachine と呼ばれているものです)。
QFC のデフォルトの HTML_QuickForm_Action_Next および HTML_QuickForm_Action_Back に基づいたアクションハンドラを作成する必要があります。 これは、ページレベルおよびコントローラレベルのどちらでも行うことが可能です。 ページレベルでサブクラスを作成するほうがシンプルですが、 複雑な StateMachine を使用するなら複数のサブクラスを作成することになります。
上の例の場合、ページ 1 の 'next' アクションは、 ユーザの入力内容に応じてページ 2 あるいはページ 3 のいずれかに 'user' を送信します。このハンドラは、訪れなかったほうのページに 大しても 'valid' フラグを設定します。
ページ 2A および 2B の 'back' アクションは、 ユーザをページ 1 に戻します。一方、'next' アクションはページ 3 に移動します。
最後に、ページ 3 の 'back' アクションハンドラは、 ページ 1 での入力内容に応じてページ 2A あるいは 2B のいずれかに移動します。
実際に動作する例は、statemachine.php ファイルです。