/contentmanager/code/trunk/administrator/components/com_contentmanager/libraries/jxtended/form/form.php
PHP | 924 lines | 394 code | 111 blank | 419 comment | 76 complexity | a214648258cb7ffebc881a64fc3e2e7f MD5 | raw file
- <?php
- /**
- * @version $Id: form.php 160 2009-07-09 00:06:09Z eddieajau $
- * @package JXtended.Libraries
- * @subpackage Form
- * @copyright Copyright (C) 2008 - 2009 JXtended, LLC. All rights reserved.
- * @license GNU General Public License <http://www.gnu.org/copyleft/gpl.html>
- * @link http://jxtended.com
- */
- defined('JPATH_BASE') or die;
- /**
- * Form Class for JXtended Libraries.
- *
- * 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.
- *
- * <code>
- * <?php
- * jximport2('jxtended.form.form');
- * $form = &JXForm::getInstance({XML FILE}, {OPTIONS});
- * ?>
- * </code>
- *
- * @package JXtended.Libraries
- * @subpackage Forms
- * @version 2.0
- */
- class JXForm extends JObject
- {
- /**
- * The form action URL.
- *
- * @access private
- * @since 2.0
- * @var string
- */
- var $_action = null;
- /**
- * The form id.
- *
- * @access private
- * @since 2.0
- * @var string
- */
- var $_id = null;
- /**
- * The form name.
- *
- * @access private
- * @since 2.0
- * @var string
- */
- var $_name = null;
- /**
- * Flag to indicate a multi-part form for uploads.
- *
- * @access private
- * @since 2.0
- * @var boolean
- */
- var $_multipart = false;
- /**
- * The form fieldsets as XML objects.
- *
- * @access private
- * @since 2.0
- * @var array
- */
- var $_fieldsets = array();
- /**
- * Method to get an instance of a form.
- *
- * @access public
- * @param string $file The name of the form to load.
- * @param array $options An array of options to pass to the form.
- * @return object A JXForm instance.
- * @since 2.0
- */
- function &getInstance($file, $options = array())
- {
- static $instances = null;
- if ($instances == null) {
- $instances = array();
- }
- // Only load the form once.
- if (!isset($instances[$file]))
- {
- // Instantiate the form.
- $instances[$file] = new JXForm($options);
- $instances[$file]->load($file, true, true);
- }
- return $instances[$file];
- }
- /**
- * Method to construct the object on instantiation.
- *
- * @access protected
- * @param array $options An array of form options.
- * @return void
- * @since 2.0
- */
- function __construct($options = array())
- {
- // Set the options if specified.
- $this->_action = array_key_exists('action', $options) ? $options['action'] : null;
- $this->_id = array_key_exists('id', $options) ? $options['id'] : null;
- $this->_multipart = array_key_exists('multipart', $options) ? $options['multipart'] : false;
- $this->_name = array_key_exists('name', $options) ? $options['name'] : 'jxform';
- }
- /**
- * Method to bind data to the form fields.
- *
- * @access public
- * @param mixed $data An array or object of form values.
- * @param string $group The group to bind the fields to.
- * @return boolean True on success, false otherwise.
- * @since 2.0
- */
- function bind($data, $group = null)
- {
- if (!is_object($data) && !is_array($data)) {
- return false;
- }
- // Iterate through the fieldsets.
- foreach ($this->_fieldsets as $fieldset => $fields)
- {
- // Bind if no group is specified or if the group matches the current fieldset.
- if ($group === null || ($group !== null && $fieldset === $group))
- {
- // Iterate through the values.
- foreach((array)$data as $k => $v)
- {
- // Bind the value to the field if it exists.
- if (isset($this->_fieldsets[$fieldset][$k]) && is_object($this->_fieldsets[$fieldset][$k])) {
- $this->_fieldsets[$fieldset][$k]->setData($v);
- }
- }
- }
- }
- return true;
- }
- /**
- * Method to load the form description from a file or string.
- *
- * If $data is a file name, $file must be set to true. The reset option
- * works on a group basis. If the XML file or string references groups
- * that have already been created they will be replaced with the fields
- * in the new file unless the $reset parameter has been set to false.
- *
- * @access public
- * @param string $data The name of an XML file or an XML string.
- * @param string $file Flag to toggle whether the $data is a file path or a string.
- * @param string $reset Flag to toggle whether the form description should be reset.
- * @return boolean True on success, false otherwise.
- * @since 2.0
- */
- function load($data, $file = true, $reset = true)
- {
- $return = false;
- // Make sure we have data.
- if (!empty($data))
- {
- // Get the XML parser and load the data.
- $parser = &JFactory::getXMLParser('Simple');
- // If the data is a file, load the XML from the file.
- if ($file)
- {
- // If we were not given the absolute path of a form file, attempt to find one.
- if (!file_exists($data)) {
- jimport('joomla.filesystem.path');
- $data = JPath::find(JXForm::addFormPath(), strtolower($data).'.xml');
- }
- // Attempt to load the XML file.
- $loaded = $parser->loadFile($data);
- }
- // Load the data as a string.
- else {
- $loaded = $parser->loadString($data);
- }
- // Make sure the XML was loaded.
- if ($loaded)
- {
- // Check if any fieldsets exist.
- if (isset($parser->document->fields))
- {
- // Load the form fieldsets.
- foreach ($parser->document->fields as $fieldset)
- {
- $this->loadFieldsXML($fieldset, $reset);
- $return = true;
- }
- }
- // Check if an action is set.
- if ($parser->document->attributes('action') && $reset) {
- $this->setAction($parser->document->attributes('action'));
- }
- // Check if a name is set.
- if ($parser->document->attributes('name') && $reset) {
- $this->setName($parser->document->attributes('name'));
- }
- // Check if an id is set.
- if ($parser->document->attributes('id') && $reset) {
- $this->setId($parser->document->attributes('id'));
- }
- }
- }
- return $return;
- }
- /**
- * Method to filter an array of data based on the form fields.
- *
- * @access public
- * @param array $data The data to filter.
- * @param string $group An optional group to limit the filtering to.
- * @return array An array of filtered data.
- * @since 2.0
- */
- function filter($data, $group = null)
- {
- $return = array();
- // Static input filters for specific settings
- static $noHtmlFilter = null;
- static $safeHtmlFilter = null;
- // Get the safe HTML filter if not set.
- if (is_null($safeHtmlFilter)) {
- $safeHtmlFilter = &JFilterInput::getInstance(null, null, 1, 1);
- }
- // Get the no HTML filter if not set.
- if (is_null($noHtmlFilter)) {
- $noHtmlFilter = &JFilterInput::getInstance(/* $tags, $attr, $tag_method, $attr_method, $xss_auto */);
- }
- // Iterate through the fieldsets.
- foreach ($this->_fieldsets as $fieldset => $fields)
- {
- // Filter if no group is specified or if the group matches the current fieldset.
- if ($group === null || ($group !== null && $fieldset === $group))
- {
- // Filter the fields.
- foreach ($fields as $name => $field)
- {
- // Get the field information.
- $filter = $field->attributes('filter');
- // Check for a value to filter.
- if (isset($data[$name]))
- {
- // Handle the different filter options.
- switch (strtoupper($filter))
- {
- case 'RAW':
- // No Filter.
- $return[$name] = $data[$name];
- break;
- case 'SAFEHTML':
- // Filter safe HTML.
- $return[$name] = $safeHtmlFilter->clean($data[$name], $filter);
- break;
- default:
- // Check for a callback filter.
- if (function_exists($filter)) {
- // Filter using the callback.
- $return[$name] = call_user_func($filter, $data[$name]);
- } else {
- // Filter out HTML.
- $return[$name] = $noHtmlFilter->clean($data[$name], $filter);
- }
- break;
- }
- }
- }
- }
- }
- return $return;
- }
- /**
- * Method to validate form data.
- *
- * Validation warnings will be pushed into JXForm::_errors and should be
- * retrieved with JXForm::getErrors() when validate returns boolean false.
- *
- * @access public
- * @param array $data An array of field values to validate.
- * @param string $group An option group to limit the validation to.
- * @return mixed Boolean on success, JException on error.
- * @since 2.0
- */
- function validate($data, $group = null)
- {
- $return = true;
- $data = (array)$data;
- // Check if the group exists.
- if ($group !== null && !isset($this->_fieldsets[$group])) {
- // The group that was supposed to be filtered does not exist.
- return new JException(JText::sprintf('JX_LIBRARIES_FORM_VALIDATOR_GROUP_NOT_FOUND', $group), 0, E_ERROR);
- }
- // Get a validator object.
- jximport2('jxtended.form.validator');
- $validator = new JXFormValidator();
- // Iterate through the fieldsets.
- foreach ($this->_fieldsets as $fieldset => $fields)
- {
- // Filter if no group is specified or if the group matches the current fieldset.
- if ($group === null || ($group !== null && $fieldset === $group))
- {
- // Run the validator over the group.
- $results = $validator->validate($this->_fieldsets[$fieldset], $data);
- // Check for a error.
- if (JError::isError($results) && $results->level === E_ERROR) {
- return new JException($results->getMessage(), 0, E_ERROR);
- }
- // Check the validation results.
- if (count($results))
- {
- // Get the validation messages.
- foreach ($results as $result) {
- if (JError::isError($result) && $result->level === E_WARNING) {
- $this->setError($result);
- $return = false;
- }
- }
- }
- }
- }
- return $return;
- }
- /**
- * Method to get the form action URL.
- *
- * @access public
- * @param string $default The default form action URL if it is not set.
- * @return string The form action URL.
- * @since 2.0
- */
- function getAction($default = null)
- {
- return !is_null($this->_action) ? $this->_action : $default;
- }
- /**
- * Method to set the form action URL.
- *
- * @access public
- * @param string $action The form action URL.
- * @return void
- * @since 2.0
- */
- function setAction($action)
- {
- $this->_action = $action;
- }
- /**
- * Method to get the form id.
- *
- * @access public
- * @param string $default The default form id if it is not set.
- * @return string The form id.
- * @since 2.0
- */
- function getId($default = null)
- {
- return !is_null($this->_id) ? $this->_id : $default;
- }
- /**
- * Method to set the form id.
- *
- * @access public
- * @param string $value The new form id.
- * @return void
- * @since 2.0
- */
- function setId($value)
- {
- $this->_id = $value;
- }
- /**
- * Method to get the form name.
- *
- * @access public
- * @param string $default The default form name if it is not set.
- * @return string The form name.
- * @since 2.0
- */
- function getName($default = null)
- {
- return !is_null($this->_name) ? $this->_name : $default;
- }
- /**
- * Method to set the form name.
- *
- * @access public
- * @param string $value The new form name.
- * @return void
- * @since 2.0
- */
- function setName($value)
- {
- $this->_name = $value;
- }
- /**
- * Method to add a field to a group.
- *
- * @access public
- * @param object $field The field object to add.
- * @param string $group The group to add the field to.
- * @return void
- * @since 2.0
- */
- function addField(&$field, $group = '_default')
- {
- // Add the field to the group.
- $this->_fieldsets[$group][$field->attributes('name')] = &$field;
- }
- /**
- * Method to add an array of fields to a group.
- *
- * @access public
- * @param array $fields An array of field objects to add.
- * @param string $group The group to add the fields to.
- * @return void
- * @since 2.0
- */
- function addFields(&$fields, $group = '_default')
- {
- // Add the fields to the group.
- foreach ($fields as $field) {
- $this->_fieldsets[$group][$field->attributes('name')] = $field;
- }
- }
- /**
- * Method to get a form field.
- *
- * @access public
- * @param string $name The name of the form field.
- * @param string $group The group the field is in.
- * @param mixed $controlName The control name of the field.
- * @return object Rendered Form Field object
- * @since 2.0
- */
- function getField($name, $group = '_default', $controlName = 'jxform')
- {
- // Get the XML node.
- $node = isset($this->_fieldsets[$group][$name]) ? $this->_fieldsets[$group][$name] : null;
- if (empty($node)) {
- return false;
- }
- // Get the field info.
- $type = $node->attributes('type');
- $data = $node->data();
- $value = !empty($data) ? $data : $node->attributes('default');
- // Load the field.
- $field = &$this->loadFieldType($type);
- // If the field could not be loaded, get a text field.
- if ($field === false) {
- $field = &$this->loadFieldType('text');
- }
- // Render the field.
- return $field->render($node, $value, $controlName);
- }
- /**
- * Method to replace a field in a group.
- *
- * @access public
- * @param object $field The field object to replace.
- * @param string $group The group to replace the field in.
- * @return void
- * @since 2.0
- */
- function setField(&$field, $group = '_default')
- {
- $return = false;
- // Add the fields to the group if it exists.
- if (isset($this->_fieldsets[$group][$field->attributes('name')])) {
- $this->_fieldsets[$group][$field->attributes('name')] = $field;
- $return = true;
- }
- return $return;
- }
- /**
- * Method to get the fields in a group.
- *
- * @access public
- * @param string $controlName The control name for the form field group
- * @param string $group The form field group
- * @return array Associative array of rendered Form Field object by field name
- * @since 2.0
- */
- function getFields($group = '_default', $controlName = 'jxform')
- {
- $results = array();
- // Check if the group exists.
- if (isset($this->_fieldsets[$group]))
- {
- // Get the fields in the group.
- foreach ($this->_fieldsets[$group] as $name => $node)
- {
- // Get the field info.
- $type = $node->attributes('type');
- $data = $node->data();
- $value = !empty($data) ? $data : $node->attributes('default');
- // Load the field.
- $field = &$this->loadFieldType($type);
- // If the field could not be loaded, get a text field.
- if ($field === false) {
- $field = &$this->loadFieldType('text');
- }
- // Render the field.
- $results[$name] = $field->render($node, $value, $controlName);
- }
- }
- return $results;
- }
- /**
- * Method to assign an array of fields to a group.
- *
- * @access public
- * @param array $fields An array of field objects to assign.
- * @param string $group The group to assign the fields to.
- * @return void
- * @since 2.0
- */
- function setFields(&$fields, $group = '_default')
- {
- // Reset the fields group,
- $this->_fieldsets[$group] = array();
- // Add the fields to the group.
- foreach ($fields as $field) {
- $this->_fieldsets[$group][$field->attributes('name')] = $field;
- }
- }
- /**
- * Method to get a list of fieldset groups.
- *
- * @access public
- * @return array An array of fieldset groups.
- * @since 2.0
- */
- function getGroups()
- {
- return array_keys($this->_fieldsets);
- }
- /**
- * Method to remove a fieldset group.
- *
- * @access public
- * @param string $group The fieldset group to remove.
- * @return void
- * @since 2.0
- */
- function removeGroup($group)
- {
- unset($this->_fieldsets[$group]);
- }
- /**
- * Method to get the input control for a field.
- *
- * @access public
- * @param string The field name.
- * @param string The control name for the form field.
- * @param string The group the field is in.
- * @param mixed The optional value to render as the default for the field.
- * @return string The form field input control.
- * @since 2.0
- */
- function getInput($name, $controlName = 'jxform', $group = '_default', $value = null)
- {
- // Get the XML node.
- $node = isset($this->_fieldsets[$group][$name]) ? $this->_fieldsets[$group][$name] : null;
- // If there is no XML node for the given field name, return false.
- if (empty($node)) {
- return false;
- }
- // Load the field type.
- $type = $node->attributes('type');
- $field = & $this->loadFieldType($type);
- // If the field could not be loaded, get a text field.
- if ($field === false) {
- $field = & $this->loadFieldType('text');
- }
- // Get the value for the form field.
- if ($value === null) {
- $data = $node->data();
- $value = !empty($data) ? $data : $node->attributes('default');
- }
- // Render the field label.
- $input = $field->fetchField($name, $value, $node, $controlName);
- return $input;
- }
- /**
- * Method to get the label for a field.
- *
- * @access public
- * @param string The field name.
- * @param string The control name for the form field.
- * @param string The group the field is in.
- * @return string The form field label.
- * @since 2.0
- */
- function getLabel($name, $controlName = 'jxform', $group = '_default')
- {
- // Get the XML node.
- $node = isset($this->_fieldsets[$group][$name]) ? $this->_fieldsets[$group][$name] : null;
- // If there is no XML node for the given field name, return false.
- if (empty($node)) {
- return false;
- }
- // Load the field type.
- $type = $node->attributes('type');
- $field = & $this->loadFieldType($type);
- // If the field could not be loaded, get a text field.
- if ($field === false) {
- $field = & $this->loadFieldType('text');
- }
- // Get some field attributes for rendering the label.
- $label = $node->attributes('label');
- $descr = $node->attributes('description');
- // Make sure we have a valid label.
- $label = $label ? $label : $name;
- // Render the field label.
- $label = $field->fetchLabel($label, $descr, $node, $controlName, $name);
- return $label;
- }
- /**
- * Method to get the value of a field.
- *
- * @access public
- * @param string $field The field to set.
- * @param mixed $default The default value of the field if empty.
- * @param string $group The group the field is in.
- * @return boolean The value of the field or the default value if empty.
- * @since 2.0
- */
- function getValue($field, $default = null, $group = '_default')
- {
- $return = null;
- // Get the field value if it exists.
- if (isset($this->_fieldsets[$group][$field]) && is_object($this->_fieldsets[$group][$field])) {
- $return = $this->_fieldsets[$group][$field]->data() ? $this->_fieldsets[$group][$field]->data() : $default;
- }
- return $return;
- }
- /**
- * Method to set the value of a field.
- *
- * @access public
- * @param string $field The field to set.
- * @param mixed $value The value to set the field to.
- * @param string $group The group the field is in.
- * @return boolean True if field exists, false otherwise.
- * @since 2.0
- */
- function setValue($field, $value, $group = '_default')
- {
- // Set the field if it exists.
- if (isset($this->_fieldsets[$group][$field]) && is_object($this->_fieldsets[$group][$field])) {
- $this->_fieldsets[$group][$field]->setData($value);
- return true;
- } else {
- return false;
- }
- }
- /**
- * Loads form fields from an XML fieldset element optionally reseting fields before loading new ones.
- *
- * @access public
- * @param object $xml The XML fieldset object.
- * @param boolean $reset Flag to toggle whether the form fieldset should be reset.
- * @return boolean True on success, false otherwise.
- * @since 2.0
- */
- function loadFieldsXML(&$xml, $reset = true)
- {
- // Check for an XML object.
- if (!is_object($xml)) {
- return false;
- }
- // Get the group name.
- $group = ($xml->attributes('group')) ? $xml->attributes('group') : '_default';
- if ($reset) {
- // Reset the field group.
- $this->setFields($xml->children(), $group);
- } else {
- // Add to the field group.
- $this->addFields($xml->children(), $group);
- }
- // Check if there is a field path to handle.
- if ($xml->attributes('addfieldpath'))
- {
- jimport('joomla.filesystem.folder');
- jimport('joomla.filesystem.path');
- $path = JPath::clean(JPATH_ROOT.DS.$xml->attributes('addfieldpath'));
- // Add the field path to the list if it exists.
- if (JFolder::exists($path)) {
- JXForm::addFieldPath($path);
- }
- }
- return true;
- }
- /**
- * Method to load a form field object.
- *
- * @access public
- * @param string $type The field type.
- * @param boolean $new Flag to toggle whether we should get a new instance of the object.
- * @return mixed Field object on success, false otherwise.
- * @since 2.0
- */
- function &loadFieldType($type, $new = false)
- {
- $false = false;
- $key = md5($type);
- $class = 'JXFieldType'.ucfirst($type);
- // Return the field object if it already exists and we don't need a new one.
- if (isset($this->_fieldTypes[$key]) && $new === false) {
- return $this->_fieldTypes[$key];
- }
- if (!class_exists('JXFormFieldList') || !class_exists('JXFormFieldList')) {
- jximport2('jxtended.form.formfield');
- jximport2('jxtended.form.fields.list');
- }
- // TODO: Is this needed?
- // // Check if the field is a complex type.
- // if ($pos = strpos($type, '_'))
- // {
- // // Load the base field type.
- // $base = substr($type, 0, $pos);
- // $this->loadFieldType($base);
- // }
- if(!class_exists($class))
- {
- $paths = JXForm::addFieldPath();
- // If the type is complex, add the base type to the paths.
- if ($pos = strpos($type, '_'))
- {
- // Add the complex type prefix to the paths.
- for ($i = 0, $n = count($paths); $i < $n; $i++)
- {
- // Derive the new path.
- $path = $paths[$i].DS.substr($type, 0, $pos);
- // If the path does not exist, add it.
- if (!in_array($path, $paths)) {
- array_unshift($paths, $path);
- }
- }
- // Break off the end of the complex type.
- $type = substr($type, $pos+1);
- }
- // Try to find the field file.
- jimport('joomla.filesystem.path');
- if ($file = JPath::find($paths, strtolower($type).'.php')) {
- require_once $file;
- } else {
- return $false;
- }
- // Check once and for all if the class exists.
- if (!class_exists($class)) {
- return $false;
- }
- }
- // Instantiate a new field object.
- $this->_fieldTypes[$key] = new $class($this);
- return $this->_fieldTypes[$key];
- }
- /**
- * Method to add a path to the list of form include paths.
- *
- * @access public
- * @param mixed $new A path or array of paths to add.
- * @return array The list of paths that have been added.
- * @since 2.0
- * @static
- */
- function addFormPath($new = null)
- {
- static $paths;
- if (!isset($paths)) {
- $paths = array(dirname(__FILE__).DS.'forms');
- }
- // Force path to an array.
- settype($new, 'array');
- // Add the new paths to the list if not already there.
- foreach ($new as $path) {
- if (!in_array($path, $paths)) {
- array_unshift($paths, trim($path));
- }
- }
- return $paths;
- }
- /**
- * Method to add a path to the list of field include paths.
- *
- * @access public
- * @param mixed $new A path or array of paths to add.
- * @return array The list of paths that have been added.
- * @since 2.0
- * @static
- */
- function addFieldPath($new = null)
- {
- static $paths;
- if (!isset($paths)) {
- $paths = array(dirname(__FILE__).DS.'fields');
- }
- // Force path to an array.
- settype($new, 'array');
- // Add the new paths to the list if not already there.
- foreach ($new as $path) {
- if (!in_array($path, $paths)) {
- array_unshift($paths, trim($path));
- }
- }
- return $paths;
- }
- }