If you are already familiar with MVC frameworks, then you probably know: controller is a
component that accepts user input and instructs other components to perform actions based on that
input. HTML_QuickForm2_Controller is somewhat smaller in scope than a typical
framework controller since it only deals with forms. When using the Controller, an action name is
sent in GET
or POST
data, usually by clicking a specially
named button. This name contains id
of one of the form pages added to
Controller and name of action handler to call (e.g. 'next'
for going forward
in a wizard), that data is extracted and an appropriate action handler is called.
Key features:
Key classes and interfaces:
HTML_QuickForm2_Controller is a rewrite of PHP4 HTML_QuickForm_Controller, so if you are already using the latter you can go to migration guide which contains step-by-step instructions for porting your scripts to new package.
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_QuickForm2_Controller does not start a session automatically, you should explicitly call session_start() before instantiating the controller class.
More complex usage examples are installed with the package. Along with a form similar to the one below they include two multipage forms: a tabbed form and a wizard.
The same example form that was used in the package's tutorial will now be rewritten using the Controller:
Builds and processes a form with a single input field, using Controller
<?php
// Load the main class
require_once 'HTML/QuickForm2.php';
// Load the controller
require_once 'HTML/QuickForm2/Controller.php';
// Load the Action interface (we will implement it)
require_once 'HTML/QuickForm2/Controller/Action.php';
// Class representing a form page
class TutorialPage extends HTML_QuickForm2_Controller_Page
{
protected function populateForm()
{
// Add some elements to the form
$fieldset = $this->form->addElement('fieldset')->setLabel('QuickForm2_Controller tutorial example');
$name = $fieldset->addElement('text', 'name', array('size' => 50, 'maxlength' => 255))
->setLabel('Enter your name:');
// We set the name of the submit button so that it binds to default 'submit' handler
$fieldset->addElement('submit', $this->getButtonName('submit'),
array('value' => 'Send!'));
// The action to call if a user presses Enter rather than clicks on a button
$this->setDefaultAction('submit');
// Define filters and validation rules
$name->addFilter('trim');
$name->addRule('required', 'Please enter your name');
}
}
// Action to process the form after successful validation
class TutorialProcess implements HTML_QuickForm2_Controller_Action
{
public function perform(HTML_QuickForm2_Controller_Page $page, $name)
{
$values = $page->getController()->getValue();
echo '<h1>Hello, ' . htmlspecialchars($values['name']) . '!</h1>';
}
}
$page = new TutorialPage(new HTML_QuickForm2('tutorial'));
// We only add the custom 'process' handler, Controller will care for default ones
$page->addHandler('process', new TutorialProcess());
$controller = new HTML_QuickForm2_Controller('tutorial');
// Set defaults for the form elements
$controller->addDataSource(new HTML_QuickForm2_DataSource_Array(array(
'name' => 'Joe User'
)));
$controller->addPage($page);
// Process the request
$controller->run();
?>
You may note that the above code is more verbose than the original. While that is definitely
true, to make a three page wizard you'll only need to create three subclasses of HTML_QuickForm2_Controller_Page, a
'process'
handler and add them to Controller, which already has default
handlers for typical 'Back'
and 'Next'
buttons. It will
require a non-trivial amount of programming without the Controller infrastructure.
To define pages for your controller you need to subclass HTML_QuickForm2_Controller_Page implementing its abstract populateForm() method. Note that this method will be called on demand (i.e. only when the user sees the form in question), so it is better performance-wise to keep all form-building code in it than to pass a pre-populated instance of HTML_QuickForm2 to page's constructor.
Most of the code in the method just repeats what was done in the original tutorial, however some of it requires explanation:
<?php
// We set the name of the submit button so that it binds to default 'submit' handler
$fieldset->addElement('submit', $this->getButtonName('submit'),
array('value' => 'Send!'));
// The action to call if a user presses Enter rather than clicks on a button
$this->setDefaultAction('submit');
?>
The first line uses getButtonName() to
set a special name for form's submit button and thus trigger a 'submit'
action on a 'tutorial'
form when that button is clicked (default handler for
such action is implemented in HTML_QuickForm2_Controller_Action_Submit). The second one sets an action to
trigger when no submit button is clicked (e.g. user presses Enter
instead of
clicking). Under the hood this is done by adding an instance of HTML_QuickForm2_Controller_DefaultAction to the form.
You'll usually need custom handlers for only two actions:
'process'
'process'
handler is, obviously, completely application-specific and will
usually deal with storing the form values somewhere. When creating a custom
'display'
handler it is easiest to subclass HTML_QuickForm2_Controller_Action_Display and override its renderForm()
method to use a Renderer or do any other tweaks you like.
First we instantiate the custom Page class and add a custom action handler to it
<?php
$page = new TutorialPage(new HTML_QuickForm2('tutorial'));
// We only add the custom 'process' handler, Controller will care for default ones
$page->addHandler('process', new TutorialProcess());
?>
We don't bother with other action handlers as Controller will automatically load and use them.
Then we instantiate the controller
<?php
$controller = new HTML_QuickForm2_Controller('tutorial');
?>
Note that Controller needs an id
and it should be unique if you have several
Controllers in application, as it is used for storing values in session.
Then we add a DataSource and the page to the Controller
<?php
// Set defaults for the form elements
$controller->addDataSource(new HTML_QuickForm2_DataSource_Array(array(
'name' => 'Joe User'
)));
$controller->addPage($page);
?>
While it is possible to add DataSource to an instance of HTML_QuickForm2 within Page instead, the above code allows setting the default values for the whole (possibly multipage) form. Note also that Controller's DataSources, unlike form's, are stored in session.
Finally we call the Controller's run() method
<?php
$controller->run();
?>
which takes care of finding the name of the current action and calling the necessary handler.