導入

導入 -- このパッケージを使用すると、何がうれしいのか

なぜ "Controller" なの?

このパッケージは、PageController デザインパターンを実装したものです。 これは、リクエストの受け取りと (受け取った GET データあるいは POST データに依存した) アクションの実行をひとつのページで行うことを意味します。 PageController パターンについては、 Martin Fowler のウェブサイト および WACT プロジェクトのウェブサイト でより詳しく説明されています。

QuickForm においてこれがどのような意味を持つかというと、 ひとつのスクリプト内で、リクエストの内容に応じて さまざまなフォームの表示や入力内容の検証を行うということです。 これにより、複数ページで構成される複雑なフォーム (ウィザードなどを思い浮かべでください) を ほんとうに簡単に作成できるようになります。

PageController パターンの最も基本的な実装は、以下のようになります。
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 で書き直してみましょう。

例 47-1基本的なコントローラの使用法

// コントローラを読み込みます
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 になじみが深い方なら) その内容は見慣れているでしょうが、多少の例外があります。
$this->_formBuilt = true;
フォームの作成は "重たい" 処理です。そのため、 本当に必要な場合にのみ buildForm() をコールするようにします。この処理を 2 回コールする (そして要素のセットを 2 回取得する) ことを避けるためには $_formBuilt プロパティを設定します。

2 番目に注意すべき点は、以下の行です。
$this->addElement('submit', $this->getButtonName('submit'), 'Send');
getButtonName() メソッドを使用して送信ボタンの名前を指定し、 ボタンがクリックされた際に 'submit' アクションが実行されるようにしています。

3 番目は、以下の行です。
$this->setDefaultAction('submit');
フォームのボタンをクリックする以外にも、Enter キーを押すことで フォームを送信することができます。このような場合 ほとんどのブラウザでは特定の送信ボタンが押されたとは考えず、 そのためボタンの名前が送信されません。 setDefaultAction() で、このような場合にコールされるアクションを (フォームに特別な hidden フィールドを追加することで) 設定します。

独自のアクションを作成する

通常は、'process' および 'display' の 2 つのアクションについてのハンドラを作成する必要があります。 前者については、ここで説明することは困難です。というのも、 そのフォームで何をどのように処理すべきなのかを知っているのは あなた自身だけだからです。後者については、 HTML_QuickForm_Action_Display のサブクラスを作成してその _renderForm() メソッドをオーバーライドし、適切な レンダラ をコールして独自の出力を行えるようにする必要があります。

すべてをひとつにまとめる

次に、上で定義したページクラスのインスタンスを作成します。
$page =& new FirstPage('firstForm');
そして、そこに独自のアクションハンドラを追加します。
$page->addAction('process', new ActionProcess());
フォームの入力内容が有効だった場合は、 'submit' アクションのデフォルトハンドラとして 'process' アクションがコールされます。

それから、コントローラのインスタンスを作成します。
$controller =& new HTML_QuickForm_Controller('tutorial');
コントローラ名が必須パラメータであることに注意しましょう。 もしアプリケーション内で複数のコントローラを使用するのであれば、 それぞれ別の名前を指定する必要があります。なぜなら、 セッション内に値を保存する際にコントローラ名が使用されるからです。

それから、フォームのデフォルト値を設定してそれをページに追加します。
$controller->setDefaults(array(
    'name' => 'Joe User'
));
$controller->addPage($page);
この方法以外にも、buildForm() の中でページの setDefaults() をコールする方法もあります。しかし、前者のアプローチが すべてのフォームのデフォルト値を一度に指定できるのに対して、 後者の方法では特定のページについてしか設定できません。

最後に、コントローラの run() メソッドをコールします。
$controller->run();
これにより、現在のアクション名を取得して適切なハンドラがコールされます。 以上です。

高度な使用例

は、パッケージのアーカイブに含まれています。 上で説明した例と似たものに加えて、 さらに 2 つの複数ページフォームの例が含まれています。