Renderers
Introduction
Renderers in HTML_QuickForm2 are classes that output the form. They either generate the resultant HTML themselves or represent the form in some intermediate format that can later be used by e.g. a template engine.
Renderers also contain a Javascript builder object that aggregates code needed for client-side validation and Javascript-backed elements. This means that rendering step is mandatory if you are using any of these.
A new feature in HTML_QuickForm2 compared to HTML_QuickForm is the ability to extend Renderer functionality by plugins.
Typical form output workflow:
<?php
require_once 'HTML/QuickForm2/Renderer.php';
$renderer = HTML_QuickForm2_Renderer::factory('custom');
// common options
$renderer->setOption(array(
'group_errors' => true,
'required_note' => 'Fields labeled in 36pt bold red font are required'
));
// renderer-specific setup
$renderer->doSomeOutputCustomization();
// ...
$renderer->doAnotherOutputCustomization();
// process the form
$form->render($renderer);
// Output the links to JS libraries, if used
foreach ($renderer->getJavascriptBuilder()->getLibraries() as $link) {
echo $link . "\n";
}
// Assuming the renderer implements __toString()
echo $renderer;
?>
The following renderers are installed with the package:
Common Renderer API
setOption() method is used to set the values of configuration parameters and getOption() method to read them. Passing an unknown parameter name to these methods will result in an Exception. The following parameters are defined in the base class and known to all Renderers:
Parameter name | Description | Expected type | Default value |
---|---|---|---|
group_hiddens |
Whether to group hidden elements together or render them where they were added. | boolean | TRUE |
group_errors |
Whether to group error messages or render them alongside elements they apply to. | boolean | FALSE |
errors_prefix |
Leading message for grouped errors. | string | 'Invalid information entered:' |
errors_suffix |
Trailing message for grouped errors. | string | 'Please correct these fields.' |
required_note |
Note displayed if the form contains required elements. | string | '<em>*</em> denotes required fields.' |
setJavascriptBuilder() sets a Javascript builder object used during form rendering and getJavascriptBuilder() returns that object (if an object was not set previosly a new instance is created). Package users will mostly need to interact with this object to properly include Javascript library files.
reset() method clears all accumulated data. It is called automatically when rendering a HTML_QuickForm2 object, but must be called manually when rendering form elements separately.
Creating Renderer objects
It is only possible to instantiate built-in Renderers through HTML_QuickForm2_Renderer::factory() as their __construct() methods are declared protected. Moreover, factory() returns an instance of HTML_QuickForm2_Renderer_Proxy wrapping around a specific Renderer instance. This setup is needed for plugin support and serves as a workaround for PHP shortcomings:
- It is impossible (before PHP 5.4) to add methods to an object at runtime without using some esoteric extension like runkit;
- It is impossible to define properties/methods accessible to class and related classes (e.g. Java's protected modifier allows access from classes of the same package).
Proxy and factory() are used to aggregate methods from several classes and to limit access to them from outside: all fields and methods of a Renderer instance are public, but the only path to that instance is through a Proxy that only allows access to explicitly "published" methods and methods defined in base class. Plugins, however, have direct access to a Renderer instance and thus can freely use its API.
It is definitely possible to create a subclass of a built-in Renderer with a public __construct() method and do not use factory(). This will, however, prevent plugins from working.
Renderer Plugins
Plugins are the means to enhance Renderer functionality at runtime. From user's point of view the Renderer object simply gets a new method:
<?php
require_once 'HTML/QuickForm2/Renderer.php';
HTML_QuickForm2_Renderer::registerPlugin('foo', 'Foo_PluginBar');
$foo = HTML_QuickForm2_Renderer::factory('foo');
$foo->doBar();
// This will also work
HTML_QuickForm2_Renderer::registerPlugin('foo', 'Foo_PluginMore');
$foo->performMore();
?>
The main puprose of plugins is to allow custom elements which require some complex output behaviour to define that behaviour in separate classes leveraging existing Renderer code. Previously it was usually implemented in the element class itself, leading to unnecessary bloat and code duplication.
dualselect.php
example installed with the package shows, among other things, how to create a renderer plugin for a custom element.