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

<?php
switch ($_REQUEST['action']) {
    case 
'foo'
        
doFoo(); 
        break;
    case 
'bar'
        
doBar(); 
        break;
    default:
        echo 
'Hello, world!';
}
?>

HTML_QuickForm_Controller is a bit more complex. There are three base classes:

  • HTML_QuickForm_Controller: this class extracts the action name from request and calls the appropriate handler. It includes several Pages.
  • HTML_QuickForm_Page: this class (extending HTML_QuickForm) represents a single page of a form.
  • HTML_QuickForm_Action: this class implements the Command design pattern, i.e. is essentially an OO callback.

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

Session initialization

This simple example does not use sessions since there is no need to pass data between pages. You'll need to use sessions when dealing with a real multipage form, though. HTML_QuickForm_Controller does not start a session automatically, you should explicitly call session_start() before instantiating the controller class.

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

Basic Controller usage

<?php
// Load the controller
require_once 'HTML/QuickForm/Controller.php';
// Load the base Action class (we will subclass it later)
require_once 'HTML/QuickForm/Action.php';

// Class representing a form
class FirstPage extends HTML_QuickForm_Page
{
    function 
buildForm()
    {
        
$this->_formBuilt true;

        
// Add some elements to the form
        
$this->addElement('header'null'QuickForm tutorial example');
        
$this->addElement('text''name''Enter your name:', array('size' => 50'maxlength' => 255));
        
// Note how we set the name of the submit button
        
$this->addElement('submit'$this->getButtonName('submit'), 'Send');

        
// Define filters and validation rules
        
$this->applyFilter('name''trim');
        
$this->addRule('name''Please enter your name''required'null'client');

        
$this->setDefaultAction('submit');
    }
}

// Action to process the form
class ActionProcess extends HTML_QuickForm_Action
{
    function 
perform(&$page$actionName)
    {
        echo 
'<h1>Hello, ' htmlspecialchars($page->exportValue('name')) . '!</h1>';
    }
}

$page =& new FirstPage('firstForm');

// We only add the 'process' handler, Controller will care for default ones
$page->addAction('process', new ActionProcess());

// Instantiate the Controller
$controller =& new HTML_QuickForm_Controller('tutorial');

// Set defaults for the form elements
$controller->setDefaults(array(
    
'name' => 'Joe User'
));

// Add the page to Controller
$controller->addPage($page);

// Process the request
$controller->run();
?>

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:

<?php
$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

<?php
$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

<?php
$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

<?php
$page 
=& new FirstPage('firstForm');
?>

and add our custom action handler to it

<?php
$page
->addAction('process', new ActionProcess());
?>

the 'process' action will be called by the default 'submit' action handler if the form is valid.

Then we instantiate the controller

<?php
$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

<?php
$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

<?php
$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:

  • Wizard: form pages contain 'Next' and 'Back' buttons and you can't go to the next page unless the current page is valid.
  • Tabbed form: form has several pages and buttons allow to go directly to the corresponding page. Form is validated only when the global 'Submit' button is pressed.
HTML_QuickForm_Controller (Previous) Understanding package features (Next)
Last updated: Thu, 27 Nov 2014 — Download Documentation
Do you think that something on this page is wrong? Please file a bug report or add a note.
View this page in:

User Notes:

Note by: Ed Greenberg
Look in the doc directory under pear...

pear/doc/HTML_QuickForm_Controller/examples/wizard.php

and others
Note by: powtac@gmx.de
Couldn't there be a example with 2 or more quickform pages?