Source for file form.php
Documentation is available at form.php
* @package Joomla.Platform
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
jimport('joomla.utilities.arrayhelper');
* Form Class for the Joomla Platform.
* This class implements a robust API for constructing, populating, filtering, and validating forms.
* It uses XML definitions to construct form fields and a variety of field and rule classes to
* render and validate the form.
* @package Joomla.Platform
* @link http://www.w3.org/TR/html4/interact/forms.html
* @link http://www.w3.org/TR/html5/forms.html
* The JRegistry data store for form fields during display.
* The form object errors array.
* The name of the form instance.
* The form object options for use in rendering and validation.
* The form XML definition.
protected static $forms =
array();
* Alows extensions to implement repeating elements
* Method to instantiate the form object.
* @param string $name The name of the form.
* @param array $options An array of form options.
public function __construct($name, array $options =
array())
// Set the name for the form.
// Initialise the JRegistry data.
// Set the options if specified.
$this->options['control'] = isset
($options['control']) ?
$options['control'] :
false;
* Method to bind data to the form.
* @param mixed $data An array or object of data to bind to the form.
* @return boolean True on success.
public function bind($data)
// Make sure there is a valid JForm XML document.
if (!($this->xml instanceof
SimpleXMLElement))
// The data must be an object or array.
// Convert the input to an array.
$data =
$data->toArray();
$data =
$data->getProperties();
// Handle other types of objects.
// Process the input data.
foreach ($data as $k =>
$v)
// If the field exists set the value.
$this->data->set($k, $v);
// If the value is an object or an associative array hand it off to the recursive bind level method.
* Method to bind data to the form for the group level.
* @param string $group The dot-separated form group path on which to bind the data.
* @param mixed $data An array or object of data to bind to the form for the group level.
// Ensure the input data is an array.
// Process the input data.
foreach ($data as $k =>
$v)
// If the field exists set the value.
$this->data->set($group .
'.' .
$k, $v);
// If the value is an object or an associative array, hand it off to the recursive bind level method
* Method to filter the form data.
* @param array $data An array of field values to filter.
* @param string $group The dot-separated form group path on which to filter the fields.
* @return mixed Array or false.
public function filter($data, $group =
null)
// Make sure there is a valid JForm XML document.
if (!($this->xml instanceof
SimpleXMLElement))
// Get the fields for which to filter the data.
foreach ($fields as $field)
$name = (string)
$field['name'];
// Get the field groups for the element.
$attrs =
$field->xpath('ancestor::fields[@name]/@name');
$groups =
array_map('strval', $attrs ?
$attrs :
array());
// Get the field value from the data input.
// Filter the value if it exists.
if ($input->exists($group .
'.' .
$name))
$output->set($group .
'.' .
$name, $this->filterField($field, $input->get($group .
'.' .
$name, (string)
$field['default'])));
// Filter the value if it exists.
if ($input->exists($name))
$output->set($name, $this->filterField($field, $input->get($name, (string)
$field['default'])));
return $output->toArray();
* Return all errors, if any.
* @return array Array of error messages or RuntimeException objects.
* Method to get a form field represented as a JFormField object.
* @param string $name The name of the form field.
* @param string $group The optional dot-separated form group path on which to find the field.
* @param mixed $value The optional value to use as the default for the field.
* @return mixed The JFormField object for the field or boolean false on error.
public function getField($name, $group =
null, $value =
null)
// Make sure there is a valid JForm XML document.
if (!($this->xml instanceof
SimpleXMLElement))
// Attempt to find the field by name and group.
// If the field element was not found return false.
return $this->loadField($element, $group, $value);
* Method to get an attribute value from a field XML element. If the attribute doesn't exist or
* is null then the optional default value will be used.
* @param string $name The name of the form field for which to get the attribute value.
* @param string $attribute The name of the attribute for which to get a value.
* @param mixed $default The optional default value to use if no attribute value exists.
* @param string $group The optional dot-separated form group path on which to find the field.
* @return mixed The attribute value for the field.
* @throws UnexpectedValueException
// Make sure there is a valid JForm XML document.
if (!($this->xml instanceof
SimpleXMLElement))
throw
new UnexpectedValueException(sprintf('%s::getFieldAttribute `xml` is not an instance of SimpleXMLElement', get_class($this)));
// Find the form field element from the definition.
// If the element exists and the attribute exists for the field return the attribute value.
if (($element instanceof
SimpleXMLElement) &&
((string)
$element[$attribute]))
return (string)
$element[$attribute];
// Otherwise return the given default value.
* Method to get an array of JFormField objects in a given fieldset by name. If no name is
* given then all fields are returned.
* @param string $set The optional name of the fieldset.
* @return array The array of JFormField objects in the fieldset.
// Get all of the field elements in the fieldset.
// If no field elements were found return empty.
// Build the result array from the found field elements.
foreach ($elements as $element)
// Get the field groups for the element.
$attrs =
$element->xpath('ancestor::fields[@name]/@name');
$groups =
array_map('strval', $attrs ?
$attrs :
array());
// If the field is successfully loaded add it to the result array.
if ($field =
$this->loadField($element, $group))
$fields[$field->id] =
$field;
* Method to get an array of fieldset objects optionally filtered over a given field group.
* @param string $group The dot-separated form group path on which to filter the fieldsets.
* @return array The array of fieldset objects.
// Make sure there is a valid JForm XML document.
if (!($this->xml instanceof
SimpleXMLElement))
// Get the fields elements for a given group.
foreach ($elements as &$element)
// Get an array of <fieldset /> elements and fieldset attributes within the fields element.
if ($tmp =
$element->xpath('descendant::fieldset[@name] | descendant::field[@fieldset]/@fieldset'))
// Get an array of <fieldset /> elements and fieldset attributes.
$sets =
$this->xml->xpath('//fieldset[@name] | //field[@fieldset]/@fieldset');
// If no fieldsets are found return empty.
// Process each found fieldset.
// Are we dealing with a fieldset element?
if ((string)
$set['name'])
// Only create it if it doesn't already exist.
if (empty($fieldsets[(string)
$set['name']]))
// Build the fieldset object.
$fieldset = (object)
array('name' =>
'', 'label' =>
'', 'description' =>
'');
foreach ($set->attributes() as $name =>
$value)
$fieldset->$name = (string)
$value;
// Add the fieldset object to the list.
$fieldsets[$fieldset->name] =
$fieldset;
// Must be dealing with a fieldset attribute.
// Only create it if it doesn't already exist.
if (empty($fieldsets[(string)
$set]))
// Attempt to get the fieldset element for data (throughout the entire form document).
$tmp =
$this->xml->xpath('//fieldset[@name="' . (string)
$set .
'"]');
// If no element was found, build a very simple fieldset object.
$fieldset = (object)
array('name' => (string)
$set, 'label' =>
'', 'description' =>
'');
// Build the fieldset object from the element.
$fieldset = (object)
array('name' =>
'', 'label' =>
'', 'description' =>
'');
foreach ($tmp[0]->attributes() as $name =>
$value)
$fieldset->$name = (string)
$value;
// Add the fieldset object to the list.
$fieldsets[$fieldset->name] =
$fieldset;
* Method to get the form control. This string serves as a container for all form fields. For
* example, if there is a field named 'foo' and a field named 'bar' and the form control is
* empty the fields will be rendered like: <input name="foo" /> and <input name="bar" />. If
* the form control is set to 'joomla' however, the fields would be rendered like:
* <input name="joomla[foo]" /> and <input name="joomla[bar]" />.
* @return string The form control string.
return (string)
$this->options['control'];
* Method to get an array of JFormField objects in a given field group by name.
* @param string $group The dot-separated form group path for which to get the form fields.
* @param boolean $nested True to also include fields in nested groups that are inside of the
* group for which to find fields.
* @return array The array of JFormField objects in the field group.
public function getGroup($group, $nested =
false)
// Get all of the field elements in the field group.
// If no field elements were found return empty.
// Build the result array from the found field elements.
foreach ($elements as $element)
// Get the field groups for the element.
$attrs =
$element->xpath('ancestor::fields[@name]/@name');
$groups =
array_map('strval', $attrs ?
$attrs :
array());
// If the field is successfully loaded add it to the result array.
if ($field =
$this->loadField($element, $group))
$fields[$field->id] =
$field;
* Method to get a form field markup for the field input.
* @param string $name The name of the form field.
* @param string $group The optional dot-separated form group path on which to find the field.
* @param mixed $value The optional value to use as the default for the field.
* @return string The form field markup.
public function getInput($name, $group =
null, $value =
null)
// Attempt to get the form field.
if ($field =
$this->getField($name, $group, $value))
* Method to get the label for a field input.
* @param string $name The name of the form field.
* @param string $group The optional dot-separated form group path on which to find the field.
* @return string The form field label.
public function getLabel($name, $group =
null)
// Attempt to get the form field.
if ($field =
$this->getField($name, $group))
* Method to get the form name.
* @return string The name of the form.
* Method to get the value of a field.
* @param string $name The name of the field for which to get the value.
* @param string $group The optional dot-separated form group path on which to get the value.
* @param mixed $default The optional default value of the field value is empty.
* @return mixed The value of the field or the default value if empty.
public function getValue($name, $group =
null, $default =
null)
// If a group is set use it.
$return =
$this->data->get($group .
'.' .
$name, $default);
$return =
$this->data->get($name, $default);
* Method to get a control group with label and input.
* @param string $name The name of the field for which to get the value.
* @param string $group The optional dot-separated form group path on which to get the value.
* @param mixed $default The optional default value of the field value is empty.
* @return string A string containing the html for the control goup
$field =
$this->getField($name, $group, $default);
return $field->getControlGroup();
* Method to get all control groups with label and input of a fieldset.
* @param string $name The name of the fieldset for which to get the values.
* @return string A string containing the html for the control goups
foreach ($fields as $field)
$html[] =
$field->getControlGroup();
* Method to load the form description from an XML string or object.
* The replace option works per field. If a field being loaded already exists in the current
* form definition then the behavior or load will vary depending upon the replace flag. If it
* is set to true, then the existing field will be replaced in its exact location by the new
* field being loaded. If it is false, then the new field being loaded will be ignored and the
* method will move on to the next field to load.
* @param string $data The name of an XML string or object.
* @param string $replace Flag to toggle whether form fields should be replaced if a field
* already exists with the same group/name.
* @param string $xpath An optional xpath to search for the fields.
* @return boolean True on success, false otherwise.
public function load($data, $replace =
true, $xpath =
false)
// If the data to load isn't already an XML element or string return false.
if ((!($data instanceof
SimpleXMLElement)) &&
(!is_string($data)))
// Attempt to load the XML if a string.
$data =
new SimpleXMLElement($data);
// Make sure the XML loaded correctly.
// If we have no XML definition at this point let's make sure we get one.
// If no XPath query is set to search for fields, and we have a <form />, set it and return.
if (!$xpath &&
($data->getName() ==
'form'))
// Synchronize any paths found in the load.
// Create a root element for the form.
$this->xml =
new SimpleXMLElement('<form></form>');
// Get the XML elements to load.
$elements =
$data->xpath($xpath);
elseif ($data->getName() ==
'form')
$elements =
$data->children();
// If there is nothing to load return true.
// Load the found form elements.
foreach ($elements as $element)
// Get an array of fields with the correct name.
$fields =
$element->xpath('descendant-or-self::field');
foreach ($fields as $field)
// Get the group names as strings for ancestor fields elements.
$attrs =
$field->xpath('ancestor::fields[@name]/@name');
$groups =
array_map('strval', $attrs ?
$attrs :
array());
// Check to see if the field exists in the current form.
if ($current =
$this->findField((string)
$field['name'], implode('.', $groups)))
// If set to replace found fields, replace the data and remove the field so we don't add it twice.
$addeddom =
$olddom->ownerDocument->importNode($loadeddom);
$olddom->parentNode->replaceChild($addeddom, $olddom);
$loadeddom->parentNode->removeChild($loadeddom);
// Merge the new field data into the existing XML document.
self::addNode($this->xml, $element);
// Synchronize any paths found in the load.
* Method to load the form description from an XML file.
* The reset option works on a group basis. If the XML file references
* groups that have already been created they will be replaced with the
* fields in the new XML file unless the $reset parameter has been set
* @param string $file The filesystem path of an XML file.
* @param string $reset Flag to toggle whether form fields should be replaced if a field
* already exists with the same group/name.
* @param string $xpath An optional xpath to search for the fields.
* @return boolean True on success, false otherwise.
public function loadFile($file, $reset =
true, $xpath =
false)
// Check to see if the path is an absolute path.
// Not an absolute path so let's attempt to find one using JPath.
// If unable to find the file return false.
// Attempt to load the XML file.
return $this->load($xml, $reset, $xpath);
* Method to remove a field from the form definition.
* @param string $name The name of the form field for which remove.
* @param string $group The optional dot-separated form group path on which to find the field.
* @return boolean True on success.
* @throws UnexpectedValueException
// Make sure there is a valid JForm XML document.
if (!($this->xml instanceof
SimpleXMLElement))
throw
new UnexpectedValueException(sprintf('%s::getFieldAttribute `xml` is not an instance of SimpleXMLElement', get_class($this)));
// Find the form field element from the definition.
// If the element exists remove it from the form definition.
if ($element instanceof
SimpleXMLElement)
$dom->parentNode->removeChild($dom);
* Method to remove a group from the form definition.
* @param string $group The dot-separated form group path for the group to remove.
* @return boolean True on success.
* @throws UnexpectedValueException
// Make sure there is a valid JForm XML document.
if (!($this->xml instanceof
SimpleXMLElement))
throw
new UnexpectedValueException(sprintf('%s::getFieldAttribute `xml` is not an instance of SimpleXMLElement', get_class($this)));
// Get the fields elements for a given group.
foreach ($elements as &$element)
$dom->parentNode->removeChild($dom);
* Method to reset the form data store and optionally the form XML definition.
* @param boolean $xml True to also reset the XML form definition.
* @return boolean True on success.
public function reset($xml =
false)
$this->xml =
new SimpleXMLElement('<form></form>');
* Method to set a field XML element to the form definition. If the replace flag is set then
* the field will be set whether it already exists or not. If it isn't set, then the field
* will not be replaced if it already exists.
* @param SimpleXMLElement $element The XML element object representation of the form field.
* @param string $group The optional dot-separated form group path on which to set the field.
* @param boolean $replace True to replace an existing field if one already exists.
* @return boolean True on success.
* @throws UnexpectedValueException
public function setField(SimpleXMLElement $element, $group =
null, $replace =
true)
// Make sure there is a valid JForm XML document.
if (!($this->xml instanceof
SimpleXMLElement))
throw
new UnexpectedValueException(sprintf('%s::getFieldAttribute `xml` is not an instance of SimpleXMLElement', get_class($this)));
// Find the form field element from the definition.
$old =
$this->findField((string)
$element['name'], $group);
// If an existing field is found and replace flag is false do nothing and return true.
if (!$replace &&
!empty($old))
// If an existing field is found and replace flag is true remove the old field.
if ($replace &&
!empty($old) &&
($old instanceof
SimpleXMLElement))
$dom->parentNode->removeChild($dom);
// If no existing field is found find a group element and add the field as a child of it.
// Get the fields elements for a given group.
// If an appropriate fields element was found for the group, add the element.
if (isset
($fields[0]) &&
($fields[0] instanceof
SimpleXMLElement))
self::addNode($fields[0], $element);
// Set the new field to the form.
self::addNode($this->xml, $element);
// Synchronize any paths found in the load.
* Method to set an attribute value for a field XML element.
* @param string $name The name of the form field for which to set the attribute value.
* @param string $attribute The name of the attribute for which to set a value.
* @param mixed $value The value to set for the attribute.
* @param string $group The optional dot-separated form group path on which to find the field.
* @return boolean True on success.
* @throws UnexpectedValueException
// Make sure there is a valid JForm XML document.
if (!($this->xml instanceof
SimpleXMLElement))
throw
new UnexpectedValueException(sprintf('%s::getFieldAttribute `xml` is not an instance of SimpleXMLElement', get_class($this)));
// Find the form field element from the definition.
// If the element doesn't exist return false.
if (!($element instanceof
SimpleXMLElement))
// Otherwise set the attribute and return true.
$element[$attribute] =
$value;
// Synchronize any paths found in the load.
* Method to set some field XML elements to the form definition. If the replace flag is set then
* the fields will be set whether they already exists or not. If it isn't set, then the fields
* will not be replaced if they already exist.
* @param array &$elements The array of XML element object representations of the form fields.
* @param string $group The optional dot-separated form group path on which to set the fields.
* @param boolean $replace True to replace existing fields if they already exist.
* @return boolean True on success.
* @throws UnexpectedValueException
public function setFields(&$elements, $group =
null, $replace =
true)
// Make sure there is a valid JForm XML document.
if (!($this->xml instanceof
SimpleXMLElement))
throw
new UnexpectedValueException(sprintf('%s::getFieldAttribute `xml` is not an instance of SimpleXMLElement', get_class($this)));
// Make sure the elements to set are valid.
foreach ($elements as $element)
if (!($element instanceof
SimpleXMLElement))
throw
new UnexpectedValueException(sprintf('$element not SimpleXMLElement in %s::setFields', get_class($this)));
foreach ($elements as $element)
if (!$this->setField($element, $group, $replace))
// Synchronize any paths found in the load.
* Method to set the value of a field. If the field does not exist in the form then the method
* @param string $name The name of the field for which to set the value.
* @param string $group The optional dot-separated form group path on which to find the field.
* @param mixed $value The value to set for the field.
* @return boolean True on success.
public function setValue($name, $group =
null, $value =
null)
// If the field does not exist return false.
// If a group is set use it.
$this->data->set($group .
'.' .
$name, $value);
$this->data->set($name, $value);
* Method to validate form data.
* Validation warnings will be pushed into JForm::errors and should be
* retrieved with JForm::getErrors() when validate returns boolean false.
* @param array $data An array of field values to validate.
* @param string $group The optional dot-separated form group path on which to filter the
* fields to be validated.
* @return mixed True on sucess.
public function validate($data, $group =
null)
// Make sure there is a valid JForm XML document.
if (!($this->xml instanceof
SimpleXMLElement))
// Create an input registry object from the data to validate.
// Get the fields for which to validate the data.
foreach ($fields as $field)
$name = (string)
$field['name'];
// Get the group names as strings for ancestor fields elements.
$attrs =
$field->xpath('ancestor::fields[@name]/@name');
$groups =
array_map('strval', $attrs ?
$attrs :
array());
// Get the value from the input data.
$value =
$input->get($group .
'.' .
$name);
$value =
$input->get($name);
if ($valid instanceof
Exception)
* Method to apply an input filter to a value based on field data.
* @param string $element The XML element object representation of the form field.
* @param mixed $value The value to filter for the field.
* @return mixed The filtered value.
// Make sure there is a valid SimpleXMLElement.
if (!($element instanceof
SimpleXMLElement))
// Get the field filter type.
$filter = (string)
$element['filter'];
// Process the input value based on the filter.
foreach ((array)
$value as $action =>
$ids)
// Build the rules array.
$return[$action] =
array();
foreach ($ids as $id =>
$p)
$return[$action][$id] =
($p ==
'1' ||
$p ==
'true') ?
true :
false;
// Do nothing, thus leaving the return value as null.
// Filter the input as an array of integers.
// Make sure the input is an array.
$value =
is_array($value) ?
$value :
array($value);
// Convert a date to UTC based on the server timezone offset.
// Get the server timezone setting.
// Return an SQL formatted datetime string in UTC.
// Convert a date to UTC based on the user timezone offset.
// Get the user timezone setting defaulting to the server timezone setting.
// Return a MySQL formatted datetime string in UTC.
// Ensures a protocol is present in the saved field. Only use when
// the only permitted protocols requre '://'. See JFormRuleUrl for list of these.
$protocol =
parse_url($value, PHP_URL_SCHEME);
// If there is no protocol and the relative option is not specified,
// we assume that it is an external URL and prepend http://.
if (($element['type'] ==
'url' &&
!$protocol &&
!$element['relative'])
||
(!$element['type'] ==
'url' &&
!$protocol))
// If it looks like an internal link, then add the root.
if (substr($value, 0) ==
'index.php')
// Otherwise we treat it is an external link.
// Put the url back together.
$value =
$protocol .
'://' .
$value;
// If relative URLS are allowed we assume that URLs without protocols are internal.
elseif (!$protocol &&
$element['relative'])
// If it starts with the host string, just prepend the protocol.
if (substr($value, 0) ==
$host)
$value =
'http://' .
$value;
// Otherwise prepend the root.
// Does it match the NANP pattern?
if (preg_match('/^(?:\+?1[-. ]?)?\(?([2-9][0-8][0-9])\)?[-. ]?([2-9][0-9]{2})[-. ]?([0-9]{4})$/', $value) ==
1)
if (substr($number, 0, 1) ==
1)
if (substr($number, 0, 2) ==
'+1')
$result =
'1.' .
$number;
// If not, does it match ITU-T?
elseif (preg_match('/^\+(?:[0-9] ?){6,14}[0-9]$/', $value) ==
1)
$countrycode = (string)
preg_replace('/[^\d]/', '', $countrycode);
$number =
strstr($value, ' ');
$result =
$countrycode .
'.' .
$number;
// If not, does it match EPP?
elseif (preg_match('/^\+[0-9]{1,3}\.[0-9]{4,14}(?:x.+)?$/', $value) ==
1)
$value =
substr($value, 0, $xpos);
// Maybe it is already ccc.nnnnnnn?
elseif (preg_match('/[0-9]{1,3}\.[0-9]{4,14}$/', $value) ==
1)
// If not, can we make it a string of digits?
if ($value !=
null &&
strlen($value) <=
15)
// If it is fewer than 13 digits assume it is a local number
// If it has 13 or more digits let's make a country code.
$result =
substr($value, 0, $cclen) .
'.' .
substr($value, $cclen);
// If not let's not save anything.
// Check for a callback filter.
// Filter using a callback function if specified.
// Filter using JFilterInput. All HTML code is filtered by default.
* Method to get a form field represented as an XML element object.
* @param string $name The name of the form field.
* @param string $group The optional dot-separated form group path on which to find the field.
* @return mixed The XML element object for the field or boolean false on error.
protected function findField($name, $group =
null)
// Make sure there is a valid JForm XML document.
if (!($this->xml instanceof
SimpleXMLElement))
// Let's get the appropriate field element based on the method arguments.
// Get the fields elements for a given group.
// Get all of the field elements with the correct name for the fields elements.
foreach ($elements as $element)
// If there are matching field elements add them to the fields array.
if ($tmp =
$element->xpath('descendant::field[@name="' .
$name .
'"]'))
// Make sure something was found.
// Use the first correct match in the given group.
$groupNames =
explode('.', $group);
foreach ($fields as &$field)
// Get the group names as strings for ancestor fields elements.
$attrs =
$field->xpath('ancestor::fields[@name]/@name');
$names =
array_map('strval', $attrs ?
$attrs :
array());
// If the field is in the exact group use it and break out of the loop.
if ($names == (array)
$groupNames)
// Get an array of fields with the correct name.
$fields =
$this->xml->xpath('//field[@name="' .
$name .
'"]');
// Make sure something was found.
// Search through the fields for the right one.
foreach ($fields as &$field)
// If we find an ancestor fields element with a group name then it isn't what we want.
if ($field->xpath('ancestor::fields[@name]'))
* Method to get an array of <field /> elements from the form XML document which are
* in a specified fieldset by name.
* @param string $name The name of the fieldset.
* @return mixed Boolean false on error or array of SimpleXMLElement objects.
// Make sure there is a valid JForm XML document.
if (!($this->xml instanceof
SimpleXMLElement))
* Get an array of <field /> elements that are underneath a <fieldset /> element
* with the appropriate name attribute, and also any <field /> elements with
* the appropriate fieldset attribute. To allow repeatable elements only immediate
* field descendants of the fieldset are selected.
$fields =
$this->xml->xpath('//fieldset[@name="' .
$name .
'"]/field | //field[@fieldset="' .
$name .
'"]');
* Method to get an array of <field /> elements from the form XML document which are
* in a control group by name.
* @param mixed $group The optional dot-separated form group path on which to find the fields.
* Null will return all fields. False will return fields not in a group.
* @param boolean $nested True to also include fields in nested groups that are inside of the
* group for which to find fields.
* @return mixed Boolean false on error or array of SimpleXMLElement objects.
// Make sure there is a valid JForm XML document.
if (!($this->xml instanceof
SimpleXMLElement))
// Get only fields in a specific group?
// Get the fields elements for a given group.
// Get all of the field elements for the fields elements.
foreach ($elements as $element)
// If there are field elements add them to the return result.
if ($tmp =
$element->xpath('descendant::field'))
// If we also want fields in nested groups then just merge the arrays.
// If we want to exclude nested groups then we need to check each field.
$groupNames =
explode('.', $group);
// Get the names of the groups that the field is in.
$attrs =
$field->xpath('ancestor::fields[@name]/@name');
$names =
array_map('strval', $attrs ?
$attrs :
array());
// If the field is in the specific group then add it to the return list.
if ($names == (array)
$groupNames)
elseif ($group ===
false)
// Get only field elements not in a group.
$fields =
$this->xml->xpath('descendant::fields[not(@name)]/field | descendant::fields[not(@name)]/fieldset/field ');
// Get an array of all the <field /> elements.
$fields =
$this->xml->xpath('//field');
* Method to get a form field group represented as an XML element object.
* @param string $group The dot-separated form group path on which to find the group.
* @return mixed An array of XML element objects for the group or boolean false on error.
// Make sure there is a valid JForm XML document.
if (!($this->xml instanceof
SimpleXMLElement))
// Make sure there is actually a group to find.
// Get any fields elements with the correct group name.
$elements =
$this->xml->xpath('//fields[@name="' . (string)
$group[0] .
'"]');
// Check to make sure that there are no parent groups for each element.
foreach ($elements as $element)
if (!$element->xpath('ancestor::fields[@name]'))
// Iterate through the nested groups to find any matching form field groups.
for ($i =
1, $n =
count($group); $i <
$n; $i++
)
// Initialise some loop variables.
// Check to make sure that there are no parent groups for each element.
foreach ($current as $element)
// Get any fields elements with the correct group name.
$children =
$element->xpath('descendant::fields[@name="' . (string)
$group[$i] .
'"]');
// For the found fields elements validate that they are in the correct groups.
foreach ($children as $fields)
// Get the group names as strings for ancestor fields elements.
$attrs =
$fields->xpath('ancestor-or-self::fields[@name]/@name');
$names =
array_map('strval', $attrs ?
$attrs :
array());
// If the group names for the fields element match the valid names at this
// level add the fields element.
if ($validNames ==
$names)
// Only include valid XML objects.
foreach ($tmp as $element)
if ($element instanceof
SimpleXMLElement)
* Method to load, setup and return a JFormField object based on field data.
* @param string $element The XML element object representation of the form field.
* @param string $group The optional dot-separated form group path on which to find the field.
* @param mixed $value The optional value to use as the default for the field.
* @return mixed The JFormField object for the field or boolean false on error.
protected function loadField($element, $group =
null, $value =
null)
// Make sure there is a valid SimpleXMLElement.
if (!($element instanceof
SimpleXMLElement))
$type =
$element['type'] ? (string)
$element['type'] :
'text';
// Load the JFormField object for the field.
// If the object could not be loaded, get a text field object.
* Get the value for the form field if not set.
* Default to the translated version of the 'default' attribute
* if 'translate_default' attribute if set to 'true' or '1'
* else the value of the 'default' attribute for the field.
$default = (string)
$element['default'];
if (($translate =
$element['translate_default']) &&
((string)
$translate ==
'true' || (string)
$translate ==
'1'))
if ($lang->hasKey($default))
$debug =
$lang->setDebug(false);
$default =
JText::_($default);
$default =
JText::_($default);
$value =
$this->getValue((string)
$element['name'], $group, $default);
// Setup the JFormField object.
if ($field->setup($element, $value, $group))
* Proxy for {@link JFormHelper::loadFieldType()}.
* @param string $type The field type.
* @param boolean $new Flag to toggle whether we should get a new instance of the object.
* @return mixed JFormField object on success, false otherwise.
* Proxy for JFormHelper::loadRuleType().
* @param string $type The rule type.
* @param boolean $new Flag to toggle whether we should get a new instance of the object.
* @return mixed JFormRule object on success, false otherwise.
* @see JFormHelper::loadRuleType()
* Method to synchronize any field, form or rule paths contained in the XML document.
* @return boolean True on success.
* @todo Maybe we should receive all addXXXpaths attributes at once?
// Make sure there is a valid JForm XML document.
if (!($this->xml instanceof
SimpleXMLElement))
// Get any addfieldpath attributes from the form definition.
$paths =
$this->xml->xpath('//*[@addfieldpath]/@addfieldpath');
$paths =
array_map('strval', $paths ?
$paths :
array());
foreach ($paths as $path)
self::addFieldPath($path);
// Get any addformpath attributes from the form definition.
$paths =
$this->xml->xpath('//*[@addformpath]/@addformpath');
$paths =
array_map('strval', $paths ?
$paths :
array());
foreach ($paths as $path)
self::addFormPath($path);
// Get any addrulepath attributes from the form definition.
$paths =
$this->xml->xpath('//*[@addrulepath]/@addrulepath');
$paths =
array_map('strval', $paths ?
$paths :
array());
foreach ($paths as $path)
self::addRulePath($path);
* Method to validate a JFormField object based on field data.
* @param SimpleXMLElement $element The XML element object representation of the form field.
* @param string $group The optional dot-separated form group path on which to find the field.
* @param mixed $value The optional value to use as the default for the field.
* @param JRegistry $input An optional JRegistry object with the entire data set to validate
* against the entire form.
* @return mixed Boolean true if field value is valid, Exception on failure.
* @throws InvalidArgumentException
* @throws UnexpectedValueException
protected function validateField(SimpleXMLElement $element, $group =
null, $value =
null, JRegistry $input =
null)
// Check if the field is required.
$required =
((string)
$element['required'] ==
'true' || (string)
$element['required'] ==
'required');
// If the field is required and the value is empty return an error message.
if (($value ===
'') ||
($value ===
null))
$message =
JText::_($element['label']);
$message =
JText::_($element['name']);
$message =
JText::sprintf('JLIB_FORM_VALIDATE_FIELD_REQUIRED', $message);
return new RuntimeException($message);
// Get the field validation rule.
if ($type = (string)
$element['validate'])
// Load the JFormRule object for the field.
// If the object could not be loaded return an error message.
throw
new UnexpectedValueException(sprintf('%s::validateField() rule `%s` missing.', get_class($this), $type));
// Run the field validation rule test.
$valid =
$rule->test($element, $value, $group, $input, $this);
// Check for an error in the validation test.
if ($valid instanceof
Exception)
// Check if the field is valid.
// Does the field have a defined error message?
$message = (string)
$element['message'];
$message =
JText::_($element['message']);
return new UnexpectedValueException($message);
$message =
JText::_($element['label']);
$message =
JText::sprintf('JLIB_FORM_VALIDATE_FIELD_INVALID', $message);
return new UnexpectedValueException($message);
* Proxy for {@link JFormHelper::addFieldPath()}.
* @param mixed $new A path or array of paths to add.
* @return array The list of paths that have been added.
* Proxy for JFormHelper::addFormPath().
* @param mixed $new A path or array of paths to add.
* @return array The list of paths that have been added.
* @see JFormHelper::addFormPath()
* Proxy for JFormHelper::addRulePath().
* @param mixed $new A path or array of paths to add.
* @return array The list of paths that have been added.
* @see JFormHelper::addRulePath()
* Method to get an instance of a form.
* @param string $name The name of the form.
* @param string $data The name of an XML file or string to load as the form definition.
* @param array $options An array of form options.
* @param string $replace Flag to toggle whether form fields should be replaced if a field
* already exists with the same group/name.
* @param string $xpath An optional xpath to search for the fields.
* @return object JForm instance.
* @throws InvalidArgumentException if no data provided.
* @throws RuntimeException if the form could not be loaded.
public static function getInstance($name, $data =
null, $options =
array(), $replace =
true, $xpath =
false)
// Reference to array with form instances
// Only instantiate the form if it does not already exist.
if (!isset
($forms[$name]))
throw
new InvalidArgumentException(sprintf('JForm::getInstance(name, *%s*)', gettype($data)));
$forms[$name] =
new JForm($name, $options);
if ($forms[$name]->load($data, $replace, $xpath) ==
false)
throw
new RuntimeException('JForm::getInstance could not load form');
if ($forms[$name]->loadFile($data, $replace, $xpath) ==
false)
throw
new RuntimeException('JForm::getInstance could not load file');
* Adds a new child SimpleXMLElement node to the source.
* @param SimpleXMLElement $source The source element on which to append.
* @param SimpleXMLElement $new The new element to append.
protected static function addNode(SimpleXMLElement $source, SimpleXMLElement $new)
// Add the new child node.
$node =
$source->addChild($new->getName(), trim($new));
// Add the attributes of the child node.
foreach ($new->attributes() as $name =>
$value)
$node->addAttribute($name, $value);
// Add any children of the new node.
foreach ($new->children() as $child)
self::addNode($node, $child);
* Update the attributes of a child node
* @param SimpleXMLElement $source The source element on which to append the attributes
* @param SimpleXMLElement $new The new element to append
protected static function mergeNode(SimpleXMLElement $source, SimpleXMLElement $new)
// Update the attributes of the child node.
foreach ($new->attributes() as $name =>
$value)
if (isset
($source[$name]))
$source[$name] = (string)
$value;
$source->addAttribute($name, $value);
* Merges new elements into a source <fields> element.
* @param SimpleXMLElement $source The source element.
* @param SimpleXMLElement $new The new element to merge.
protected static function mergeNodes(SimpleXMLElement $source, SimpleXMLElement $new)
// The assumption is that the inputs are at the same relative level.
// So we just have to scan the children and deal with them.
// Update the attributes of the child node.
foreach ($new->attributes() as $name =>
$value)
if (isset
($source[$name]))
$source[$name] = (string)
$value;
$source->addAttribute($name, $value);
foreach ($new->children() as $child)
$type =
$child->getName();
$fields =
$source->xpath($type .
'[@name="' .
$name .
'"]');
// This node does not exist, so add it.
self::addNode($source, $child);
self::mergeNode($fields[0], $child);
self::mergeNodes($fields[0], $child);
* Returns the value of an attribute of the form itself
* @param string $name Name of the attribute to get
* @param mixed $default Optional value to return if attribute not found
* @return mixed Value of the attribute / default
if ($this->xml instanceof
SimpleXMLElement)
$attributes =
$this->xml->attributes();
// Ensure that the attribute exists
$value =
$attributes->$name;
* Getter for the form data
* @return JRegistry Object with the data
* Method to get the XML form object
* @return SimpleXMLElement The form XML object
Documentation generated on Tue, 19 Nov 2013 15:03:34 +0100 by phpDocumentor 1.4.3