このパッケージは、PageController デザインパターンを実装したものです。 これは、リクエストの受け取りと (受け取った GET データあるいは POST データに依存した) アクションの実行をひとつのページで行うことを意味します。 PageController パターンについては、 Martin Fowler のウェブサイト および WACT プロジェクトのウェブサイト でより詳しく説明されています。
QuickForm においてこれがどのような意味を持つかというと、 ひとつのスクリプト内で、リクエストの内容に応じて さまざまなフォームの表示や入力内容の検証を行うということです。 これにより、複数ページで構成される複雑なフォーム (ウィザードなどを思い浮かべでください) を ほんとうに簡単に作成できるようになります。
PageController パターンの最も基本的な実装は、以下のようになります。
<?php
switch ($_REQUEST['action']) {
case 'foo':
doFoo();
break;
case 'bar':
doBar();
break;
default:
echo 'Hello, world!';
}
?>
HTML_QuickForm_Controller はこれより少しだけ複雑で、 3 つの基底クラスが存在します。
リクエストで送信されるアクションは ページ名とアクション名で構成され、それによって どのページ (例: 画面表示・フォームの検証など) がリクエストを処理するか・ そのページが何を行うのか が決まります。
セッションの初期化ページ間でのデータのやりとりの必要がないため、この例ではセッションを使用しません。 しかし、実際に複数ページのフォームを使用する際にはきっとセッションが必要となるでしょう。 HTML_QuickForm_Controller は、セッションを自動的には開始 しません。コントローラクラスのインスタンスを作成する前に、 session_start() を明示的にコールする必要があります。
このパッケージの機能について理解するため、 HTML_QuickForm チュートリアル の例を HTML_QuickForm_Controller で書き直してみましょう。
基本的なコントローラの使用法
<?php
// コントローラを読み込みます
require_once 'HTML/QuickForm/Controller.php';
// 基底アクションクラスを読み込みます
// (これを継承したクラスをあとで作成します)
require_once 'HTML/QuickForm/Action.php';
// フォームを表すクラス
class FirstPage extends HTML_QuickForm_Page
{
function buildForm()
{
$this->_formBuilt = true;
// フォームに要素を追加します
$this->addElement('header', null, 'QuickForm tutorial example');
$this->addElement('text', 'name', 'Enter your name:', array('size' => 50, 'maxlength' => 255));
// submit ボタンの名前を設定する方法に注意してください
$this->addElement('submit', $this->getButtonName('submit'), 'Send');
// フィルタと検証ルールを追加します
$this->applyFilter('name', 'trim');
$this->addRule('name', 'Please enter your name', 'required', null, 'client');
$this->setDefaultAction('submit');
}
}
// フォームを処理するアクション
class ActionProcess extends HTML_QuickForm_Action
{
function perform(&$page, $actionName)
{
echo '<h1>Hello, ' . htmlspecialchars($page->exportValue('name')) . '!</h1>';
}
}
$page =& new FirstPage('firstForm');
// 'process' ハンドラのみを追加します
// コントローラはこれをデフォルトとして使用します
$page->addAction('process', new ActionProcess());
// コントローラをインスタンス化します
$controller =& new HTML_QuickForm_Controller('tutorial');
// フォーム要素のデフォルト値を設定します
$controller->setDefaults(array(
'name' => 'Joe User'
));
// コントローラにページを追加します
$controller->addPage($page);
// リクエストを処理します
$controller->run();
?>
もとのコードより冗長になってしまっていると思われるかもしれません。
確かにそのとおりですが、3 ページからなるウィザード形式のフォームを
作成する場合のことを考えてみましょう。HTML_QuickForm_Controller
を使用している場合は、
HTML_QuickForm_Page
のサブクラスを 3 つ作成し、
HTML_QuickForm_Action
に基づいた 'process'
イベントのハンドラを作成して
それらをコントローラに追加するだけですみます。
しかし、HTML_QuickForm_Controller を使用していない場合は
大量のプログラミングが必要となることでしょう。
まず HTML_QuickForm_Page のサブクラスを作成し、 buildForm() メソッドをオーバーライドする必要があります。 (QuickForm になじみが深い方なら) その内容は見慣れているでしょうが、多少の例外があります。
<?php
$this->_formBuilt = true;
?>
フォームの作成は "重たい" 処理です。そのため、
本当に必要な場合にのみ buildForm()
をコールするようにします。この処理を 2 回コールする
(そして要素のセットを 2 回取得する) ことを避けるためには
$_formBuilt
プロパティを設定します。
2 番目に注意すべき点は、以下の行です。
<?php
$this->addElement('submit', $this->getButtonName('submit'), 'Send');
?>
getButtonName()
メソッドを使用して送信ボタンの名前を指定し、
ボタンがクリックされた際に 'submit'
アクションが実行されるようにしています。
3 番目は、以下の行です。
<?php
$this->setDefaultAction('submit');
?>
フォームのボタンをクリックする以外にも、Enter キーを押すことで フォームを送信することができます。このような場合 ほとんどのブラウザでは特定の送信ボタンが押されたとは考えず、 そのためボタンの名前が送信されません。 setDefaultAction() で、このような場合にコールされるアクションを (フォームに特別な hidden フィールドを追加することで) 設定します。
通常は、'process'
および 'display'
の 2 つのアクションについてのハンドラを作成する必要があります。
前者については、ここで説明することは困難です。というのも、
そのフォームで何をどのように処理すべきなのかを知っているのは
あなた自身だけだからです。後者については、
HTML_QuickForm_Action_Display
のサブクラスを作成してその _renderForm()
メソッドをオーバーライドし、適切な
レンダラ
をコールして独自の出力を行えるようにする必要があります。
次に、上で定義したページクラスのインスタンスを作成します。
<?php
$page =& new FirstPage('firstForm');
?>
そして、そこに独自のアクションハンドラを追加します。
<?php
$page->addAction('process', new ActionProcess());
?>
フォームの入力内容が有効だった場合は、
'submit'
アクションのデフォルトハンドラとして
'process'
アクションがコールされます。
それから、コントローラのインスタンスを作成します。
<?php
$controller =& new HTML_QuickForm_Controller('tutorial');
?>
コントローラ名が必須パラメータであることに注意しましょう。 もしアプリケーション内で複数のコントローラを使用するのであれば、 それぞれ別の名前を指定する必要があります。なぜなら、 セッション内に値を保存する際にコントローラ名が使用されるからです。
それから、フォームのデフォルト値を設定してそれをページに追加します。
<?php
$controller->setDefaults(array(
'name' => 'Joe User'
));
$controller->addPage($page);
?>
この方法以外にも、buildForm() の中でページの setDefaults() をコールする方法もあります。しかし、前者のアプローチが すべてのフォームのデフォルト値を一度に指定できるのに対して、 後者の方法では特定のページについてしか設定できません。
最後に、コントローラの run() メソッドをコールします。
<?php
$controller->run();
?>
これにより、現在のアクション名を取得して適切なハンドラがコールされます。 以上です。
は、パッケージのアーカイブに含まれています。 上で説明した例と似たものに加えて、 さらに 2 つの複数ページフォームの例が含まれています。
'Next'
ボタンおよび 'Back'
ボタンが含まれており、
現在のページの入力内容が有効でない限り次のページには進めません。
'Submit'
ボタンが押されたときにのみ
入力内容が検証されます。