Source for file Form.php
Documentation is available at Form.php
* A package designed to make creating input forms easy for PHP-GTK 2 packages
* This package was designed to make it easy to add forms to PHP-GTK 2 packages
* and applications. The package is modeled after HTML_QuickForm but cannot
* extend HTML_QuickForm because HTML_QuickForm is tied too tightly to HTML.
* PHP-GTK 2 forms are very similar to HTML forms. They consist of a handful of
* different input types and the data is submitted all together when a user
* clicks the submit button. The difference is how the user values are
* submitted and stored. HTML forms submit data in an HTTP request using either
* GET or POST. PHP-GTK 2 forms call a callback which is then responsible for
* In HTML_QuickForm, all form elements extend a common base class. In PHP-GTK
* 2 this is not possible because the elements need to be added to containes.
* To be added to a container a class must extends GtkWidget. While it is not
* possible to force all form elements to inherit from the same base class we
* can use an interface to enforce some consistency.
* In order to make it possible to create elements on the fly without
* restricting the number of constructor arguments this package must use the
* Reflection API. This means that the user must have reflection enabled.
* @todo At least one group class.
* @todo Element classes (Done: Text, Password, Submit, Cancel)
* @todo Rule classes (Done: Required)
* @package Structures_Form
* @copyright Copyright 2006 Scott Mattocks
const ERROR_ADD_ELEMENT_DOUBLEADD = -1;
const ERROR_ADD_RULE_DOUBLEADD = -2;
const ERROR_UNREGISTERED_ELEMENT = -3;
const ERROR_UNREGISTERED_RULE = -4;
const ERROR_REGISTRATION_ELEMENT = -5;
const ERROR_REGISTRATION_ELEMENT_DOUBLEREG = -6;
const ERROR_REGISTRATION_RULE = -7;
const ERROR_REGISTRATION_RULE_DOUBLEREG = -8;
const ERROR_UNREGISTRATION_ELEMENTINUSE = -9;
const ERROR_UNREGISTRATION_ELEMENT = -10;
const ERROR_UNREGISTRATION_RULEINUSE = -11;
const ERROR_UNREGISTRATION_RULE = -12;
const ERROR_LACKSINTERFACE_ELEMENT = -13;
const ERROR_LACKSINTERFACE_ELEMENTSET = -14;
const ERROR_LACKSINTERFACE_RULE = -15;
const ERROR_LACKSINTERFACE_GROUP = -16;
const ERROR_LACKSINTERFACE_RENDERER = -17;
const ERROR_NONEXISTENT_CLASS = -18;
const ERROR_NONEXISTENT_FILE = -19;
const ERROR_NONEXISTENT_ELEMENT = -20;
const ERROR_NONEXISTENT_CALLBACK = -21;
const ERROR_RENDER_FAILURE = -22;
const ELEMENTSET_PATH = 'Structures/Form/Element/';
const ELEMENTSET_PREFIX = 'Structures_Form_Element_';
const DEFAULT_ERRORCALLBACK = 'defaultErrorCallback';
* The name of the rule defining required elements.
const REQUIRED_RULE = 'required';
* The rules to be applied to each element.
* The registered element types.
* The method to call after values are collected from a submitted form.
* @var mixed string or array
* The callback for error handling.
* @var mixed string or array
* Send the widgets to the callback instead of the values.
* The default values for the form elements.
* A note identifying the required field marker.
* The renderer should prepend the required symbol to the note.
* A symbol identifying the required fields.
* The renderer should provide some sort of formatting to make the symbol
* The default renderer class defined by the element set.
* The path to the default renderer defined by the element set.
* The object responsible for displaying the form.
* An array relating error codes to error messages.
protected static $errorMsgs =
Structures_Form ::ERROR_ADD_ELEMENT_DOUBLEADD =>
'Cannot add the element. The element or element name already exists in the form.',
Structures_Form ::ERROR_ADD_RULE_DOUBLEADD =>
'Cannot create the rule. A rule of this type already exists in the form',
Structures_Form ::ERROR_UNREGISTERED_ELEMENT =>
'Cannot add the element. The type is not registered.',
Structures_Form ::ERROR_UNREGISTERED_RULE =>
'Cannot add the rule. The type is not registered.',
Structures_Form ::ERROR_REGISTRATION_ELEMENT =>
'An error occured while trying to register the element.',
Structures_Form ::ERROR_REGISTRATION_ELEMENT_DOUBLEREG =>
'The element could not be registered. An element of this type or with the same name is already registered.',
Structures_Form ::ERROR_REGISTRATION_RULE =>
'An error occured while trying to register the rule.',
Structures_Form ::ERROR_REGISTRATION_RULE_DOUBLEREG =>
'The rule could not be registered. A rule of this type or with the same name is already registered.',
Structures_Form ::ERROR_UNREGISTRATION_ELEMENTINUSE =>
'The element could not be unregistered. It is currently in use.',
Structures_Form ::ERROR_UNREGISTRATION_ELEMENT =>
'An error occured while trying to unregister the element.',
Structures_Form ::ERROR_UNREGISTRATION_RULEINUSE =>
'The rule could not be unregistered. It is currently in use.',
Structures_Form ::ERROR_UNREGISTRATION_RULE =>
'An error occured while trying to unregister the rule.',
Structures_Form ::ERROR_LACKSINTERFACE_ELEMENT =>
'The element could not be added to the form. It does not implement the needed interface.',
Structures_Form ::ERROR_LACKSINTERFACE_ELEMENTSET =>
'The element set could not be registered. It does not implement the needed interface.',
Structures_Form ::ERROR_LACKSINTERFACE_RULE =>
'The rule could not be added to the form. It does not implement the needed interface.',
Structures_Form ::ERROR_LACKSINTERFACE_GROUP =>
'The element group could not be added. It does not implement the needed interface.',
Structures_Form ::ERROR_LACKSINTERFACE_RENDERER =>
'The renderer could not be set. It does not implement the needed interface.',
Structures_Form ::ERROR_NONEXISTENT_CLASS =>
'The class does not exist.',
Structures_Form ::ERROR_NONEXISTENT_FILE =>
'The file could not be read or does not exist.',
Structures_Form ::ERROR_NONEXISTENT_ELEMENT =>
'The element does not exist.',
Structures_Form ::ERROR_NONEXISTENT_CALLBACK =>
'The callback does not exist.',
Structures_Form ::ERROR_RENDER_FAILURE =>
'An error occurred while trying to render the form.'
* Constructor. Sets the callbacks then registers any default element or
* A callback must be passed in so that the form knows what to do with the
* values that are collected by the form. Optionally, the user may tell the
* form to pass the widgets themselves, not the values, to the callback.
* The user may also define an error callback, which will be called if any
* rules are viloated. If no error callback is defined, the default
* callback ($this->defaultErrorCallback()) will be used. The default just
* passes the errors on to the renderer.
* @param mixed $callback The method to call when the form is
* @param boolean $submitObjects Send the widgets to the callback not the
* @param mixed $errorCallback A callback for handling errors.
* @throws Structures_Form_Exception
// Make sure the callback exists.
require_once 'Structures/Form/Exception.php';
throw new Structures_Form_Exception (self ::getErrorMessage (self ::ERROR_NONEXISTENT_CALLBACK ),
self ::ERROR_NONEXISTENT_CALLBACK
// Set the submit callback.
// Set the error handling callback.
$errorCallback = array ($this, self ::DEFAULT_ERRORCALLBACK );
// Set whether or not we want to send the objects.
// Register default rules.
* Sets the error callback.
* @param mixed $callback A string or array.
* Returns the submit callback.
* @return mixed A string or array.
* Returns the error callback.
* @return mixed A string or array.
* Registers a set of elements.
* Only elements types that are registered with Structures_Form may be
* added to the form. This helps to ensure that the elements implement the
* Element sets must also define a default renderer.
* To avoid overhead, type registration is not checked until the type is
* registerElement may throw an exception that will be passed along to the
* @param string $elementSet The name of an element set.
* @return boolean true if the element set was registered.
* @throws Structures_Form_Exception
// Try to get the element set.
if (!$this->isIncludable(self ::ELEMENTSET_PATH . $elementSet . '.php')) {
require_once 'Structures/Form/Exception.php';
throw new Structures_Form_Exception (self ::getErrorMessage (self ::ERROR_NONEXISTENT_FILE ),
self ::ERROR_NONEXISTENT_FILE
// Include the element set file.
require_once self ::ELEMENTSET_PATH . $elementSet . '.php';
// Get the correct element set classname.
$class = self ::ELEMENTSET_PREFIX . $elementSet;
// Instantiate the calss. The class must be instantiated to use
// instanceof. If there was only one method it might not be worth
// instantiating the class but since we have two methods we might as
// well. I know the methods can be called statically but this is
// Check to see if the correct interface is implemented
require_once 'Structures/Form/ElementSetInterface.php';
require_once 'Structures/Form/Exception.php';
throw new Structures_Form_Exception (self ::getErrorMessage (self ::ERROR_LACKSINTERFACE_ELEMENTSET ),
self ::ERROR_LACKSINTERFACE_ELEMENTSET
// Register the element set.
foreach ($eSet->getElementSet () as $element) {
// Set the default renderer.
$renderer = $eSet->getDefaultRenderer ();
* Registers the default rule types.
* Rule objects are used to validate the values of the form elements before
* they are submitted to the callback. If an elements value violates a rule
* a rule callback will be called which allows the user to handle errors in
* their own way. All violations are collected on each submit and then
* passed off to the rule callback.
* Only registered rules may be applied to a form element.
* All registered rules must implement the Structures_Form_RuleInterface.
* To avoid overhead, a rule is not checked until it is applied to a form
// Create an array of the default rules.
array (self ::REQUIRED_RULE ,
'Structures_Form_Rule_Required',
'Structures/Form/Rule/Required.php'
'Structures_Form_Rule_Regex',
'Structures/Form/Rule/Regex.php'
'Structures_Form_Rule_Alpha',
'Structures/Form/Rule/Alpha.php'
'Structures_Form_Rule_Numeric',
'Structures/Form/Rule/Numeric.php'
'Structures_Form_Rule_NumericRange',
'Structures/Form/Rule/NumericRange.php'
'Structures_Form_Rule_LengthRange',
'Structures/Form/Rule/LengthRange.php'
'Structures_Form_Rule_AlphaNumeric',
'Structures/Form/Rule/AlphaNumeric.php'
foreach ($defaultRules as $rule) {
* Returns an error message for the given error code.
* @param integer $errorCode The error code to get a message for.
* @return string An error message.
return self ::$errorMsgs[$errorCode];
* Creates and adds an element to the form.
* Only elements types that are registered with Structures_Form may be added
* to the form. This helps to ensure that the elements implement the proper
* To avoid overhead, type registration is not checked until the type is
* This method passes any extra arguments on to the element constructor.
* This allows one method to be used for creating many types of elements.
* The exact number and type of arguments that is passed to this method
* varies depending on the type of element to be created. If the wrong
* number or type of arguments is passed, the element constructor should
* An exception may be thrown by createElement or addElementObject. If so
* it will be bubble up through this method.
* @param string $type The element type.
* @param string $name The element name.
* @return object A Structures_Form element
* @throws Structures_Form_Exception
// Freak out if the element name is already in use.
require_once 'Structures/Form/Exception.php';
throw new Structures_Form_Exception (self ::getErrorMessage (self ::ERROR_ADD_ELEMENT_DOUBLEADD ),
self ::ERROR_ADD_ELEMENT_DOUBLEADD
// Add the element to the form.
* Inserts an element object at the given location.
* Only elements types that are registered with Structures_Form may be added
* to the form. This helps to ensure that the elements implement the proper
* To avoid overhead, type registration is not checked until the type is
* @param object $element The element object.
* @return object The inserted object.
// Make sure the type is registered.
require_once 'Structures/Form/Exception.php';
throw new Structures_Form_Exception (self ::getErrorMessage (self ::ERROR_UNREGISTERED_ELEMENT ),
self ::ERROR_UNREGISTERED_ELEMENT
// Make sure the element implements the needed interface.
require_once 'Structures/Form/ElementInterface.php';
require_once 'Structures/Form/Exception.php';
throw new Structures_Form_Exception (self ::getErrorMessage (self ::ERROR_LACKSINTERFACE_ELEMENT ),
self ::ERROR_LACKSINTERFACE_ELEMENT
// Make sure an element with this name isn't already in the form.
require_once 'Structures/Form/Exception.php';
throw new Structures_Form_Exception (self ::getErrorMessage (self ::ERROR_ADD_ELEMENT_DOUBLEADD ),
self ::ERROR_ADD_ELEMENT_DOUBLEADD
// Make sure this specific element was not already added.
if ($elem === $element) {
require_once 'Structures/Form/Exception.php';
throw new Structures_Form_Exception (self ::getErrorMessage (self ::ERROR_ADD_ELEMENT_DOUBLEADD ),
self ::ERROR_ADD_ELEMENT_DOUBLEADD
// Add the element to the elements array.
// Go through the current elements until we find the right position.
$elements[$element->getName ()] = $element;
$elements[$name] = $elem;
// If the element was not inserted, add the element to the end.
$elements[$element->getName ()] = $element;
// Update the elements array.
* Moves an element object from its current position to the given position.
* If the position is greater than the number of elements, the element will
* be added to the end of the form.
* @param object $element The element to move.
* @param integer $position The new position.
* @return object The object that was moved.
// First remove the element from the form.
// Then insert it in the given position.
* Creates an element but does not add it to the form.
* Only elements types that are registered with Structures_Form may be added
* to the form. This helps to ensure that the elements implement the proper
* To avoid overhead, type registration is not checked until the type is
* This method passes any extra arguments on to the element constructor.
* This allows one method to be used for creating many types of elements.
* The exact number and type of arguments that is passed to this method
* varies depending on the type of element to be created. If the wrong
* number or type of arguments is passed, the element constructor should
* @param string $type The element type.
* @param string $name The element name.
* @return object A Structures_Form element
* @throws Structures_Form_Exception
// Make sure the type is registered.
require_once 'Structures/Form/Exception.php';
throw new Structures_Form_Exception (self ::getErrorMessage (self ::ERROR_UNREGISTERED_ELEMENT ),
self ::ERROR_UNREGISTERED_ELEMENT
// Make sure an element with this name isn't already in the form.
require_once 'Structures/Form/Exception.php';
throw new Structures_Form_Exception (self ::getErrorMessage (self ::ERROR_ADD_ELEMENT_DOUBLEADD ),
self ::ERROR_ADD_ELEMENT_DOUBLEADD
// Include the element class file.
// Make sure the class exists.
require_once 'Structures/Form/Exception.php';
throw new Structures_Form_Exception (self ::getErrorMessage (self ::ERROR_REGISTRATION_ELEMENT ),
self ::ERROR_NONEXISTENT_CLASS
// Try to instantiate the class.
// First add the form as the first argument.
// Instantiate the class.
// Set the name of the object.
* Removes an element from the form by name.
* Adds an element to the form.
* Only elements types that are registered with Structures_Form may be added
* to the form. This helps to ensure that the elements implement the proper
* To avoid overhead, type registration is not checked until the type is
* @return object The added element.
* Removes an element object from the form.
* This method is useful if an element has been added with the wrong name.
* Trying to remove it by the name returned by getName() will not work so
* you must remove it by the object.
// Loop through the current elements and see if the given element is
if ($elem === $element) {
// Remove by the name the form thinks the element has.
* Registers an element type with this form.
* Before an element type can be used in a form, it must be registered.
* Registering an element type helps to make sure that type names are
* unique and that element classes implement the needed interface.
* To avoid overhead, registered classes are not checked until the type is
* @param string $name The name to identify the element type.
* @param string $class The name of the element class.
* @param string $path The path to the class definition.
* @return boolean true if the class was registered
* @throws Structures_Form_Exception
// Check to see if the element is already registered.
require_once 'Structures/Form/Exception.php';
throw new Structures_Form_Exception (self ::getErrorMessage (self ::ERROR_REGISTRATION_ELEMENT ),
self ::ERROR_REGISTRATION_ELEMENT_DOUBLEREG
// If the class is not already declared, make sure the path is
require_once 'Structures/Form/Exception.php';
throw new Structures_Form_Exception (self ::getErrorMessage (self ::ERROR_REGISTRATION_ELEMENT ),
self ::ERROR_NONEXISTENT_FILE
// Add the information to the registered elements array.
* Returns whether or not a path is in the include path.
* @return boolean true if the path is in the include path.
// Break up the include path and check to see if the path is readable.
// If we got down here, the path is not readable from the include path.
* Unregisters an element type with a form.
* An element type may not be unregistered if the form contains elements of
* You may want to unregister a type to prevent a certain type from being
* used in the form. For example if your app creates forms on the fly from
* user supplied data, you can unregister the text type to prevent users
* from creating a form with free form text entries.
* @param string $type The element type name.
* @return boolean true if the type was unregistered
* @throws Structures_Form_Exception
// Check to make sure the element isn't in use.
require_once 'Structures/Form/Exception.php';
throw new Structures_Form_Exception (self ::getErrorMessage (self ::ERROR_UNREGISTRATION_ELEMENT ),
self ::ERROR_UNREGISTRATION_ELEMENTINUSE
// Just unset the element in the registered elements array.
* Returns whether or not an element type is registered.
* @param string $type The name of the element type.
* @param string $class Optional class name to check.
* @return boolean true if the element type is registered.
// Check to see if the element is registered under a different
// Use a case insensitive comparison.
if (strcmp($element['class'], $class) === 0 ) {
// If we made it here, the class is not registered.
* Returns all of the elements in the form of the given type.
* @param string $type The element type name.
// Loop through the elements and check their type.
if ($element->getType () == $type) {
$elements[$name] = $element;
* Returns the form element with the given name.
* @param string $name The element name.
* @return mixed Either the object or false if the object was not found.
// Check the element groups.
if ($group->elementExists ($name)) {
return $group->getElement ($name);
* Returns an array of all elements.
* @return array An array of elements array(<name> => <element>)
* Returns whether or not the given element is associated with this form.
* @param string $name The name of the element to check.
* @return boolean true if the element is part of this form.
return (isset ($this->elements[$name]) &&
* Returns whether or not the element object is associated with this form.
* @param object $element The element object.
* @return boolean true if the element is part of the form.
// Go through all of the elements and check to see if the given element
if ($elem === $element) {
* Returns the current position of the element.
* @param string $name The element name.
* @return integer The current position.
* This method disbands a group. It does not destroy the elements in the
* group or even remove them from the form. It simply disbands the group
* and makes the elements free floating individuals. The elements are
* inserted where the group used to be.
* This method returns an array containing the names of any elements that
* were in the group before it was disbanded.
* If the group does not exist, this method will return an empty array.
* @param string $group The name of the group to disband.
// Make sure the group exists.
// Grab the group elements.
// Grab the current group position.
// Remove the elements from the group.
foreach ($elements as $element) {
// Reverse the elements and insert them into the position the group
$this->insertElementObject ($element, $pos);
* Returns whether or not the given group exists in this form.
* @param string $name The name of the group.
* @return boolean true if the group exists.
// Check to see if an element with the group name exists.
// See if the element implements the group interface.
* Returns whether or not the element is a group.
* @param object $element The element to check.
* @return boolean true if the element is an group.
require_once 'Structures/Form/GroupInterface.php';
* Returns the group element.
* If the group does not exists, this method returns false.
* @param string $group The name of the group.
* Returns an array containing all groups.
// Loop through all the elements and figure out which ones are groups.
$groups[$name] = $element;
* Adds an element to a group.
* A group is just a way to logically and visually group form elements.
* Elements can be added to or removed from a group without removing them
* from the form all together. However, obviously if the element is removed
* from the form, it will be removed from the group. If you readd the same
* element object, it will NOT be readded to the group.
* Elements may only be part of one group. If the element is already part
* of another group, it will not be added to this group.
* @param string $name The name of the element.
* @param string $group The name of the group.
* @return boolean true if the element has been added to the group.
// Check to make sure the element exists.
// Make sure the group exists.
* Removes an element from a group.
* A group is just a way to logically and visually group form elements.
* Elements can be added to or removed from a group without removing them
* from the form all together. However, obviously if the element is removed
* from the form, it will be removed from the group. If you readd the same
* element object, it will NOT be readded to the group.
* @param string $element The name of the element.
* @param string $group The name of the group.
* @return object The object that was removed or false
// Make sure the group exists.
// Check to make sure the element is part of the group.
if (!$grp->elementExists ($element)) {
// Remove the element from the group.
* Adds an element object to a group.
* A group is just a way to logically and visually group form elements.
* Elements can be added to or removed from a group without removing them
* from the form all together. However, obviously if the element is removed
* from the form, it will be removed from the group. If you readd the same
* element object, it will NOT be readded to the group.
* This method returns true if the element has been added to the group and
* false in all other cases including when the element is not part of the
* form or the group does not exist.
* Elements may only be part of one group. If the element is already part
* of another group, it will not be added to this group.
* An element must be part of the form before it can be added to the group.
* This is normally not a problem as elements should be created using
* addElement or createElement.
* @param string $element The element.
* @param string $group The name of the group.
* @return boolean true if the element has been added to the group.
// Check to make sure the element exists.
// Make sure the group exists.
// Remove the element from the form.
// Add the element to the group.
return $grp->addElement ($element);
* Removes an element object from a group.
* A group is just a way to logically and visually group form elements.
* Elements can be added to or removed from a group without removing them
* from the form all together. However, obviously if the element is removed
* from the form, it will be removed from the group. If you readd the same
* element object, it will NOT be readded to the group.
* This method returns true if the element has been removed from the group
* and false in all other cases including when the element is not part of
* the form or the group does not exist.
* @param string $element The element.
* @param string $group The name of the group.
* @return object The object that was removed or false.
// Make sure the group exists.
// Check to make sure the element is part of the group.
if (!$grp->elementExists ($element->getName ())) {
// Remove the element from the group.
$grp->removeElement ($element);
* Returns an array containing the names of the elements in the given
* If the group does not exist, this method returns an empty array.
* @param string $name The name of the group
// Make sure the group exists.
return $grp->getAllElements ();
* Returns the current value for all elements in an associative array.
* The array will be of the form: array(<name> => <value>);
// Loop through all the elements and collect their values.
// Check to see if the element is a group.
// Merge the values from the group with the other values.
// Just add the element's value to the array.
$values[$name] = $element->getValue ();
* Returns the current value for the given element.
* @param string $name The element name.
* @return mixed The value of the element or group of elements.
* @throws Structures_Form_Exception
// Check to see if the element exists.
// Throw an exception because returning any value could be
require_once 'Structures/Form/Exception.php';
throw new Structures_Form_Exception (self ::getErrorMessage (self ::ERROR_NONEXISTENT_ELEMENT ),
self ::ERROR_NONEXISTENT_ELEMENT
// Return the element's value. A groups return value will be an array.
return $element->getValue ();
* Sets the values for the form elements.
* The array passed in should be of the form: array(<name> => <value>)
* @param array $values An array of values.
* @return array An array containing names of elements whose value has
// Loop through the array and try to set the values of each element.
foreach ($values as $element => $value) {
// We want to prevent throwing an exception here so check for the
// Try to set the value for the element.
if ($this->setValue($element, $value)) {
* Sets the value for the given element.
* This method returns true if the value appears to have been changed. If
* false is returned, it may indicated that the element does not exist,
* that the new value was the same as the old value, or that it was frozen.
* @param string $name The name of the element
* @param mixed $value The element value.
* @return boolean true if the element's value was set.
// Check to see if the element exists.
// Throw an exception because returning any value could be
require_once 'Structures/Form/Exception.php';
throw new Structures_Form_Exception (self ::getErrorMessage (self ::ERROR_NONEXISTENT_ELEMENT ),
self ::ERROR_NONEXISTENT_ELEMENT
return $element->setValue ($value);
* Clears the values of all form elements (if possible).
* @return array An array of elements whose value has been cleared.
// Loop through all elements and call the clearValue method.
if ($element->clearValue ()) {
// Value was cleared successfully.
* Sets the values of the elements and make the given values the defautls.
* This method over writes any values currently set!
* @param array $defaults An array of default values.
* @return array An array containing names of elements whose value has
// Set the array as the defaults.
* Restores the elements to their default values.
* This method over writes any values currently set!
* If no defaults were set, this method will return an empty array.
* @return array An array containing names of elements whose value has
* Returns the array of default values.
* Collects submitted values and calls the callback or error callback.
* @return boolean false to continue processing callbacks.
// Process the errors. An empty array will clear any existing errors.
// Check to see if the form widgets should be submitted instead of
// Call the user's callback.
// Continue calling callbacks.
// Stop processing callbacks.
* Simply passes the error array on to the renderer.
* It might be a good idea to re-render the form after errors are added but
* that is the responsibility of the developer and the renderer. It cannot
* be determined here if the user wants to re-render. Nor can the form
* reliably be changed form here.
* If errors need to be handled in a different way, you should set a custom
* error callback either when the form is constructed or by using
* @param array $errors An array of error messages.
// Check to see if the renderer is set. (It almost has to be)
* Validates the values of the form against the applied rules.
* This method returns an array even if there are no errors. If the array
* is empty, then no errors occurred or no rules were applied.
* @return array An array of error messages
// Call each rule and check for errors.
foreach ($this->rules as $name => $rule) {
// Validate the elements.
foreach ($rule['elements'] as $element) {
$result = $rObj->validate ($this->getElement($element));
* Registers a rule class with the form.
* Rule objects are used to validate the values of the form elements before
* they are submitted to the callback. If an elements value violates a rule
* a rule callback will be called which allows the user to handle errors in
* their own way. All violations are collected on each submit and then
* passed off to the rule callback.
* Only registered rules may be applied to a form element.
* All registered rules must implement the Structures_Form_RuleInterface.
* To avoid overhead, a rule is not checked until it is applied to a form
* @param string $name A name to identify the rule.
* @param string $class The name of the rule class.
* @param string $path The path to the class definition.
* @return boolean true if the rule was registered.
* @throws Structures_Form_Exception
// Check to see if the element is already registered.
require_once 'Structures/Form/Exception.php';
throw new Structures_Form_Exception (self ::getErrorMessage (self ::ERROR_REGISTRATION_RULE ),
self ::ERROR_REGISTRATION_RULE_DOUBLEREG
// If the class is not already declared, make sure the path is
require_once 'Structures/Form/Exception.php';
throw new Structures_Form_Exception (self ::getErrorMessage (self ::ERROR_REGISTRATION_RULE ),
self ::ERROR_NONEXISTENT_FILE
// Add the information to the registered elements array.
* Unregisters a rule with the form.
* Only registered rules may be applied to a form element.
* A rule may not be unregistered if it is currently being applied to one
* You may want to unregister a rule to prevent it from being applied to a
* form. For example, if your app creates forms on the fly, you may want to
* unregister a rule to prevent the user from applying a rule that their
* PHP installation cannot support (regular expressions may not be
* @param string $name The name of the rule class.
* @return boolean true if the rule was unregistered.
* @throws Structures_Form_Exception
// Make sure the rule is not applied.
require_once 'Structures/Form/Exception.php';
throw new Structures_Form_Exception (self ::getErrorMessage (self ::ERROR_UNREGISTRATION_RULE ),
self ::ERROR_UNREGISTRATION_RULEINUSE
// Just unset the registered rule element for this rule.
* Returns whether or not a rule is registered.
* @param string $rule The name of the rule type.
* @param string $class Optional class name to check.
* @return boolean true if the rule is registered.
// Check to see if the rule is registered under a different name.
// Use a case insensitive comparison.
// If we made it here, the class is not registered.
* Associates a rule with a form element.
* When a form is submitted, the values will be checked against any rules
* that have been associated with the elements. A rule of a give type can
* only be added to an individual element once. Attempting to add a rule
* to the same element twice will have no extra effect.
* This method passes any extra arguments on to the rule constructor.
* This allows one method to be used for creating many types of rules.
* The exact number and type of arguments that is passed to this method
* varies depending on the type of rule to be created. If the wrong
* number or type of arguments is passed, the rule constructor should
* @param string $name The name of the element.
* @param string $rule The name of the rule.
* @return boolean true if the rule was applied.
public function addRule($name, $rule)
// Check to make sure the element exists.
// Make sure the rule is registered.
// See if we need to create the rule object.
if (!isset ($this->rules[$rule]['object']) ||
// Create the rule object.
// Create the rule object.
// Set up the rules array.
$this->rules[$rule] = array ('object' => $rObj,
// Associate the rule with the element.
$this->rules[$rule]['elements'][] = $name;
* When a form is submitted, the values will be checked against any rules
* that have been associated with the elements. A rule of a give type can
* only be added to an individual element once. Attempting to add a rule
* to the same element twice will have no extra effect.
* This method passes any extra arguments on to the rule constructor.
* This allows one method to be used for creating many types of rules.
* The exact number and type of arguments that is passed to this method
* varies depending on the type of rule to be created. If the wrong
* number or type of arguments is passed, the rule constructor should
* @param string $rule The name of the rule.
* @return boolean true if the rule was applied.
// Make sure the rule is registered.
require_once 'Structures/Form/Exception.php';
throw new Structures_Form_Exception (self ::getErrorMessage (self ::ERROR_UNREGISTERED_RULE ),
self ::ERROR_UNREGISTERED_RULE
// Make sure an element with this name isn't already in the form.
require_once 'Structures/Form/Exception.php';
throw new Structures_Form_Exception (self ::getErrorMessage (self ::ERROR_ADD_RULE_DOUBLEADD ),
self ::ERROR_ADD_RULE_DOUBLEADD
// Include the element class file.
// Make sure the class exists.
require_once 'Structures/Form/Exception.php';
throw new Structures_Form_Exception (self ::getErrorMessage (self ::ERROR_REGISTRATION_RULE ),
self ::ERROR_NONEXISTENT_CLASS
// Try to instantiate the class.
// First add the form as the first argument. <-- Not needed.
// Next instantiate the class.
// Make sure the object implements the correct interface.
require_once 'Structures/Form/RuleInterface.php';
require_once 'Structures/Form/Exception.php';
throw new Structures_Form_Exception (self ::getErrorMessage (self ::ERROR_LACKSINTERFACE_RULE ),
self ::ERROR_LACKSINTERFACE_RULE
* Removes a rule from an element.
* When a form is submitted, the values will be checked against any rules
* that have been associated with the elements. A rule of a give type can
* only be added to an individual element once. Attempting to add a rule
* to the same element twice will have no extra effect. Therefore, it only
* makes sense to try to remove a rule once.
* This method will return true if the rule is not associated with the
* element. This means that it will also return true even if the rule was
* never associated with the element in the first place.
* @param string $element The name of the element to remove the rule from
* @param string $rule The name of the rule to remove
* @return boolean true if the rule is no longer associated with the
// Check to make sure the element exists.
// Make sure the rule is registered.
// Remove the element/rule association.
if (isset ($this->rules[$rule]['elements']) &&
unset ($this->rules[$rule]['elements'][$key]);
* Associates a rule with a form element object.
* When a form is submitted, the values will be checked against any rules
* that have been associated with the elements. A rule of a give type can
* only be added to an individual element once. Attempting to add a rule
* to the same element twice will have no extra effect.
* This method passes any extra arguments on to the rule constructor.
* This allows one method to be used for creating many types of rules.
* The exact number and type of arguments that is passed to this method
* varies depending on the type of rule to be created. If the wrong
* number or type of arguments is passed, the rule constructor should
* @param object $element The form element object
* @param string $rule The form rule name.
* @return boolean true if the rule was applied.
// Check to make sure the element exists.
// Make sure the rule is registered.
// Apply the rule to the element.
$args[0 ] = $element->getName ();
* Removes a rule from a form element object.
* When a form is submitted, the values will be checked against any rules
* that have been associated with the elements. A rule of a give type can
* only be added to an individual element once. Attempting to add a rule
* to the same element twice will have no extra effect. Therefore, it only
* makes sense to try to remove a rule once.
* This method will return true if the rule is not associated with the
* element. This means that it will also return true even if the rule was
* never associated with the element in the first place.
* @param object $element The form element to remove the rule from.
* @param string $rule The rule to remove from the object.
* @return boolean true if the rule is no longer associated with the
// Check to make sure the element exists.
// Make sure the rule is registered.
// We only need to disassociate the rule with the name.
* Returns whether or not the give rule is currently associated with any
* @param string $name The name of the form rule to check.
* @return boolean true if the rule is currently associated with an element
return (isset ($this->rules[$name]) &&
* Returns whether or not a rule with the given name already exists.
* @param string $rule The name fo the rule.
* @return boolean true if the name is in use.
* @param string $note The text to use.
* Returns the current required note.
* Sets the require symbol.
* @param string $symbol The text to use.
* Returns the current required symbol.
* Returns whether or not an element is required.
* @param string $element The name of the element.
* @return boolean true if the required rule is applied to the element.
return (isset ($this->rules[self ::REQUIRED_RULE ]['elements']) &&
in_array($element, $this->rules[self ::REQUIRED_RULE ]['elements'])
* Returns whether or not the given rule is applied to the given element.
* This method returns true if the rule is applied to the element and false
* in all other cases including if the rule or element is not defined.
* @param string $element The name of the element.
* @param string $rule The name of the rule.
* @return boolean true if the rule is applied to the element.
return (isset ($this->rules[$rule]) &&
* Sets a renderer object.
* Renderers must implement Structures_Form_RendererInterface. This helps to
* ensure consistency among the API and avoid any fatal errors. A renderer
* is used to position and display the form elements within a container
* Unlike rules and elements, renderers are created on their own (not
* through a form method). This is because they do not need to know
* thing about the form at construction time and the form does not need to
* know anything about the renderer until the form is to be displayed.
* A form may only have one renderer at a time. Setting a second renderer
* will overwrite the first. If no renderer is set, the default renderer
* @param object $renderer An object that implements
* Structures_Form::RENDERER_INTERFACE
* @throws Structures_Form_Exception
// Make sure that the renderer is an object and that it implements the
require_once 'Structures/Form/RendererInterface.php';
require_once 'Structures/Form/Exception.php';
throw new Structures_Form_Exception (self ::getErrorMessage (self ::ERROR_LACKSINTERFACE_RENDERER ),
self ::ERROR_LACKSINTERFACE_RENDERER
// Set the form for the renderer.
* Creates a default renderer object.
* This method may be called by group elements that need to renderer
* elements but do not have a renderer set.
// Require the default renderer file.
// Create an instance of the default renderer.
* Creates a default renderer and sets it as the current renderer.
* An exception may be thrown by setRenderer. It will pass through to the
// Get a default renderer.
* Returns a container widget holding the form elements.
* Passes the elements, required note and required symbol to the renderer
* and then calls renderer().
* Pulling elements out of a renderer is a pain in the ass. Trying to find
* the correct widget (or parent widget) can be nearly impossible.
* Therefore, even if you remove a widget from the form, it will still
* appear if the widget was removed after the form was rendered.
* @return object A container widget holding the form.
* @throws Structures_Form_Exception
// Check to see if a renderer has been set.
// Try to create a default renderer.
require_once 'Structures/Form/Exception.php';
} catch (Structures_Form_Exception $sfe) {
// Set a prettier error message but keep the same code.
throw new Structures_Form_Exception (self ::getErrorMessage (self ::ERROR_RENDER_FAILURE ),
// Pass the elements to the renderer.
// Pass the required note and symbol.
// Try to renderer the form.
// Keep track of the rendered widget.
// Return the container widget.
} catch (Structures_Form_Exception $sfe) {
// Set a prettier error message but keep the same code.
throw new Structures_Form_Exception (self ::getErrorMessage (self ::ERROR_RENDER_FAILURE ),
* Returns the most recently rendered widget.
* This method will not render the form! It only returns the widget created
* when render() was called!
* @return object The rendered form.
* Changes the UI of the form from the current set of elements to the given
* This method allows you to quickly and easily change from one element set
* to another. In most cases it is only necessary to change renderers but
* some renderers may have additional requirements for the elements that
* necessitate changing the classes that represent the elements.
* @param object $elementSet A Structures_Form_Element set.
* @return boolean true if the element set was changed successfully.
public function swapElementSet(Structures_Form_ElementSet $elementSet)
// First, get the new element set.
foreach ($elementSet as $element) {
// Next, remove all of the elements for each type.
$removed[$elem->getName ()] = $elem;
// Next, unregister the old type and register the new type.
// Then create elements of the new type.
foreach ($removed as $name => $elem) {
// Set all of the element's data.
$newElem->setValue ($elem->getValue ());
$elem->isFrozen () ? $newElem->freeze () : $newElem->unfreeze ();
$newElem->setLabel ($elem->getLabel ());
// Then re-add the new element.
// Finally, set a new default renderer.
$renderer = $elementSet->getDefaultRenderer ();
Documentation generated on Mon, 11 Mar 2019 14:44:13 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.
|