Introduction

Introduction -- What is this package useful for

Why "Controller"?

This package implements a PageController design pattern, which essentially means that there is a single page processing requests and actions this page performs depend on parameters passed in GET or POST data. The pattern is described in more detail on Martin Fowler's website and WACT project website.

What does this mean in application to QuickForm: we have a single script which shows and validates different forms depending on data in request. This allows to fairly easy build very complex forms consisting of several pages (think wizards and such).

The most basic implementation of the PageController pattern would look like
switch ($_REQUEST['action']) {
    'foo': 
        doFoo(); 
        break;
    'bar': 
        doBar(); 
        break;
    default:
        echo 'Hello, world!';
}
HTML_QuickForm_Controller is a bit more complex. There are three base classes:

The action sent in request consists of a page name and an action name, it defines which Page will process the request (e.g. display or validate the form) and what exactly this Page should do.

Basic usage example

To ease understanding of this package's features, lets take an example form from HTML_QuickForm tutorial and redo it using HTML_QuickForm_Controller:

You may note that the code is more verbose than the original. That is true, but to make a three page wizard-type form you'll only need to create three subclasses of HTML_QuickForm_Page and 'process' event handler based on HTML_QuickForm_Action and add them to Controller, while without the Controller infrastructure it will require a non-trivial amount of programming.

Creating custom pages

You need to subclass HTML_QuickForm_Page and override its buildForm() method. Its contents are pretty self-explanatory (if you are familiar with QuickForm), except for a few things:
$this->_formBuilt = true;
Form building is a "heavy" operation, thus we call buildForm() only when necessary. To prevent calling it twice (and getting two sets of elements instead of one) we set $_formBuilt property.

The second notable line is
$this->addElement('submit', $this->getButtonName('submit'), 'Send');
We use getButtonName() method to set the submit button's name and thus to trigger a 'submit' action when the button is clicked.

The third thing is
$this->setDefaultAction('submit');
The user can submit the form by pressing Enter button, not by clicking on any of the form buttons. Most browsers will not consider any submit button as clicked in this case and will not send its name. setDefaultAction() sets the action (by adding a special hidden element to the form) that will be called in this case.

Creating custom actions

You'll usually need to create handlers for two actions: 'process' and 'display'. While it is difficult to say anything about the former, as only you know how to process your form, for the latter you'll need to subclass HTML_QuickForm_Action_Display and override its _renderForm() method to call the appropriate Renderer and do form output customization.

Tying this all together

Next we instantiate the page class defined above
$page =& new FirstPage('firstForm');
and add our custom action handler to it
$page->addAction('process', new ActionProcess());
the 'process' action will be called bu default 'submit' action handler if the form is valid.

Then we instantiate the controller
$controller =& new HTML_QuickForm_Controller('tutorial');
Note that the name is a required parameter, and if you will have several Controllers in your application they should have different names, as the names are used to store values in sessions.

Then we set the defaults for the form and add the page to it
$controller->setDefaults(array(
    'name' => 'Joe User'
));
$controller->addPage($page);
It is perfectly legal to do call Page's setDefaults() from within buildForm(), but the former approach allows to set the defaults for the form as a whole, while the latter only for the page in question.

Finally we call the Controller's run() method
$controller->run();
which will take care of finding the name of the current action and calling the necessary handler. That's all.

Advanced usage examples

...are available in the package archive. Along with the example similar to the provided above, there are two multipage forms: