10 defined(
'JPATH_PLATFORM') or die;
12 jimport('joomla.filesystem.path');
13 jimport('joomla.utilities.arrayhelper');
42 protected $errors = array();
56 protected $options = array();
70 protected static $forms = array();
77 public $repeat =
false;
87 public function __construct($name, array $options = array())
96 $this->options[
'control'] = isset($options[
'control']) ? $options[
'control'] :
false;
108 public function bind($data)
111 if (!($this->xml instanceof SimpleXMLElement))
117 if (!is_object($data) && !is_array($data))
123 if (is_object($data))
130 elseif ($data instanceof
JObject)
133 $data = $data->getProperties();
138 $data = (array) $data;
143 foreach ($data as $k => $v)
145 if ($this->findField($k))
148 $this->data->set($k, $v);
153 $this->bindLevel($k, $v);
170 protected function bindLevel($group, $data)
173 settype($data,
'array');
176 foreach ($data as $k => $v)
178 if ($this->findField($k, $group))
181 $this->data->set($group .
'.' . $k, $v);
186 $this->bindLevel($group .
'.' . $k, $v);
201 public function filter($data, $group = null)
204 if (!($this->xml instanceof SimpleXMLElement))
213 $fields = $this->findFieldsByGroup($group);
222 foreach ($fields as $field)
224 $name = (string) $field[
'name'];
227 $attrs = $field->xpath(
'ancestor::fields[@name]/@name');
228 $groups = array_map(
'strval', $attrs ? $attrs : array());
229 $group = implode(
'.', $groups);
235 if ($input->exists($group .
'.' . $name))
237 $output->set($group .
'.' . $name, $this->filterField($field, $input->get($group .
'.' . $name, (
string) $field[
'default'])));
243 if ($input->exists($name))
245 $output->set($name, $this->filterField($field, $input->get($name, (
string) $field[
'default'])));
250 return $output->toArray();
260 public function getErrors()
262 return $this->errors;
276 public function getField($name, $group = null, $value = null)
279 if (!($this->xml instanceof SimpleXMLElement))
285 $element = $this->findField($name, $group);
293 return $this->loadField($element, $group, $value);
310 public function getFieldAttribute($name, $attribute, $default = null, $group = null)
313 if (!($this->xml instanceof SimpleXMLElement))
315 throw new UnexpectedValueException(sprintf(
'%s::getFieldAttribute `xml` is not an instance of SimpleXMLElement', get_class($this)));
319 $element = $this->findField($name, $group);
322 if (($element instanceof SimpleXMLElement) && ((
string) $element[$attribute]))
324 return (
string) $element[$attribute];
344 public function getFieldset($set = null)
351 $elements = $this->findFieldsByFieldset($set);
357 $elements = $this->findFieldsByGroup();
361 if (empty($elements))
367 foreach ($elements as $element)
370 $attrs = $element->xpath(
'ancestor::fields[@name]/@name');
371 $groups = array_map(
'strval', $attrs ? $attrs : array());
372 $group = implode(
'.', $groups);
375 if ($field = $this->loadField($element, $group))
377 $fields[$field->id] = $field;
393 public function getFieldsets($group = null)
395 $fieldsets = array();
399 if (!($this->xml instanceof SimpleXMLElement))
407 $elements = &$this->findGroup($group);
409 foreach ($elements as &$element)
412 if ($tmp = $element->xpath(
'descendant::fieldset[@name] | descendant::field[@fieldset]/@fieldset'))
414 $sets = array_merge($sets, (array) $tmp);
421 $sets = $this->xml->xpath(
'//fieldset[@name] | //field[@fieldset]/@fieldset');
431 foreach ($sets as $set)
434 if ((
string) $set[
'name'])
437 if (empty($fieldsets[(
string) $set[
'name']]))
440 $fieldset = (object) array(
'name' =>
'',
'label' =>
'',
'description' =>
'');
442 foreach ($set->attributes() as $name => $value)
444 $fieldset->$name = (string) $value;
448 $fieldsets[$fieldset->name] = $fieldset;
456 if (empty($fieldsets[(
string) $set]))
459 $tmp = $this->xml->xpath(
'//fieldset[@name="' . (
string) $set .
'"]');
464 $fieldset = (object) array(
'name' => (
string) $set,
'label' =>
'',
'description' =>
'');
470 $fieldset = (object) array(
'name' =>
'',
'label' =>
'',
'description' =>
'');
472 foreach ($tmp[0]->attributes() as $name => $value)
474 $fieldset->$name = (string) $value;
479 $fieldsets[$fieldset->name] = $fieldset;
498 public function getFormControl()
500 return (
string) $this->options[
'control'];
514 public function getGroup($group, $nested =
false)
519 $elements = $this->findFieldsByGroup($group, $nested);
522 if (empty($elements))
528 foreach ($elements as $element)
531 $attrs = $element->xpath(
'ancestor::fields[@name]/@name');
532 $groups = array_map(
'strval', $attrs ? $attrs : array());
533 $group = implode(
'.', $groups);
536 if ($field = $this->loadField($element, $group))
538 $fields[$field->id] = $field;
556 public function getInput($name, $group = null, $value = null)
559 if ($field = $this->getField($name, $group, $value))
561 return $field->input;
577 public function getLabel($name, $group = null)
580 if ($field = $this->getField($name, $group))
582 return $field->label;
595 public function getName()
611 public function getValue($name, $group = null, $default = null)
616 $return = $this->data->get($group .
'.' . $name, $default);
620 $return = $this->data->get($name, $default);
637 public function getControlGroup($name, $group = null, $default = null)
639 $field = $this->getField($name, $group, $default);
642 return $field->getControlGroup();
656 public function getControlGroups($name)
658 $fields = $this->getFieldset($name);
661 foreach ($fields as $field)
663 $html[] = $field->getControlGroup();
666 return implode(
'', $html);
687 public function load($data, $replace =
true, $xpath =
false)
690 if ((!($data instanceof SimpleXMLElement)) && (!is_string($data)))
696 if (is_string($data))
700 $data =
new SimpleXMLElement($data);
715 if (empty($this->xml))
718 if (!$xpath && ($data->getName() ==
'form'))
731 $this->xml =
new SimpleXMLElement(
'<form></form>');
740 $elements = $data->xpath($xpath);
742 elseif ($data->getName() ==
'form')
744 $elements = $data->children();
748 if (empty($elements))
754 foreach ($elements as $element)
757 $fields = $element->xpath(
'descendant-or-self::field');
759 foreach ($fields as $field)
762 $attrs = $field->xpath(
'ancestor::fields[@name]/@name');
763 $groups = array_map(
'strval', $attrs ? $attrs : array());
766 if ($current = $this->findField((
string) $field[
'name'], implode(
'.', $groups)))
771 $olddom = dom_import_simplexml($current);
772 $loadeddom = dom_import_simplexml($field);
773 $addeddom = $olddom->ownerDocument->importNode($loadeddom);
774 $olddom->parentNode->replaceChild($addeddom, $olddom);
775 $loadeddom->parentNode->removeChild($loadeddom);
785 self::addNode($this->xml, $element);
811 public function loadFile($file, $reset =
true, $xpath =
false)
817 $file =
JPath::find(self::addFormPath(), strtolower($file) .
'.xml');
827 $xml = simplexml_load_file($file);
829 return $this->load($xml, $reset, $xpath);
843 public function removeField($name, $group = null)
846 if (!($this->xml instanceof SimpleXMLElement))
848 throw new UnexpectedValueException(sprintf(
'%s::getFieldAttribute `xml` is not an instance of SimpleXMLElement', get_class($this)));
852 $element = $this->findField($name, $group);
855 if ($element instanceof SimpleXMLElement)
857 $dom = dom_import_simplexml($element);
858 $dom->parentNode->removeChild($dom);
874 public function removeGroup($group)
877 if (!($this->xml instanceof SimpleXMLElement))
879 throw new UnexpectedValueException(sprintf(
'%s::getFieldAttribute `xml` is not an instance of SimpleXMLElement', get_class($this)));
883 $elements = &$this->findGroup($group);
885 foreach ($elements as &$element)
887 $dom = dom_import_simplexml($element);
888 $dom->parentNode->removeChild($dom);
903 public function reset($xml =
false)
911 $this->xml =
new SimpleXMLElement(
'<form></form>');
931 public function setField(SimpleXMLElement $element, $group = null, $replace =
true)
934 if (!($this->xml instanceof SimpleXMLElement))
936 throw new UnexpectedValueException(sprintf(
'%s::getFieldAttribute `xml` is not an instance of SimpleXMLElement', get_class($this)));
940 $old = $this->findField((
string) $element[
'name'], $group);
943 if (!$replace && !empty($old))
949 if ($replace && !empty($old) && ($old instanceof SimpleXMLElement))
951 $dom = dom_import_simplexml($old);
952 $dom->parentNode->removeChild($dom);
959 $fields = &$this->findGroup($group);
962 if (isset($fields[0]) && ($fields[0] instanceof SimpleXMLElement))
964 self::addNode($fields[0], $element);
970 self::addNode($this->xml, $element);
992 public function setFieldAttribute($name, $attribute, $value, $group = null)
995 if (!($this->xml instanceof SimpleXMLElement))
997 throw new UnexpectedValueException(sprintf(
'%s::getFieldAttribute `xml` is not an instance of SimpleXMLElement', get_class($this)));
1001 $element = $this->findField($name, $group);
1004 if (!($element instanceof SimpleXMLElement))
1012 $element[$attribute] = $value;
1035 public function setFields(&$elements, $group = null, $replace =
true)
1038 if (!($this->xml instanceof SimpleXMLElement))
1040 throw new UnexpectedValueException(sprintf(
'%s::getFieldAttribute `xml` is not an instance of SimpleXMLElement', get_class($this)));
1044 foreach ($elements as $element)
1046 if (!($element instanceof SimpleXMLElement))
1048 throw new UnexpectedValueException(sprintf(
'$element not SimpleXMLElement in %s::setFields', get_class($this)));
1055 foreach ($elements as $element)
1057 if (!$this->setField($element, $group, $replace))
1081 public function setValue($name, $group = null, $value = null)
1084 if (!$this->findField($name, $group))
1092 $this->data->set($group .
'.' . $name, $value);
1096 $this->data->set($name, $value);
1116 public function validate($data, $group = null)
1119 if (!($this->xml instanceof SimpleXMLElement))
1130 $fields = $this->findFieldsByGroup($group);
1139 foreach ($fields as $field)
1142 $name = (string) $field[
'name'];
1145 $attrs = $field->xpath(
'ancestor::fields[@name]/@name');
1146 $groups = array_map(
'strval', $attrs ? $attrs : array());
1147 $group = implode(
'.', $groups);
1152 $value = $input->get($group .
'.' . $name);
1156 $value = $input->get($name);
1160 $valid = $this->validateField($field, $group, $value, $input);
1163 if ($valid instanceof Exception)
1165 array_push($this->errors, $valid);
1183 protected function filterField($element, $value)
1186 if (!($element instanceof SimpleXMLElement))
1192 $filter = (string) $element[
'filter'];
1197 switch (strtoupper($filter))
1203 foreach ((array) $value as $action => $ids)
1206 $return[$action] = array();
1208 foreach ($ids as $id => $p)
1212 $return[$action][$id] = ($p ==
'1' || $p ==
'true') ?
true :
false;
1230 if (is_object($value))
1232 $value = get_object_vars($value);
1235 $value = is_array($value) ? $value : array($value);
1248 if ((
int) $value > 0)
1264 if ((
int) $value > 0)
1288 $value = trim($value);
1291 $protocol = parse_url($value, PHP_URL_SCHEME);
1295 if (($element[
'type'] ==
'url' && !$protocol && !$element[
'relative'])
1296 || (!$element[
'type'] ==
'url' && !$protocol))
1301 if (substr($value, 0) ==
'index.php')
1308 $value = $protocol .
'://' . $value;
1312 elseif (!$protocol && $element[
'relative'])
1317 if (substr($value, 0) == $host)
1319 $value =
'http://' . $value;
1334 $value = trim($value);
1337 if (preg_match(
'/^(?:\+?1[-. ]?)?\(?([2-9][0-8][0-9])\)?[-. ]?([2-9][0-9]{2})[-. ]?([0-9]{4})$/', $value) == 1)
1339 $number = (string) preg_replace(
'/[^\d]/',
'', $value);
1341 if (substr($number, 0, 1) == 1)
1343 $number = substr($number, 1);
1346 if (substr($number, 0, 2) ==
'+1')
1348 $number = substr($number, 2);
1351 $result =
'1.' . $number;
1355 elseif (preg_match(
'/^\+(?:[0-9] ?){6,14}[0-9]$/', $value) == 1)
1357 $countrycode = substr($value, 0, strpos($value,
' '));
1358 $countrycode = (string) preg_replace(
'/[^\d]/',
'', $countrycode);
1359 $number = strstr($value,
' ');
1360 $number = (string) preg_replace(
'/[^\d]/',
'', $number);
1361 $result = $countrycode .
'.' . $number;
1365 elseif (preg_match(
'/^\+[0-9]{1,3}\.[0-9]{4,14}(?:x.+)?$/', $value) == 1)
1367 if (strstr($value,
'x'))
1369 $xpos = strpos($value,
'x');
1370 $value = substr($value, 0, $xpos);
1373 $result = str_replace(
'+',
'', $value);
1377 elseif (preg_match(
'/[0-9]{1,3}\.[0-9]{4,14}$/', $value) == 1)
1385 $value = (string) preg_replace(
'/[^\d]/',
'', $value);
1387 if ($value != null && strlen($value) <= 15)
1389 $length = strlen($value);
1394 $result =
'.' . $value;
1399 $cclen = $length - 12;
1400 $result = substr($value, 0, $cclen) .
'.' . substr($value, $cclen);
1416 if (strpos($filter,
'::') !==
false && is_callable(explode(
'::', $filter)))
1418 $return = call_user_func(explode(
'::', $filter), $value);
1422 elseif (function_exists($filter))
1424 $return = call_user_func($filter, $value);
1448 protected function findField($name, $group = null)
1454 if (!($this->xml instanceof SimpleXMLElement))
1463 $elements = &$this->findGroup($group);
1466 foreach ($elements as $element)
1469 if ($tmp = $element->xpath(
'descendant::field[@name="' . $name .
'"]'))
1471 $fields = array_merge($fields, $tmp);
1482 $groupNames = explode(
'.', $group);
1484 foreach ($fields as &$field)
1487 $attrs = $field->xpath(
'ancestor::fields[@name]/@name');
1488 $names = array_map(
'strval', $attrs ? $attrs : array());
1491 if ($names == (array) $groupNames)
1501 $fields = $this->xml->xpath(
'//field[@name="' . $name .
'"]');
1510 foreach ($fields as &$field)
1513 if ($field->xpath(
'ancestor::fields[@name]'))
1540 protected function &findFieldsByFieldset($name)
1545 if (!($this->xml instanceof SimpleXMLElement))
1556 $fields = $this->xml->xpath(
'//fieldset[@name="' . $name .
'"]/field | //field[@fieldset="' . $name .
'"]');
1574 protected function &findFieldsByGroup($group = null, $nested =
false)
1580 if (!($this->xml instanceof SimpleXMLElement))
1589 $elements = &$this->findGroup($group);
1592 foreach ($elements as $element)
1595 if ($tmp = $element->xpath(
'descendant::field'))
1600 $fields = array_merge($fields, $tmp);
1606 $groupNames = explode(
'.', $group);
1608 foreach ($tmp as $field)
1611 $attrs = $field->xpath(
'ancestor::fields[@name]/@name');
1612 $names = array_map(
'strval', $attrs ? $attrs : array());
1615 if ($names == (array) $groupNames)
1617 $fields = array_merge($fields, array($field));
1624 elseif ($group ===
false)
1627 $fields = $this->xml->xpath(
'descendant::fields[not(@name)]/field | descendant::fields[not(@name)]/fieldset/field ');
1632 $fields = $this->xml->xpath(
'//field');
1647 protected function &findGroup($group)
1654 if (!($this->xml instanceof SimpleXMLElement))
1660 $group = explode(
'.', $group);
1665 $elements = $this->xml->xpath(
'//fields[@name="' . (
string) $group[0] .
'"]');
1668 foreach ($elements as $element)
1670 if (!$element->xpath(
'ancestor::fields[@name]'))
1677 for ($i = 1, $n = count($group); $i < $n; $i++)
1680 $validNames = array_slice($group, 0, $i + 1);
1685 foreach ($current as $element)
1688 $children = $element->xpath(
'descendant::fields[@name="' . (
string) $group[$i] .
'"]');
1691 foreach ($children as $fields)
1694 $attrs = $fields->xpath(
'ancestor-or-self::fields[@name]/@name');
1695 $names = array_map(
'strval', $attrs ? $attrs : array());
1699 if ($validNames == $names)
1708 foreach ($tmp as $element)
1710 if ($element instanceof SimpleXMLElement)
1712 $groups[] = $element;
1731 protected function loadField($element, $group = null, $value = null)
1734 if (!($element instanceof SimpleXMLElement))
1740 $type = $element[
'type'] ? (string) $element[
'type'] :
'text';
1743 $field = $this->loadFieldType($type);
1746 if ($field ===
false)
1748 $field = $this->loadFieldType(
'text');
1757 if ($value === null)
1759 $default = (string) $element[
'default'];
1761 if (($translate = $element[
'translate_default']) && ((string) $translate ==
'true' || (
string) $translate ==
'1'))
1765 if ($lang->hasKey($default))
1767 $debug = $lang->setDebug(
false);
1769 $lang->setDebug($debug);
1777 $value = $this->getValue((
string) $element[
'name'], $group, $default);
1781 $field->setForm($this);
1783 if ($field->setup($element, $value, $group))
1803 protected function loadFieldType($type, $new =
true)
1819 protected function loadRuleType($type, $new =
true)
1832 protected function syncPaths()
1835 if (!($this->xml instanceof SimpleXMLElement))
1841 $paths = $this->xml->xpath(
'//*[@addfieldpath]/@addfieldpath');
1842 $paths = array_map(
'strval', $paths ? $paths : array());
1845 foreach ($paths as $path)
1847 $path = JPATH_ROOT .
'/' . ltrim($path,
'/\\');
1848 self::addFieldPath($path);
1852 $paths = $this->xml->xpath(
'//*[@addformpath]/@addformpath');
1853 $paths = array_map(
'strval', $paths ? $paths : array());
1856 foreach ($paths as $path)
1858 $path = JPATH_ROOT .
'/' . ltrim($path,
'/\\');
1859 self::addFormPath($path);
1863 $paths = $this->xml->xpath(
'//*[@addrulepath]/@addrulepath');
1864 $paths = array_map(
'strval', $paths ? $paths : array());
1867 foreach ($paths as $path)
1869 $path = JPATH_ROOT .
'/' . ltrim($path,
'/\\');
1870 self::addRulePath($path);
1891 protected function validateField(SimpleXMLElement $element, $group = null, $value = null,
JRegistry $input = null)
1896 $required = ((string) $element[
'required'] ==
'true' || (
string) $element[
'required'] ==
'required');
1901 if (($value ===
'') || ($value === null))
1903 if ($element[
'label'])
1905 $message =
JText::_($element[
'label']);
1909 $message =
JText::_($element[
'name']);
1912 $message =
JText::sprintf(
'JLIB_FORM_VALIDATE_FIELD_REQUIRED', $message);
1914 return new RuntimeException($message);
1919 if ($type = (
string) $element[
'validate'])
1922 $rule = $this->loadRuleType($type);
1925 if ($rule ===
false)
1927 throw new UnexpectedValueException(sprintf(
'%s::validateField() rule `%s` missing.', get_class($this), $type));
1931 $valid = $rule->test($element, $value, $group, $input, $this);
1934 if ($valid instanceof Exception)
1941 if ($valid ===
false)
1944 $message = (string) $element[
'message'];
1948 $message =
JText::_($element[
'message']);
1950 return new UnexpectedValueException($message);
1954 $message =
JText::_($element[
'label']);
1955 $message =
JText::sprintf(
'JLIB_FORM_VALIDATE_FIELD_INVALID', $message);
1957 return new UnexpectedValueException($message);
1973 public static function addFieldPath($new = null)
1988 public static function addFormPath($new = null)
2003 public static function addRulePath($new = null)
2024 public static function getInstance($name, $data = null, $options = array(), $replace =
true, $xpath =
false)
2027 $forms = &self::$forms;
2030 if (!isset($forms[$name]))
2032 $data = trim($data);
2036 throw new InvalidArgumentException(sprintf(
'JForm::getInstance(name, *%s*)', gettype($data)));
2040 $forms[$name] =
new JForm($name, $options);
2043 if (substr(trim($data), 0, 1) ==
'<')
2045 if ($forms[$name]->load($data, $replace, $xpath) ==
false)
2047 throw new RuntimeException(
'JForm::getInstance could not load form');
2052 if ($forms[$name]->loadFile($data, $replace, $xpath) ==
false)
2054 throw new RuntimeException(
'JForm::getInstance could not load file');
2059 return $forms[$name];
2072 protected static function addNode(SimpleXMLElement $source, SimpleXMLElement $new)
2075 $node = $source->addChild($new->getName(), trim($new));
2078 foreach ($new->attributes() as $name => $value)
2080 $node->addAttribute($name, $value);
2084 foreach ($new->children() as $child)
2086 self::addNode($node, $child);
2100 protected static function mergeNode(SimpleXMLElement $source, SimpleXMLElement $new)
2103 foreach ($new->attributes() as $name => $value)
2105 if (isset($source[$name]))
2107 $source[$name] = (string) $value;
2111 $source->addAttribute($name, $value);
2126 protected static function mergeNodes(SimpleXMLElement $source, SimpleXMLElement $new)
2132 foreach ($new->attributes() as $name => $value)
2134 if (isset($source[$name]))
2136 $source[$name] = (string) $value;
2140 $source->addAttribute($name, $value);
2144 foreach ($new->children() as $child)
2146 $type = $child->getName();
2147 $name = $child[
'name'];
2150 $fields = $source->xpath($type .
'[@name="' . $name .
'"]');
2155 self::addNode($source, $child);
2163 self::mergeNode($fields[0], $child);
2167 self::mergeNodes($fields[0], $child);
2184 public function getAttribute($name, $default = null)
2186 if ($this->xml instanceof SimpleXMLElement)
2188 $attributes = $this->xml->attributes();
2191 if (property_exists($attributes, $name))
2193 $value = $attributes->$name;
2195 if ($value !== null)
2197 return (
string) $value;
2212 public function getData()
2224 public function getXml()