summaryrefslogtreecommitdiffstats
path: root/library/vendor/Zend/Form.php
diff options
context:
space:
mode:
Diffstat (limited to 'library/vendor/Zend/Form.php')
-rw-r--r--library/vendor/Zend/Form.php3472
1 files changed, 3472 insertions, 0 deletions
diff --git a/library/vendor/Zend/Form.php b/library/vendor/Zend/Form.php
new file mode 100644
index 0000000..91987ac
--- /dev/null
+++ b/library/vendor/Zend/Form.php
@@ -0,0 +1,3472 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category Zend
+ * @package Zend_Form
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+/** @see Zend_Validate_Interface */
+
+/**
+ * Zend_Form
+ *
+ * @category Zend
+ * @package Zend_Form
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @version $Id$
+ */
+class Zend_Form implements Iterator, Countable, Zend_Validate_Interface
+{
+ /**#@+
+ * Plugin loader type constants
+ */
+ const DECORATOR = 'DECORATOR';
+ const ELEMENT = 'ELEMENT';
+ /**#@-*/
+
+ /**#@+
+ * Method type constants
+ */
+ const METHOD_DELETE = 'delete';
+ const METHOD_GET = 'get';
+ const METHOD_POST = 'post';
+ const METHOD_PUT = 'put';
+ /**#@-*/
+
+ /**#@+
+ * Encoding type constants
+ */
+ const ENCTYPE_URLENCODED = 'application/x-www-form-urlencoded';
+ const ENCTYPE_MULTIPART = 'multipart/form-data';
+ /**#@-*/
+
+ /**
+ * Form metadata and attributes
+ * @var array
+ */
+ protected $_attribs = array();
+
+ /**
+ * Decorators for rendering
+ * @var array
+ */
+ protected $_decorators = array();
+
+ /**
+ * Default display group class
+ * @var string
+ */
+ protected $_defaultDisplayGroupClass = 'Zend_Form_DisplayGroup';
+
+ /**
+ * Form description
+ * @var string
+ */
+ protected $_description;
+
+ /**
+ * Should we disable loading the default decorators?
+ * @var bool
+ */
+ protected $_disableLoadDefaultDecorators = false;
+
+ /**
+ * Display group prefix paths
+ * @var array
+ */
+ protected $_displayGroupPrefixPaths = array();
+
+ /**
+ * Groups of elements grouped for display purposes
+ * @var array
+ */
+ protected $_displayGroups = array();
+
+ /**
+ * Global decorators to apply to all elements
+ * @var null|array
+ */
+ protected $_elementDecorators;
+
+ /**
+ * Prefix paths to use when creating elements
+ * @var array
+ */
+ protected $_elementPrefixPaths = array();
+
+ /**
+ * Form elements
+ * @var array
+ */
+ protected $_elements = array();
+
+ /**
+ * Array to which elements belong (if any)
+ * @var string
+ */
+ protected $_elementsBelongTo;
+
+ /**
+ * Custom form-level error messages
+ * @var array
+ */
+ protected $_errorMessages = array();
+
+ /**
+ * Are there errors in the form?
+ * @var bool
+ */
+ protected $_errorsExist = false;
+
+ /**
+ * Has the form been manually flagged as an error?
+ * @var bool
+ */
+ protected $_errorsForced = false;
+
+ /**
+ * Form order
+ * @var int|null
+ */
+ protected $_formOrder;
+
+ /**
+ * Whether or not form elements are members of an array
+ * @var bool
+ */
+ protected $_isArray = false;
+
+ /**
+ * Form legend
+ * @var string
+ */
+ protected $_legend;
+
+ /**
+ * Plugin loaders
+ * @var array
+ */
+ protected $_loaders = array();
+
+ /**
+ * Allowed form methods
+ * @var array
+ */
+ protected $_methods = array('delete', 'get', 'post', 'put');
+
+ /**
+ * Order in which to display and iterate elements
+ * @var array
+ */
+ protected $_order = array();
+
+ /**
+ * Whether internal order has been updated or not
+ * @var bool
+ */
+ protected $_orderUpdated = false;
+
+ /**
+ * Sub form prefix paths
+ * @var array
+ */
+ protected $_subFormPrefixPaths = array();
+
+ /**
+ * Sub forms
+ * @var array
+ */
+ protected $_subForms = array();
+
+ /**
+ * @var Zend_Translate
+ */
+ protected $_translator;
+
+ /**
+ * Global default translation adapter
+ * @var Zend_Translate
+ */
+ protected static $_translatorDefault;
+
+ /**
+ * is the translator disabled?
+ * @var bool
+ */
+ protected $_translatorDisabled = false;
+
+ /**
+ * @var Zend_View_Interface
+ */
+ protected $_view;
+
+ /**
+ * @var bool
+ */
+ protected $_isRendered = false;
+
+ /**
+ * Constructor
+ *
+ * Registers form view helper as decorator
+ *
+ * @param mixed $options
+ */
+ public function __construct($options = null)
+ {
+ if (is_array($options)) {
+ $this->setOptions($options);
+ } elseif ($options instanceof Zend_Config) {
+ $this->setConfig($options);
+ }
+
+ // Extensions...
+ $this->init();
+
+ $this->loadDefaultDecorators();
+ }
+
+ /**
+ * Clone form object and all children
+ *
+ * @return void
+ */
+ public function __clone()
+ {
+ $elements = array();
+ foreach ($this->getElements() as $name => $element) {
+ $elements[] = clone $element;
+ }
+ $this->setElements($elements);
+
+ $subForms = array();
+ foreach ($this->getSubForms() as $name => $subForm) {
+ $subForms[$name] = clone $subForm;
+ }
+ $this->setSubForms($subForms);
+
+ $displayGroups = array();
+ foreach ($this->_displayGroups as $group) {
+ /** @var Zend_Form_DisplayGroup $clone */
+ $clone = clone $group;
+ $elements = array();
+ foreach ($clone->getElements() as $name => $e) {
+ $elements[] = $this->getElement($name);
+ }
+ $clone->setElements($elements);
+ $displayGroups[] = $clone;
+ }
+ $this->setDisplayGroups($displayGroups);
+ }
+
+ /**
+ * Reset values of form
+ *
+ * @return Zend_Form
+ */
+ public function reset()
+ {
+ /** @var Zend_Form_Element $element */
+ foreach ($this->getElements() as $element) {
+ $element->setValue(null);
+ }
+ /** @var Zend_Form_SubForm $subForm */
+ foreach ($this->getSubForms() as $subForm) {
+ $subForm->reset();
+ }
+
+ return $this;
+ }
+
+ /**
+ * Initialize form (used by extending classes)
+ *
+ * @return void
+ */
+ public function init()
+ {
+ }
+
+ /**
+ * Set form state from options array
+ *
+ * @param array $options
+ * @return Zend_Form
+ */
+ public function setOptions(array $options)
+ {
+ if (isset($options['prefixPath'])) {
+ $this->addPrefixPaths($options['prefixPath']);
+ unset($options['prefixPath']);
+ }
+
+ if (isset($options['elementPrefixPath'])) {
+ $this->addElementPrefixPaths($options['elementPrefixPath']);
+ unset($options['elementPrefixPath']);
+ }
+
+ if (isset($options['displayGroupPrefixPath'])) {
+ $this->addDisplayGroupPrefixPaths($options['displayGroupPrefixPath']);
+ unset($options['displayGroupPrefixPath']);
+ }
+
+ if (isset($options['elementDecorators'])) {
+ $this->_elementDecorators = $options['elementDecorators'];
+ unset($options['elementDecorators']);
+ }
+
+ if (isset($options['elements'])) {
+ $this->setElements($options['elements']);
+ unset($options['elements']);
+ }
+
+ if (isset($options['defaultDisplayGroupClass'])) {
+ $this->setDefaultDisplayGroupClass($options['defaultDisplayGroupClass']);
+ unset($options['defaultDisplayGroupClass']);
+ }
+
+ if (isset($options['displayGroupDecorators'])) {
+ $displayGroupDecorators = $options['displayGroupDecorators'];
+ unset($options['displayGroupDecorators']);
+ }
+
+ if (isset($options['elementsBelongTo'])) {
+ $elementsBelongTo = $options['elementsBelongTo'];
+ unset($options['elementsBelongTo']);
+ }
+
+ if (isset($options['attribs'])) {
+ $this->addAttribs($options['attribs']);
+ unset($options['attribs']);
+ }
+
+ if (isset($options['subForms'])) {
+ $this->addSubForms($options['subForms']);
+ unset($options['subForms']);
+ }
+
+ $forbidden = array(
+ 'Options', 'Config', 'PluginLoader', 'SubForms', 'Translator',
+ 'Attrib', 'Default',
+ );
+
+ foreach ($options as $key => $value) {
+ $normalized = ucfirst($key);
+ if (in_array($normalized, $forbidden)) {
+ continue;
+ }
+
+ $method = 'set' . $normalized;
+ if (method_exists($this, $method)) {
+ if($normalized == 'View' && !($value instanceof Zend_View_Interface)) {
+ continue;
+ }
+ $this->$method($value);
+ } else {
+ $this->setAttrib($key, $value);
+ }
+ }
+
+ if (isset($displayGroupDecorators)) {
+ $this->setDisplayGroupDecorators($displayGroupDecorators);
+ }
+
+ if (isset($elementsBelongTo)) {
+ $this->setElementsBelongTo($elementsBelongTo);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set form state from config object
+ *
+ * @param Zend_Config $config
+ * @return Zend_Form
+ */
+ public function setConfig(Zend_Config $config)
+ {
+ return $this->setOptions($config->toArray());
+ }
+
+
+ // Loaders
+
+ /**
+ * Set plugin loaders for use with decorators and elements
+ *
+ * @param Zend_Loader_PluginLoader_Interface $loader
+ * @param string $type 'decorator' or 'element'
+ * @return Zend_Form
+ * @throws Zend_Form_Exception on invalid type
+ */
+ public function setPluginLoader(Zend_Loader_PluginLoader_Interface $loader, $type = null)
+ {
+ $type = strtoupper($type);
+ switch ($type) {
+ case self::DECORATOR:
+ case self::ELEMENT:
+ $this->_loaders[$type] = $loader;
+ return $this;
+ default:
+ throw new Zend_Form_Exception(sprintf('Invalid type "%s" provided to setPluginLoader()', $type));
+ }
+ }
+
+ /**
+ * Retrieve plugin loader for given type
+ *
+ * $type may be one of:
+ * - decorator
+ * - element
+ *
+ * If a plugin loader does not exist for the given type, defaults are
+ * created.
+ *
+ * @param string $type
+ * @return Zend_Loader_PluginLoader_Interface
+ * @throws Zend_Form_Exception
+ */
+ public function getPluginLoader($type = null)
+ {
+ $type = strtoupper($type);
+ if (!isset($this->_loaders[$type])) {
+ switch ($type) {
+ case self::DECORATOR:
+ $prefixSegment = 'Form_Decorator';
+ $pathSegment = 'Form/Decorator';
+ break;
+ case self::ELEMENT:
+ $prefixSegment = 'Form_Element';
+ $pathSegment = 'Form/Element';
+ break;
+ default:
+ throw new Zend_Form_Exception(sprintf('Invalid type "%s" provided to getPluginLoader()', $type));
+ }
+
+ $this->_loaders[$type] = new Zend_Loader_PluginLoader(
+ array('Zend_' . $prefixSegment . '_' => 'Zend/' . $pathSegment . '/')
+ );
+ }
+
+ return $this->_loaders[$type];
+ }
+
+ /**
+ * Add prefix path for plugin loader
+ *
+ * If no $type specified, assumes it is a base path for both filters and
+ * validators, and sets each according to the following rules:
+ * - decorators: $prefix = $prefix . '_Decorator'
+ * - elements: $prefix = $prefix . '_Element'
+ *
+ * Otherwise, the path prefix is set on the appropriate plugin loader.
+ *
+ * If $type is 'decorator', sets the path in the decorator plugin loader
+ * for all elements. Additionally, if no $type is provided,
+ * the prefix and path is added to both decorator and element
+ * plugin loader with following settings:
+ * $prefix . '_Decorator', $path . '/Decorator/'
+ * $prefix . '_Element', $path . '/Element/'
+ *
+ * @param string $prefix
+ * @param string $path
+ * @param string $type
+ * @return Zend_Form
+ * @throws Zend_Form_Exception for invalid type
+ */
+ public function addPrefixPath($prefix, $path, $type = null)
+ {
+ $type = strtoupper($type);
+ switch ($type) {
+ case self::DECORATOR:
+ case self::ELEMENT:
+ $loader = $this->getPluginLoader($type);
+ $loader->addPrefixPath($prefix, $path);
+ return $this;
+ case null:
+ $nsSeparator = (false !== strpos($prefix, '\\'))?'\\':'_';
+ $prefix = rtrim($prefix, $nsSeparator);
+ $path = rtrim($path, DIRECTORY_SEPARATOR);
+ foreach (array(self::DECORATOR, self::ELEMENT) as $type) {
+ $cType = ucfirst(strtolower($type));
+ $pluginPath = $path . DIRECTORY_SEPARATOR . $cType . DIRECTORY_SEPARATOR;
+ $pluginPrefix = $prefix . $nsSeparator . $cType;
+ $loader = $this->getPluginLoader($type);
+ $loader->addPrefixPath($pluginPrefix, $pluginPath);
+ }
+ return $this;
+ default:
+ throw new Zend_Form_Exception(sprintf('Invalid type "%s" provided to getPluginLoader()', $type));
+ }
+ }
+
+ /**
+ * Add many prefix paths at once
+ *
+ * @param array $spec
+ * @return Zend_Form
+ */
+ public function addPrefixPaths(array $spec)
+ {
+ if (isset($spec['prefix']) && isset($spec['path'])) {
+ return $this->addPrefixPath($spec['prefix'], $spec['path']);
+ }
+ foreach ($spec as $type => $paths) {
+ if (is_numeric($type) && is_array($paths)) {
+ $type = null;
+ if (isset($paths['prefix']) && isset($paths['path'])) {
+ if (isset($paths['type'])) {
+ $type = $paths['type'];
+ }
+ $this->addPrefixPath($paths['prefix'], $paths['path'], $type);
+ }
+ } elseif (!is_numeric($type)) {
+ if (!isset($paths['prefix']) || !isset($paths['path'])) {
+ continue;
+ }
+ $this->addPrefixPath($paths['prefix'], $paths['path'], $type);
+ }
+ }
+ return $this;
+ }
+
+ /**
+ * Add prefix path for all elements
+ *
+ * @param string $prefix
+ * @param string $path
+ * @param string $type
+ * @return Zend_Form
+ */
+ public function addElementPrefixPath($prefix, $path, $type = null)
+ {
+ $this->_elementPrefixPaths[] = array(
+ 'prefix' => $prefix,
+ 'path' => $path,
+ 'type' => $type,
+ );
+
+ /** @var Zend_Form_Element $element */
+ foreach ($this->getElements() as $element) {
+ $element->addPrefixPath($prefix, $path, $type);
+ }
+
+ /** @var Zend_Form_SubForm $subForm */
+ foreach ($this->getSubForms() as $subForm) {
+ $subForm->addElementPrefixPath($prefix, $path, $type);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Add prefix paths for all elements
+ *
+ * @param array $spec
+ * @return Zend_Form
+ */
+ public function addElementPrefixPaths(array $spec)
+ {
+ $this->_elementPrefixPaths = $this->_elementPrefixPaths + $spec;
+
+ /** @var Zend_Form_Element $element */
+ foreach ($this->getElements() as $element) {
+ $element->addPrefixPaths($spec);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Add prefix path for all display groups
+ *
+ * @param string $prefix
+ * @param string $path
+ * @return Zend_Form
+ */
+ public function addDisplayGroupPrefixPath($prefix, $path)
+ {
+ $this->_displayGroupPrefixPaths[] = array(
+ 'prefix' => $prefix,
+ 'path' => $path,
+ );
+
+ /** @var Zend_Form_DisplayGroup $group */
+ foreach ($this->getDisplayGroups() as $group) {
+ $group->addPrefixPath($prefix, $path);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Add multiple display group prefix paths at once
+ *
+ * @param array $spec
+ * @return Zend_Form
+ */
+ public function addDisplayGroupPrefixPaths(array $spec)
+ {
+ foreach ($spec as $key => $value) {
+ if (is_string($value) && !is_numeric($key)) {
+ $this->addDisplayGroupPrefixPath($key, $value);
+ continue;
+ }
+
+ if (is_string($value) && is_numeric($key)) {
+ continue;
+ }
+
+ if (is_array($value)) {
+ $count = count($value);
+ if (array_keys($value) === range(0, $count - 1)) {
+ if ($count < 2) {
+ continue;
+ }
+ $prefix = array_shift($value);
+ $path = array_shift($value);
+ $this->addDisplayGroupPrefixPath($prefix, $path);
+ continue;
+ }
+ if (array_key_exists('prefix', $value) && array_key_exists('path', $value)) {
+ $this->addDisplayGroupPrefixPath($value['prefix'], $value['path']);
+ }
+ }
+ }
+ return $this;
+ }
+
+ // Form metadata:
+
+ /**
+ * Set form attribute
+ *
+ * @param string $key
+ * @param mixed $value
+ * @return Zend_Form
+ */
+ public function setAttrib($key, $value)
+ {
+ $key = (string) $key;
+ $this->_attribs[$key] = $value;
+ return $this;
+ }
+
+ /**
+ * Add multiple form attributes at once
+ *
+ * @param array $attribs
+ * @return Zend_Form
+ */
+ public function addAttribs(array $attribs)
+ {
+ foreach ($attribs as $key => $value) {
+ $this->setAttrib($key, $value);
+ }
+ return $this;
+ }
+
+ /**
+ * Set multiple form attributes at once
+ *
+ * Overwrites any previously set attributes.
+ *
+ * @param array $attribs
+ * @return Zend_Form
+ */
+ public function setAttribs(array $attribs)
+ {
+ $this->clearAttribs();
+ return $this->addAttribs($attribs);
+ }
+
+ /**
+ * Retrieve a single form attribute
+ *
+ * @param string $key
+ * @return mixed
+ */
+ public function getAttrib($key)
+ {
+ $key = (string) $key;
+ if (!isset($this->_attribs[$key])) {
+ return null;
+ }
+
+ return $this->_attribs[$key];
+ }
+
+ /**
+ * Retrieve all form attributes/metadata
+ *
+ * @return array
+ */
+ public function getAttribs()
+ {
+ return $this->_attribs;
+ }
+
+ /**
+ * Remove attribute
+ *
+ * @param string $key
+ * @return bool
+ */
+ public function removeAttrib($key)
+ {
+ if (isset($this->_attribs[$key])) {
+ unset($this->_attribs[$key]);
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Clear all form attributes
+ *
+ * @return Zend_Form
+ */
+ public function clearAttribs()
+ {
+ $this->_attribs = array();
+ return $this;
+ }
+
+ /**
+ * Set form action
+ *
+ * @param string $action
+ * @return Zend_Form
+ */
+ public function setAction($action)
+ {
+ return $this->setAttrib('action', (string) $action);
+ }
+
+ /**
+ * Get form action
+ *
+ * Sets default to '' if not set.
+ *
+ * @return string
+ */
+ public function getAction()
+ {
+ $action = $this->getAttrib('action');
+ if (null === $action) {
+ $action = '';
+ $this->setAction($action);
+ }
+ return $action;
+ }
+
+ /**
+ * Set form method
+ *
+ * Only values in {@link $_methods()} allowed
+ *
+ * @param string $method
+ * @return Zend_Form
+ * @throws Zend_Form_Exception
+ */
+ public function setMethod($method)
+ {
+ $method = strtolower($method);
+ if (!in_array($method, $this->_methods)) {
+ throw new Zend_Form_Exception(sprintf('"%s" is an invalid form method', $method));
+ }
+ $this->setAttrib('method', $method);
+ return $this;
+ }
+
+ /**
+ * Retrieve form method
+ *
+ * @return string
+ */
+ public function getMethod()
+ {
+ if (null === ($method = $this->getAttrib('method'))) {
+ $method = self::METHOD_POST;
+ $this->setAttrib('method', $method);
+ }
+ return strtolower($method);
+ }
+
+ /**
+ * Set encoding type
+ *
+ * @param string $value
+ * @return Zend_Form
+ */
+ public function setEnctype($value)
+ {
+ $this->setAttrib('enctype', $value);
+ return $this;
+ }
+
+ /**
+ * Get encoding type
+ *
+ * @return string
+ */
+ public function getEnctype()
+ {
+ if (null === ($enctype = $this->getAttrib('enctype'))) {
+ $enctype = self::ENCTYPE_URLENCODED;
+ $this->setAttrib('enctype', $enctype);
+ }
+ return $this->getAttrib('enctype');
+ }
+
+ /**
+ * Filter a name to only allow valid variable characters
+ *
+ * @param string $value
+ * @param bool $allowBrackets
+ * @return string
+ */
+ public function filterName($value, $allowBrackets = false)
+ {
+ $charset = '^a-zA-Z0-9_\x7f-\xff';
+ if ($allowBrackets) {
+ $charset .= '\[\]';
+ }
+ return preg_replace('/[' . $charset . ']/', '', (string) $value);
+ }
+
+ /**
+ * Set form name
+ *
+ * @param string $name
+ * @return Zend_Form
+ * @throws Zend_Form_Exception
+ */
+ public function setName($name)
+ {
+ $name = $this->filterName($name);
+ if ('' === (string)$name) {
+ throw new Zend_Form_Exception('Invalid name provided; must contain only valid variable characters and be non-empty');
+ }
+
+ return $this->setAttrib('name', $name);
+ }
+
+ /**
+ * Get name attribute
+ *
+ * @return null|string
+ */
+ public function getName()
+ {
+ return $this->getAttrib('name');
+ }
+
+ /**
+ * Get fully qualified name
+ *
+ * Places name as subitem of array and/or appends brackets.
+ *
+ * @return string
+ */
+ public function getFullyQualifiedName()
+ {
+ return $this->getName();
+ }
+
+ /**
+ * Get element id
+ *
+ * @return string
+ */
+ public function getId()
+ {
+ if (null !== ($id = $this->getAttrib('id'))) {
+ return $id;
+ }
+
+ $id = $this->getFullyQualifiedName();
+
+ // Bail early if no array notation detected
+ if (!strstr($id, '[')) {
+ return $id;
+ }
+
+ // Strip array notation
+ if ('[]' == substr($id, -2)) {
+ $id = substr($id, 0, strlen($id) - 2);
+ }
+ $id = str_replace('][', '-', $id);
+ $id = str_replace(array(']', '['), '-', $id);
+ $id = trim($id, '-');
+
+ return $id;
+ }
+
+ /**
+ * Set form legend
+ *
+ * @param string $value
+ * @return Zend_Form
+ */
+ public function setLegend($value)
+ {
+ $this->_legend = (string) $value;
+ return $this;
+ }
+
+ /**
+ * Get form legend
+ *
+ * @return string
+ */
+ public function getLegend()
+ {
+ return $this->_legend;
+ }
+
+ /**
+ * Set form description
+ *
+ * @param string $value
+ * @return Zend_Form
+ */
+ public function setDescription($value)
+ {
+ $this->_description = (string) $value;
+ return $this;
+ }
+
+ /**
+ * Retrieve form description
+ *
+ * @return string
+ */
+ public function getDescription()
+ {
+ return $this->_description;
+ }
+
+ /**
+ * Set form order
+ *
+ * @param int $index
+ * @return Zend_Form
+ */
+ public function setOrder($index)
+ {
+ $this->_formOrder = (int) $index;
+ return $this;
+ }
+
+ /**
+ * Get form order
+ *
+ * @return int|null
+ */
+ public function getOrder()
+ {
+ return $this->_formOrder;
+ }
+
+ /**
+ * When calling renderFormElements or render this method
+ * is used to set $_isRendered member to prevent repeatedly
+ * merging belongsTo setting
+ */
+ protected function _setIsRendered()
+ {
+ $this->_isRendered = true;
+ return $this;
+ }
+
+ /**
+ * Get the value of $_isRendered member
+ */
+ protected function _getIsRendered()
+ {
+ return (bool)$this->_isRendered;
+ }
+
+ // Element interaction:
+
+ /**
+ * Add a new element
+ *
+ * $element may be either a string element type, or an object of type
+ * Zend_Form_Element. If a string element type is provided, $name must be
+ * provided, and $options may be optionally provided for configuring the
+ * element.
+ *
+ * If a Zend_Form_Element is provided, $name may be optionally provided,
+ * and any provided $options will be ignored.
+ *
+ * @param string|Zend_Form_Element $element
+ * @param string $name
+ * @param array|Zend_Config $options
+ * @throws Zend_Form_Exception on invalid element
+ * @return Zend_Form
+ */
+ public function addElement($element, $name = null, $options = null)
+ {
+ if (is_string($element)) {
+ if (null === $name) {
+ throw new Zend_Form_Exception(
+ 'Elements specified by string must have an accompanying name'
+ );
+ }
+
+ $this->_elements[$name] = $this->createElement($element, $name, $options);
+ } elseif ($element instanceof Zend_Form_Element) {
+ $prefixPaths = array();
+ $prefixPaths['decorator'] = $this->getPluginLoader('decorator')->getPaths();
+ if (!empty($this->_elementPrefixPaths)) {
+ $prefixPaths = array_merge($prefixPaths, $this->_elementPrefixPaths);
+ }
+
+ if (is_array($this->_elementDecorators)
+ && 0 == count($element->getDecorators())
+ ) {
+ $element->setDecorators($this->_elementDecorators);
+ }
+
+ if (null === $name) {
+ $name = $element->getName();
+ }
+
+ $this->_elements[$name] = $element;
+ $this->_elements[$name]->addPrefixPaths($prefixPaths);
+ } else {
+ throw new Zend_Form_Exception(
+ 'Element must be specified by string or Zend_Form_Element instance'
+ );
+ }
+
+ $this->_order[$name] = $this->_elements[$name]->getOrder();
+ $this->_orderUpdated = true;
+ $this->_setElementsBelongTo($name);
+
+ return $this;
+ }
+
+ /**
+ * Create an element
+ *
+ * Acts as a factory for creating elements. Elements created with this
+ * method will not be attached to the form, but will contain element
+ * settings as specified in the form object (including plugin loader
+ * prefix paths, default decorators, etc.).
+ *
+ * @param string $type
+ * @param string $name
+ * @param array|Zend_Config $options
+ * @throws Zend_Form_Exception
+ * @return Zend_Form_Element
+ */
+ public function createElement($type, $name, $options = null)
+ {
+ if (!is_string($type)) {
+ throw new Zend_Form_Exception('Element type must be a string indicating type');
+ }
+
+ if (!is_string($name)) {
+ throw new Zend_Form_Exception('Element name must be a string');
+ }
+
+ $prefixPaths = array();
+ $prefixPaths['decorator'] = $this->getPluginLoader('decorator')->getPaths();
+ if (!empty($this->_elementPrefixPaths)) {
+ $prefixPaths = array_merge($prefixPaths, $this->_elementPrefixPaths);
+ }
+
+ if ($options instanceof Zend_Config) {
+ $options = $options->toArray();
+ }
+
+ if ((null === $options) || !is_array($options)) {
+ $options = array('prefixPath' => $prefixPaths);
+
+ if (is_array($this->_elementDecorators)) {
+ $options['decorators'] = $this->_elementDecorators;
+ }
+ } elseif (is_array($options)) {
+ if (array_key_exists('prefixPath', $options)) {
+ $options['prefixPath'] = array_merge($prefixPaths, $options['prefixPath']);
+ } else {
+ $options['prefixPath'] = $prefixPaths;
+ }
+
+ if (is_array($this->_elementDecorators)
+ && !array_key_exists('decorators', $options)
+ ) {
+ $options['decorators'] = $this->_elementDecorators;
+ }
+ }
+
+ $class = $this->getPluginLoader(self::ELEMENT)->load($type);
+ $element = new $class($name, $options);
+
+ return $element;
+ }
+
+ /**
+ * Add multiple elements at once
+ *
+ * @param array $elements
+ * @return Zend_Form
+ */
+ public function addElements(array $elements)
+ {
+ foreach ($elements as $key => $spec) {
+ $name = null;
+ if (!is_numeric($key)) {
+ $name = $key;
+ }
+
+ if (is_string($spec) || ($spec instanceof Zend_Form_Element)) {
+ $this->addElement($spec, $name);
+ continue;
+ }
+
+ if (is_array($spec)) {
+ $argc = count($spec);
+ $options = array();
+ if (isset($spec['type'])) {
+ $type = $spec['type'];
+ if (isset($spec['name'])) {
+ $name = $spec['name'];
+ }
+ if (isset($spec['options'])) {
+ $options = $spec['options'];
+ }
+ $this->addElement($type, $name, $options);
+ } else {
+ switch ($argc) {
+ case 0:
+ continue 2;
+ case (1 <= $argc):
+ $type = array_shift($spec);
+ case (2 <= $argc):
+ if (null === $name) {
+ $name = array_shift($spec);
+ } else {
+ $options = array_shift($spec);
+ }
+ case (3 <= $argc):
+ if (empty($options)) {
+ $options = array_shift($spec);
+ }
+ default:
+ $this->addElement($type, $name, $options);
+ }
+ }
+ }
+ }
+ return $this;
+ }
+
+ /**
+ * Set form elements (overwrites existing elements)
+ *
+ * @param array $elements
+ * @return Zend_Form
+ */
+ public function setElements(array $elements)
+ {
+ $this->clearElements();
+ return $this->addElements($elements);
+ }
+
+ /**
+ * Retrieve a single element
+ *
+ * @param string $name
+ * @return Zend_Form_Element|null
+ */
+ public function getElement($name)
+ {
+ if (array_key_exists($name, $this->_elements)) {
+ return $this->_elements[$name];
+ }
+ return null;
+ }
+
+ /**
+ * Retrieve all elements
+ *
+ * @return array
+ */
+ public function getElements()
+ {
+ return $this->_elements;
+ }
+
+ /**
+ * Remove element
+ *
+ * @param string $name
+ * @return boolean
+ */
+ public function removeElement($name)
+ {
+ $name = (string) $name;
+ if (isset($this->_elements[$name])) {
+ unset($this->_elements[$name]);
+ if (array_key_exists($name, $this->_order)) {
+ unset($this->_order[$name]);
+ $this->_orderUpdated = true;
+ } else {
+ /** @var Zend_Form_DisplayGroup $group */
+ foreach ($this->_displayGroups as $group) {
+ if (null !== $group->getElement($name)) {
+ $group->removeElement($name);
+ }
+ }
+ }
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Remove all form elements
+ *
+ * @return Zend_Form
+ */
+ public function clearElements()
+ {
+ foreach (array_keys($this->_elements) as $key) {
+ if (array_key_exists($key, $this->_order)) {
+ unset($this->_order[$key]);
+ }
+ }
+ $this->_elements = array();
+ $this->_orderUpdated = true;
+ return $this;
+ }
+
+ /**
+ * Set default values for elements
+ *
+ * Sets values for all elements specified in the array of $defaults.
+ *
+ * @param array $defaults
+ * @return Zend_Form
+ */
+ public function setDefaults(array $defaults)
+ {
+ $eBelongTo = null;
+
+ if ($this->isArray()) {
+ $eBelongTo = $this->getElementsBelongTo();
+ $defaults = $this->_dissolveArrayValue($defaults, $eBelongTo);
+ }
+ /** @var Zend_Form_Element $element */
+ foreach ($this->getElements() as $name => $element) {
+ $check = $defaults;
+ if (($belongsTo = $element->getBelongsTo()) !== $eBelongTo) {
+ $check = $this->_dissolveArrayValue($defaults, $belongsTo);
+ }
+ if (array_key_exists($name, (array)$check)) {
+ $this->setDefault($name, $check[$name]);
+ $defaults = $this->_dissolveArrayUnsetKey($defaults, $belongsTo, $name);
+ }
+ }
+ /** @var Zend_Form_SubForm $form */
+ foreach ($this->getSubForms() as $name => $form) {
+ if (!$form->isArray() && array_key_exists($name, $defaults)) {
+ $form->setDefaults($defaults[$name]);
+ } else {
+ $form->setDefaults($defaults);
+ }
+ }
+ return $this;
+ }
+
+ /**
+ * Set default value for an element
+ *
+ * @param string $name
+ * @param mixed $value
+ * @return Zend_Form
+ */
+ public function setDefault($name, $value)
+ {
+ $name = (string) $name;
+ if ($element = $this->getElement($name)) {
+ $element->setValue($value);
+ } else {
+ if (is_scalar($value)) {
+ /** @var Zend_Form_SubForm $subForm */
+ foreach ($this->getSubForms() as $subForm) {
+ $subForm->setDefault($name, $value);
+ }
+ } elseif (is_array($value) && ($subForm = $this->getSubForm($name))) {
+ $subForm->setDefaults($value);
+ }
+ }
+ return $this;
+ }
+
+ /**
+ * Retrieve value for single element
+ *
+ * @param string $name
+ * @return mixed
+ */
+ public function getValue($name)
+ {
+ if ($element = $this->getElement($name)) {
+ return $element->getValue();
+ }
+
+ if ($subForm = $this->getSubForm($name)) {
+ return $subForm->getValues(true);
+ }
+
+ /** @var Zend_Form_SubForm $subForm */
+ foreach ($this->getSubForms() as $subForm) {
+ if ($name == $subForm->getElementsBelongTo()) {
+ return $subForm->getValues(true);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Retrieve all form element values
+ *
+ * @param bool $suppressArrayNotation
+ * @return array
+ */
+ public function getValues($suppressArrayNotation = false)
+ {
+ $values = array();
+ $eBelongTo = null;
+
+ if ($this->isArray()) {
+ $eBelongTo = $this->getElementsBelongTo();
+ }
+ /** @var Zend_Form_Element $element */
+ foreach ($this->getElements() as $key => $element) {
+ if (!$element->getIgnore()) {
+ $merge = array();
+ if (($belongsTo = $element->getBelongsTo()) !== $eBelongTo) {
+ if ('' !== (string)$belongsTo) {
+ $key = $belongsTo . '[' . $key . ']';
+ }
+ }
+ $merge = $this->_attachToArray($element->getValue(), $key);
+ $values = $this->_array_replace_recursive($values, $merge);
+ }
+ }
+ /** @var Zend_Form_SubForm $subForm */
+ foreach ($this->getSubForms() as $key => $subForm) {
+ $merge = array();
+ if (!$subForm->isArray()) {
+ $merge[$key] = $subForm->getValues();
+ } else {
+ $merge = $this->_attachToArray($subForm->getValues(true),
+ $subForm->getElementsBelongTo());
+ }
+ $values = $this->_array_replace_recursive($values, $merge);
+ }
+
+ if (!$suppressArrayNotation &&
+ $this->isArray() &&
+ !$this->_getIsRendered()) {
+ $values = $this->_attachToArray($values, $this->getElementsBelongTo());
+ }
+
+ return $values;
+ }
+
+ /**
+ * Returns only the valid values from the given form input.
+ *
+ * For models that can be saved in a partially valid state, for example when following the builder,
+ * prototype or state patterns it is particularly interessting to retrieve all the current valid
+ * values to persist them.
+ *
+ * @param array $data
+ * @param bool $suppressArrayNotation
+ * @return array
+ */
+ public function getValidValues($data, $suppressArrayNotation = false)
+ {
+ $values = array();
+ $eBelongTo = null;
+
+ if ($this->isArray()) {
+ $eBelongTo = $this->getElementsBelongTo();
+ $data = $this->_dissolveArrayValue($data, $eBelongTo);
+ }
+ $context = $data;
+ /** @var Zend_Form_Element $element */
+ foreach ($this->getElements() as $key => $element) {
+ if (!$element->getIgnore()) {
+ $check = $data;
+ if (($belongsTo = $element->getBelongsTo()) !== $eBelongTo) {
+ $check = $this->_dissolveArrayValue($data, $belongsTo);
+ }
+ if (isset($check[$key])) {
+ if($element->isValid($check[$key], $context)) {
+ $merge = array();
+ if ($belongsTo !== $eBelongTo && '' !== (string)$belongsTo) {
+ $key = $belongsTo . '[' . $key . ']';
+ }
+ $merge = $this->_attachToArray($element->getValue(), $key);
+ $values = $this->_array_replace_recursive($values, $merge);
+ }
+ $data = $this->_dissolveArrayUnsetKey($data, $belongsTo, $key);
+ }
+ }
+ }
+ /** @var Zend_Form_SubForm $form */
+ foreach ($this->getSubForms() as $key => $form) {
+ $merge = array();
+ if (isset($data[$key]) && !$form->isArray()) {
+ $tmp = $form->getValidValues($data[$key]);
+ if (!empty($tmp)) {
+ $merge[$key] = $tmp;
+ }
+ } else {
+ $tmp = $form->getValidValues($data, true);
+ if (!empty($tmp)) {
+ $merge = $this->_attachToArray($tmp, $form->getElementsBelongTo());
+ }
+ }
+ $values = $this->_array_replace_recursive($values, $merge);
+ }
+ if (!$suppressArrayNotation &&
+ $this->isArray() &&
+ !empty($values) &&
+ !$this->_getIsRendered()) {
+ $values = $this->_attachToArray($values, $this->getElementsBelongTo());
+ }
+
+ return $values;
+ }
+
+ /**
+ * Get unfiltered element value
+ *
+ * @param string $name
+ * @return mixed
+ */
+ public function getUnfilteredValue($name)
+ {
+ if ($element = $this->getElement($name)) {
+ return $element->getUnfilteredValue();
+ }
+ return null;
+ }
+
+ /**
+ * Retrieve all unfiltered element values
+ *
+ * @return array
+ */
+ public function getUnfilteredValues()
+ {
+ $values = array();
+ /** @var Zend_Form_Element $element */
+ foreach ($this->getElements() as $key => $element) {
+ $values[$key] = $element->getUnfilteredValue();
+ }
+
+ return $values;
+ }
+
+ /**
+ * Set all elements' filters
+ *
+ * @param array $filters
+ * @return Zend_Form
+ */
+ public function setElementFilters(array $filters)
+ {
+ /** @var Zend_Form_Element $element */
+ foreach ($this->getElements() as $element) {
+ $element->setFilters($filters);
+ }
+ return $this;
+ }
+
+ /**
+ * Set name of array elements belong to
+ *
+ * @param string $array
+ * @return Zend_Form
+ */
+ public function setElementsBelongTo($array)
+ {
+ $origName = $this->getElementsBelongTo();
+ $name = $this->filterName($array, true);
+ if ('' === $name) {
+ $name = null;
+ }
+ $this->_elementsBelongTo = $name;
+
+ if (null === $name) {
+ $this->setIsArray(false);
+ if (null !== $origName) {
+ $this->_setElementsBelongTo();
+ }
+ } else {
+ $this->setIsArray(true);
+ $this->_setElementsBelongTo();
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set array to which elements belong
+ *
+ * @param string $name Element name
+ * @return void
+ */
+ protected function _setElementsBelongTo($name = null)
+ {
+ $array = $this->getElementsBelongTo();
+
+ if (null === $array) {
+ return;
+ }
+
+ if (null === $name) {
+ /** @var Zend_Form_Element $element */
+ foreach ($this->getElements() as $element) {
+ $element->setBelongsTo($array);
+ }
+ } else {
+ if (null !== ($element = $this->getElement($name))) {
+ $element->setBelongsTo($array);
+ }
+ }
+ }
+
+ /**
+ * Get name of array elements belong to
+ *
+ * @return string|null
+ */
+ public function getElementsBelongTo()
+ {
+ if ((null === $this->_elementsBelongTo) && $this->isArray()) {
+ $name = $this->getName();
+ if ('' !== (string)$name) {
+ return $name;
+ }
+ }
+ return $this->_elementsBelongTo;
+ }
+
+ /**
+ * Set flag indicating elements belong to array
+ *
+ * @param bool $flag Value of flag
+ * @return Zend_Form
+ */
+ public function setIsArray($flag)
+ {
+ $this->_isArray = (bool) $flag;
+ return $this;
+ }
+
+ /**
+ * Get flag indicating if elements belong to an array
+ *
+ * @return bool
+ */
+ public function isArray()
+ {
+ return $this->_isArray;
+ }
+
+ // Element groups:
+
+ /**
+ * Add a form group/subform
+ *
+ * @param Zend_Form $form
+ * @param string $name
+ * @param int $order
+ * @return Zend_Form
+ */
+ public function addSubForm(Zend_Form $form, $name, $order = null)
+ {
+ $name = (string) $name;
+ /** @var Zend_Loader_PluginLoader $loader */
+ foreach ($this->_loaders as $type => $loader) {
+ $loaderPaths = $loader->getPaths();
+ foreach ($loaderPaths as $prefix => $paths) {
+ foreach ($paths as $path) {
+ $form->addPrefixPath($prefix, $path, $type);
+ }
+ }
+ }
+
+ if (!empty($this->_elementPrefixPaths)) {
+ foreach ($this->_elementPrefixPaths as $spec) {
+ list($prefix, $path, $type) = array_values($spec);
+ $form->addElementPrefixPath($prefix, $path, $type);
+ }
+ }
+
+ if (!empty($this->_displayGroupPrefixPaths)) {
+ foreach ($this->_displayGroupPrefixPaths as $spec) {
+ list($prefix, $path) = array_values($spec);
+ $form->addDisplayGroupPrefixPath($prefix, $path);
+ }
+ }
+
+ if (null !== $order) {
+ $form->setOrder($order);
+ }
+
+ if (($oldName = $form->getName()) &&
+ $oldName !== $name &&
+ $oldName === $form->getElementsBelongTo()) {
+ $form->setElementsBelongTo($name);
+ }
+
+ $form->setName($name);
+ $this->_subForms[$name] = $form;
+ $this->_order[$name] = $order;
+ $this->_orderUpdated = true;
+ return $this;
+ }
+
+ /**
+ * Add multiple form subForms/subforms at once
+ *
+ * @param array $subForms
+ * @return Zend_Form
+ */
+ public function addSubForms(array $subForms)
+ {
+ foreach ($subForms as $key => $spec) {
+ $name = (string) $key;
+ if ($spec instanceof Zend_Form) {
+ $this->addSubForm($spec, $name);
+ continue;
+ }
+
+ if (is_array($spec)) {
+ $argc = count($spec);
+ $order = null;
+ switch ($argc) {
+ case 0:
+ continue 2;
+ case (1 <= $argc):
+ $subForm = array_shift($spec);
+
+ if (!$subForm instanceof Zend_Form) {
+ $subForm = new Zend_Form_SubForm($subForm);
+ }
+ case (2 <= $argc):
+ $name = array_shift($spec);
+ case (3 <= $argc):
+ $order = array_shift($spec);
+ default:
+ $this->addSubForm($subForm, $name, $order);
+ }
+ }
+ }
+ return $this;
+ }
+
+ /**
+ * Set multiple form subForms/subforms (overwrites)
+ *
+ * @param array $subForms
+ * @return Zend_Form
+ */
+ public function setSubForms(array $subForms)
+ {
+ $this->clearSubForms();
+ return $this->addSubForms($subForms);
+ }
+
+ /**
+ * Retrieve a form subForm/subform
+ *
+ * @param string $name
+ * @return Zend_Form|null
+ */
+ public function getSubForm($name)
+ {
+ $name = (string) $name;
+ if (isset($this->_subForms[$name])) {
+ return $this->_subForms[$name];
+ }
+ return null;
+ }
+
+ /**
+ * Retrieve all form subForms/subforms
+ *
+ * @return array
+ */
+ public function getSubForms()
+ {
+ return $this->_subForms;
+ }
+
+ /**
+ * Remove form subForm/subform
+ *
+ * @param string $name
+ * @return boolean
+ */
+ public function removeSubForm($name)
+ {
+ $name = (string) $name;
+ if (array_key_exists($name, $this->_subForms)) {
+ unset($this->_subForms[$name]);
+ if (array_key_exists($name, $this->_order)) {
+ unset($this->_order[$name]);
+ $this->_orderUpdated = true;
+ }
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Remove all form subForms/subforms
+ *
+ * @return Zend_Form
+ */
+ public function clearSubForms()
+ {
+ foreach (array_keys($this->_subForms) as $key) {
+ if (array_key_exists($key, $this->_order)) {
+ unset($this->_order[$key]);
+ }
+ }
+ $this->_subForms = array();
+ $this->_orderUpdated = true;
+ return $this;
+ }
+
+
+ // Display groups:
+
+ /**
+ * Set default display group class
+ *
+ * @param string $class
+ * @return Zend_Form
+ */
+ public function setDefaultDisplayGroupClass($class)
+ {
+ $this->_defaultDisplayGroupClass = (string) $class;
+ return $this;
+ }
+
+ /**
+ * Retrieve default display group class
+ *
+ * @return string
+ */
+ public function getDefaultDisplayGroupClass()
+ {
+ return $this->_defaultDisplayGroupClass;
+ }
+
+ /**
+ * Add a display group
+ *
+ * Groups named elements for display purposes.
+ *
+ * If a referenced element does not yet exist in the form, it is omitted.
+ *
+ * @param array $elements
+ * @param string $name
+ * @param array|Zend_Config $options
+ * @return Zend_Form
+ * @throws Zend_Form_Exception if no valid elements provided
+ */
+ public function addDisplayGroup(array $elements, $name, $options = null)
+ {
+ $group = array();
+ foreach ($elements as $element) {
+ if($element instanceof Zend_Form_Element) {
+ $elementName = $element->getName();
+ if (!isset($this->_elements[$elementName])) {
+ $this->addElement($element);
+ }
+ $element = $elementName;
+ }
+
+ if (isset($this->_elements[$element])) {
+ $add = $this->getElement($element);
+ if (null !== $add) {
+ $group[] = $add;
+ }
+ }
+ }
+ if (empty($group)) {
+ throw new Zend_Form_Exception('No valid elements specified for display group');
+ }
+
+ $name = (string) $name;
+
+ if (is_array($options)) {
+ $options['form'] = $this;
+ $options['elements'] = $group;
+ } elseif ($options instanceof Zend_Config) {
+ $options = $options->toArray();
+ $options['form'] = $this;
+ $options['elements'] = $group;
+ } else {
+ $options = array(
+ 'form' => $this,
+ 'elements' => $group,
+ );
+ }
+
+ if (isset($options['displayGroupClass'])) {
+ $class = $options['displayGroupClass'];
+ unset($options['displayGroupClass']);
+ } else {
+ $class = $this->getDefaultDisplayGroupClass();
+ }
+
+ if (!class_exists($class)) {
+ Zend_Loader::loadClass($class);
+ }
+ $this->_displayGroups[$name] = new $class(
+ $name,
+ $this->getPluginLoader(self::DECORATOR),
+ $options
+ );
+
+ if (!empty($this->_displayGroupPrefixPaths)) {
+ $this->_displayGroups[$name]->addPrefixPaths($this->_displayGroupPrefixPaths);
+ }
+
+ $this->_order[$name] = $this->_displayGroups[$name]->getOrder();
+ $this->_orderUpdated = true;
+ return $this;
+ }
+
+ /**
+ * Add a display group object (used with cloning)
+ *
+ * @param Zend_Form_DisplayGroup $group
+ * @param string|null $name
+ * @throws Zend_Form_Exception
+ * @return Zend_Form
+ */
+ protected function _addDisplayGroupObject(Zend_Form_DisplayGroup $group, $name = null)
+ {
+ if (null === $name) {
+ $name = $group->getName();
+ if ('' === (string)$name) {
+ throw new Zend_Form_Exception('Invalid display group added; requires name');
+ }
+ }
+
+ $this->_displayGroups[$name] = $group;
+ $group->setForm($this);
+
+ if (!empty($this->_displayGroupPrefixPaths)) {
+ $this->_displayGroups[$name]->addPrefixPaths($this->_displayGroupPrefixPaths);
+ }
+
+ $this->_order[$name] = $this->_displayGroups[$name]->getOrder();
+ $this->_orderUpdated = true;
+ return $this;
+ }
+
+ /**
+ * Add multiple display groups at once
+ *
+ * @param array $groups
+ * @return Zend_Form
+ */
+ public function addDisplayGroups(array $groups)
+ {
+ foreach ($groups as $key => $spec) {
+ $name = null;
+ if (!is_numeric($key)) {
+ $name = $key;
+ }
+
+ if ($spec instanceof Zend_Form_DisplayGroup) {
+ $this->_addDisplayGroupObject($spec);
+ }
+
+ if (!is_array($spec) || empty($spec)) {
+ continue;
+ }
+
+ $argc = count($spec);
+ $options = array();
+
+ if (isset($spec['elements'])) {
+ $elements = $spec['elements'];
+ if (isset($spec['name'])) {
+ $name = $spec['name'];
+ }
+ if (isset($spec['options'])) {
+ $options = $spec['options'];
+ }
+ $this->addDisplayGroup($elements, $name, $options);
+ } else {
+ switch ($argc) {
+ case (1 <= $argc):
+ $elements = array_shift($spec);
+ if (!is_array($elements) && (null !== $name)) {
+ $elements = array_merge((array) $elements, $spec);
+ $this->addDisplayGroup($elements, $name);
+ break;
+ }
+ case (2 <= $argc):
+ if (null !== $name) {
+ $options = array_shift($spec);
+ $this->addDisplayGroup($elements, $name, $options);
+ break;
+ }
+ $name = array_shift($spec);
+ case (3 <= $argc):
+ $options = array_shift($spec);
+ default:
+ $this->addDisplayGroup($elements, $name, $options);
+ }
+ }
+ }
+ return $this;
+ }
+
+ /**
+ * Add multiple display groups (overwrites)
+ *
+ * @param array $groups
+ * @return Zend_Form
+ */
+ public function setDisplayGroups(array $groups)
+ {
+ return $this->clearDisplayGroups()
+ ->addDisplayGroups($groups);
+ }
+
+ /**
+ * Return a display group
+ *
+ * @param string $name
+ * @return Zend_Form_DisplayGroup|null
+ */
+ public function getDisplayGroup($name)
+ {
+ $name = (string) $name;
+ if (isset($this->_displayGroups[$name])) {
+ return $this->_displayGroups[$name];
+ }
+
+ return null;
+ }
+
+ /**
+ * Return all display groups
+ *
+ * @return array
+ */
+ public function getDisplayGroups()
+ {
+ return $this->_displayGroups;
+ }
+
+ /**
+ * Remove a display group by name
+ *
+ * @param string $name
+ * @return boolean
+ */
+ public function removeDisplayGroup($name)
+ {
+ $name = (string) $name;
+ if (array_key_exists($name, $this->_displayGroups)) {
+ /** @var Zend_Form_Element $element */
+ foreach ($this->_displayGroups[$name] as $key => $element) {
+ if (array_key_exists($key, $this->_elements)) {
+ $this->_order[$key] = $element->getOrder();
+ $this->_orderUpdated = true;
+ }
+ }
+ unset($this->_displayGroups[$name]);
+
+ if (array_key_exists($name, $this->_order)) {
+ unset($this->_order[$name]);
+ $this->_orderUpdated = true;
+ }
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Remove all display groups
+ *
+ * @return Zend_Form
+ */
+ public function clearDisplayGroups()
+ {
+ foreach ($this->_displayGroups as $key => $group) {
+ if (array_key_exists($key, $this->_order)) {
+ unset($this->_order[$key]);
+ }
+ /** @var Zend_Form_Element $element */
+ foreach ($group as $name => $element) {
+ if (isset($this->_elements[$name])) {
+ $this->_order[$name] = $element->getOrder();
+ }
+ $this->_order[$name] = $element->getOrder();
+ }
+ }
+ $this->_displayGroups = array();
+ $this->_orderUpdated = true;
+ return $this;
+ }
+
+
+ // Processing
+
+ /**
+ * Populate form
+ *
+ * Proxies to {@link setDefaults()}
+ *
+ * @param array $values
+ * @return Zend_Form
+ */
+ public function populate(array $values)
+ {
+ return $this->setDefaults($values);
+ }
+
+ /**
+ * Determine array key name from given value
+ *
+ * Given a value such as foo[bar][baz], returns the last element (in this case, 'baz').
+ *
+ * @param string $value
+ * @return string
+ */
+ protected function _getArrayName($value)
+ {
+ if (!is_string($value) || '' === $value) {
+ return $value;
+ }
+
+ if (!strstr($value, '[')) {
+ return $value;
+ }
+
+ $endPos = strlen($value) - 1;
+ if (']' != $value[$endPos]) {
+ return $value;
+ }
+
+ $start = strrpos($value, '[') + 1;
+ $name = substr($value, $start, $endPos - $start);
+ return $name;
+ }
+
+ /**
+ * Extract the value by walking the array using given array path.
+ *
+ * Given an array path such as foo[bar][baz], returns the value of the last
+ * element (in this case, 'baz').
+ *
+ * @param array $value Array to walk
+ * @param string $arrayPath Array notation path of the part to extract
+ * @return string
+ */
+ protected function _dissolveArrayValue($value, $arrayPath)
+ {
+ // As long as we have more levels
+ while ($arrayPos = strpos($arrayPath ?? '', '[')) {
+ // Get the next key in the path
+ $arrayKey = trim(substr($arrayPath, 0, $arrayPos), ']');
+
+ // Set the potentially final value or the next search point in the array
+ if (isset($value[$arrayKey])) {
+ $value = $value[$arrayKey];
+ }
+
+ // Set the next search point in the path
+ $arrayPath = trim(substr($arrayPath, $arrayPos + 1), ']');
+ }
+
+ if (isset($value[$arrayPath])) {
+ $value = $value[$arrayPath];
+ }
+
+ return $value;
+ }
+
+ /**
+ * Given an array, an optional arrayPath and a key this method
+ * dissolves the arrayPath and unsets the key within the array
+ * if it exists.
+ *
+ * @param array $array
+ * @param string|null $arrayPath
+ * @param string $key
+ * @return array
+ */
+ protected function _dissolveArrayUnsetKey($array, $arrayPath, $key)
+ {
+ $unset =& $array;
+ $path = trim(strtr((string)$arrayPath, array('[' => '/', ']' => '')), '/');
+ $segs = ('' !== $path) ? explode('/', $path) : array();
+
+ foreach ($segs as $seg) {
+ if (!array_key_exists($seg, (array)$unset)) {
+ return $array;
+ }
+ $unset =& $unset[$seg];
+ }
+ if (array_key_exists($key, (array)$unset)) {
+ unset($unset[$key]);
+ }
+ return $array;
+ }
+
+ /**
+ * Converts given arrayPath to an array and attaches given value at the end of it.
+ *
+ * @param mixed $value The value to attach
+ * @param string $arrayPath Given array path to convert and attach to.
+ * @return array
+ */
+ protected function _attachToArray($value, $arrayPath)
+ {
+ // As long as we have more levels
+ while ($arrayPos = strrpos($arrayPath, '[')) {
+ // Get the next key in the path
+ $arrayKey = trim(substr($arrayPath, $arrayPos + 1), ']');
+
+ // Attach
+ $value = array($arrayKey => $value);
+
+ // Set the next search point in the path
+ $arrayPath = trim(substr($arrayPath, 0, $arrayPos), ']');
+ }
+
+ $value = array($arrayPath => $value);
+
+ return $value;
+ }
+
+ /**
+ * Returns a one dimensional numerical indexed array with the
+ * Elements, SubForms and Elements from DisplayGroups as Values.
+ *
+ * Subitems are inserted based on their order Setting if set,
+ * otherwise they are appended, the resulting numerical index
+ * may differ from the order value.
+ *
+ * @access protected
+ * @return array
+ */
+ public function getElementsAndSubFormsOrdered()
+ {
+ $ordered = array();
+ foreach ($this->_order as $name => $order) {
+ $order = isset($order) ? $order : count($ordered);
+ if ($this->$name instanceof Zend_Form_Element ||
+ $this->$name instanceof Zend_Form) {
+ array_splice($ordered, $order, 0, array($this->$name));
+ } else if ($this->$name instanceof Zend_Form_DisplayGroup) {
+ $subordered = array();
+ /** @var Zend_Form_Element $element */
+ foreach ($this->$name->getElements() as $element) {
+ $suborder = $element->getOrder();
+ $suborder = (null !== $suborder) ? $suborder : count($subordered);
+ array_splice($subordered, $suborder, 0, array($element));
+ }
+ if (!empty($subordered)) {
+ array_splice($ordered, $order, 0, $subordered);
+ }
+ }
+ }
+ return $ordered;
+ }
+
+ /**
+ * This is a helper function until php 5.3 is widespreaded
+ *
+ * @param array $into
+ * @return array
+ */
+ protected function _array_replace_recursive(array $into)
+ {
+ $fromArrays = array_slice(func_get_args(),1);
+
+ foreach ($fromArrays as $from) {
+ foreach ($from as $key => $value) {
+ if (is_array($value)) {
+ if (!isset($into[$key])) {
+ $into[$key] = array();
+ }
+ $into[$key] = $this->_array_replace_recursive($into[$key], $from[$key]);
+ } else {
+ $into[$key] = $value;
+ }
+ }
+ }
+ return $into;
+ }
+
+ /**
+ * Validate the form
+ *
+ * @param array $data
+ * @throws Zend_Form_Exception
+ * @return bool
+ */
+ public function isValid($data)
+ {
+ if (!is_array($data)) {
+ throw new Zend_Form_Exception(__METHOD__ . ' expects an array');
+ }
+ $translator = $this->getTranslator();
+ $valid = true;
+ $eBelongTo = null;
+
+ if ($this->isArray()) {
+ $eBelongTo = $this->getElementsBelongTo();
+ $data = $this->_dissolveArrayValue($data, $eBelongTo);
+ }
+ $context = $data;
+ /** @var Zend_Form_Element $element */
+ foreach ($this->getElements() as $key => $element) {
+ if (null !== $translator && $this->hasTranslator()
+ && !$element->hasTranslator()) {
+ $element->setTranslator($translator);
+ }
+ $check = $data;
+ if (($belongsTo = $element->getBelongsTo()) !== $eBelongTo) {
+ $check = $this->_dissolveArrayValue($data, $belongsTo);
+ }
+ if (!isset($check[$key])) {
+ $valid = $element->isValid(null, $context) && $valid;
+ } else {
+ $valid = $element->isValid($check[$key], $context) && $valid;
+ $data = $this->_dissolveArrayUnsetKey($data, $belongsTo, $key);
+ }
+ }
+ /** @var Zend_Form_SubForm $form */
+ foreach ($this->getSubForms() as $key => $form) {
+ if (null !== $translator && $this->hasTranslator()
+ && !$form->hasTranslator()) {
+ $form->setTranslator($translator);
+ }
+ if (isset($data[$key]) && !$form->isArray()) {
+ $valid = $form->isValid($data[$key]) && $valid;
+ } else {
+ $valid = $form->isValid($data) && $valid;
+ }
+ }
+
+ $this->_errorsExist = !$valid;
+
+ // If manually flagged as an error, return invalid status
+ if ($this->_errorsForced) {
+ return false;
+ }
+
+ return $valid;
+ }
+
+ /**
+ * Validate a partial form
+ *
+ * Does not check for required flags.
+ *
+ * @param array $data
+ * @return boolean
+ */
+ public function isValidPartial(array $data)
+ {
+ $eBelongTo = null;
+
+ if ($this->isArray()) {
+ $eBelongTo = $this->getElementsBelongTo();
+ $data = $this->_dissolveArrayValue($data, $eBelongTo);
+ }
+
+ $translator = $this->getTranslator();
+ $valid = true;
+ $context = $data;
+
+ /** @var Zend_Form_Element $element */
+ foreach ($this->getElements() as $key => $element) {
+ $check = $data;
+ if (($belongsTo = $element->getBelongsTo()) !== $eBelongTo) {
+ $check = $this->_dissolveArrayValue($data, $belongsTo);
+ }
+ if (isset($check[$key])) {
+ if (null !== $translator && !$element->hasTranslator()) {
+ $element->setTranslator($translator);
+ }
+ $valid = $element->isValid($check[$key], $context) && $valid;
+ $data = $this->_dissolveArrayUnsetKey($data, $belongsTo, $key);
+ }
+ }
+ /** @var Zend_Form_SubForm $form */
+ foreach ($this->getSubForms() as $key => $form) {
+ if (null !== $translator && !$form->hasTranslator()) {
+ $form->setTranslator($translator);
+ }
+ if (isset($data[$key]) && !$form->isArray()) {
+ $valid = $form->isValidPartial($data[$key]) && $valid;
+ } else {
+ $valid = $form->isValidPartial($data) && $valid;
+ }
+ }
+
+ $this->_errorsExist = !$valid;
+ return $valid;
+ }
+
+ /**
+ * Process submitted AJAX data
+ *
+ * Checks if provided $data is valid, via {@link isValidPartial()}. If so,
+ * it returns JSON-encoded boolean true. If not, it returns JSON-encoded
+ * error messages (as returned by {@link getMessages()}).
+ *
+ * @param array $data
+ * @return string JSON-encoded boolean true or error messages
+ */
+ public function processAjax(array $data)
+ {
+ if ($this->isValidPartial($data)) {
+ return Zend_Json::encode(true);
+ }
+ $messages = $this->getMessages();
+ return Zend_Json::encode($messages);
+ }
+
+ /**
+ * Add a custom error message to return in the event of failed validation
+ *
+ * @param string $message
+ * @return Zend_Form
+ */
+ public function addErrorMessage($message)
+ {
+ $this->_errorMessages[] = (string) $message;
+ return $this;
+ }
+
+ /**
+ * Add multiple custom error messages to return in the event of failed validation
+ *
+ * @param array $messages
+ * @return Zend_Form
+ */
+ public function addErrorMessages(array $messages)
+ {
+ foreach ($messages as $message) {
+ $this->addErrorMessage($message);
+ }
+ return $this;
+ }
+
+ /**
+ * Same as addErrorMessages(), but clears custom error message stack first
+ *
+ * @param array $messages
+ * @return Zend_Form
+ */
+ public function setErrorMessages(array $messages)
+ {
+ $this->clearErrorMessages();
+ return $this->addErrorMessages($messages);
+ }
+
+ /**
+ * Retrieve custom error messages
+ *
+ * @return array
+ */
+ public function getErrorMessages()
+ {
+ return $this->_errorMessages;
+ }
+
+ /**
+ * Clear custom error messages stack
+ *
+ * @return Zend_Form
+ */
+ public function clearErrorMessages()
+ {
+ $this->_errorMessages = array();
+ return $this;
+ }
+
+ /**
+ * Mark the element as being in a failed validation state
+ *
+ * @return Zend_Form
+ */
+ public function markAsError()
+ {
+ $this->_errorsExist = true;
+ $this->_errorsForced = true;
+ return $this;
+ }
+
+ /**
+ * Add an error message and mark element as failed validation
+ *
+ * @param string $message
+ * @return Zend_Form
+ */
+ public function addError($message)
+ {
+ $this->addErrorMessage($message);
+ $this->markAsError();
+ return $this;
+ }
+
+ /**
+ * Add multiple error messages and flag element as failed validation
+ *
+ * @param array $messages
+ * @return Zend_Form
+ */
+ public function addErrors(array $messages)
+ {
+ foreach ($messages as $message) {
+ $this->addError($message);
+ }
+ return $this;
+ }
+
+ /**
+ * Overwrite any previously set error messages and flag as failed validation
+ *
+ * @param array $messages
+ * @return Zend_Form
+ */
+ public function setErrors(array $messages)
+ {
+ $this->clearErrorMessages();
+ return $this->addErrors($messages);
+ }
+
+
+ public function persistData()
+ {
+ }
+
+ /**
+ * Are there errors in the form?
+ *
+ * @deprecated since 1.11.1 - use hasErrors() instead
+ * @return bool
+ */
+ public function isErrors()
+ {
+ return $this->hasErrors();
+ }
+
+ /**
+ * Are there errors in the form?
+ *
+ * @return bool
+ */
+ public function hasErrors()
+ {
+ $errors = $this->_errorsExist;
+
+ if (!$errors) {
+ /** @var Zend_Form_Element $element */
+ foreach ($this->getElements() as $element) {
+ if ($element->hasErrors()) {
+ $errors = true;
+ break;
+ }
+ }
+
+ /** @var Zend_Form_SubForm $subForm */
+ foreach ($this->getSubForms() as $subForm) {
+ if ($subForm->hasErrors()) {
+ $errors = true;
+ break;
+ }
+ }
+ }
+
+ return $errors;
+ }
+
+ /**
+ * Get error codes for all elements failing validation
+ *
+ * @param string $name
+ * @param bool $suppressArrayNotation
+ * @return array
+ */
+ public function getErrors($name = null, $suppressArrayNotation = false)
+ {
+ $errors = array();
+ if (null !== $name) {
+ if (isset($this->_elements[$name])) {
+ return $this->getElement($name)->getErrors();
+ } else if (isset($this->_subForms[$name])) {
+ return $this->getSubForm($name)->getErrors(null, true);
+ }
+ }
+
+ /** @var Zend_Form_Element $element */
+ foreach ($this->_elements as $key => $element) {
+ $errors[$key] = $element->getErrors();
+ }
+ /** @var Zend_Form_SubForm $subForm */
+ foreach ($this->getSubForms() as $key => $subForm) {
+ $merge = array();
+ if (!$subForm->isArray()) {
+ $merge[$key] = $subForm->getErrors();
+ } else {
+ $merge = $this->_attachToArray($subForm->getErrors(null, true),
+ $subForm->getElementsBelongTo());
+ }
+ $errors = $this->_array_replace_recursive($errors, $merge);
+ }
+
+ if (!$suppressArrayNotation &&
+ $this->isArray() &&
+ !$this->_getIsRendered()) {
+ $errors = $this->_attachToArray($errors, $this->getElementsBelongTo());
+ }
+
+ return $errors;
+ }
+
+ /**
+ * Retrieve error messages from elements failing validations
+ *
+ * @param string $name
+ * @param bool $suppressArrayNotation
+ * @return array
+ */
+ public function getMessages($name = null, $suppressArrayNotation = false)
+ {
+ if (null !== $name) {
+ if (isset($this->_elements[$name])) {
+ return $this->getElement($name)->getMessages();
+ } else if (isset($this->_subForms[$name])) {
+ return $this->getSubForm($name)->getMessages(null, true);
+ }
+ /** @var Zend_Form_SubForm $subForm */
+ foreach ($this->getSubForms() as $key => $subForm) {
+ if ($subForm->isArray()) {
+ $belongTo = $subForm->getElementsBelongTo();
+ if ($name == $this->_getArrayName($belongTo)) {
+ return $subForm->getMessages(null, true);
+ }
+ }
+ }
+ }
+
+ $customMessages = $this->_getErrorMessages();
+ if ($this->isErrors() && !empty($customMessages)) {
+ return $customMessages;
+ }
+
+ $messages = array();
+
+ /** @var Zend_Form_Element $element */
+ foreach ($this->getElements() as $name => $element) {
+ $eMessages = $element->getMessages();
+ if (!empty($eMessages)) {
+ $messages[$name] = $eMessages;
+ }
+ }
+
+ /** @var Zend_Form_SubForm $subForm */
+ foreach ($this->getSubForms() as $key => $subForm) {
+ $merge = $subForm->getMessages(null, true);
+ if (!empty($merge)) {
+ if (!$subForm->isArray()) {
+ $merge = array($key => $merge);
+ } else {
+ $merge = $this->_attachToArray($merge,
+ $subForm->getElementsBelongTo());
+ }
+ $messages = $this->_array_replace_recursive($messages, $merge);
+ }
+ }
+
+ if (!$suppressArrayNotation &&
+ $this->isArray() &&
+ !$this->_getIsRendered()) {
+ $messages = $this->_attachToArray($messages, $this->getElementsBelongTo());
+ }
+
+ return $messages;
+ }
+
+ /**
+ * Retrieve translated custom error messages
+ * Proxies to {@link _getErrorMessages()}.
+ *
+ * @return array
+ */
+ public function getCustomMessages()
+ {
+ return $this->_getErrorMessages();
+ }
+
+
+ // Rendering
+
+ /**
+ * Set view object
+ *
+ * @param Zend_View_Interface $view
+ * @return Zend_Form
+ */
+ public function setView(Zend_View_Interface $view = null)
+ {
+ $this->_view = $view;
+ return $this;
+ }
+
+ /**
+ * Retrieve view object
+ *
+ * If none registered, attempts to pull from ViewRenderer.
+ *
+ * @return Zend_View_Interface|null
+ */
+ public function getView()
+ {
+ if (null === $this->_view) {
+ $viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
+ $this->setView($viewRenderer->view);
+ }
+
+ return $this->_view;
+ }
+
+ /**
+ * Instantiate a decorator based on class name or class name fragment
+ *
+ * @param string $name
+ * @param null|array $options
+ * @return Zend_Form_Decorator_Interface
+ */
+ protected function _getDecorator($name, $options)
+ {
+ $class = $this->getPluginLoader(self::DECORATOR)->load($name);
+ if (null === $options) {
+ $decorator = new $class;
+ } else {
+ $decorator = new $class($options);
+ }
+
+ return $decorator;
+ }
+
+ /**
+ * Add a decorator for rendering the element
+ *
+ * @param string|Zend_Form_Decorator_Interface $decorator
+ * @param array|Zend_Config $options Options with which to initialize decorator
+ * @throws Zend_Form_Exception
+ * @return Zend_Form
+ */
+ public function addDecorator($decorator, $options = null)
+ {
+ if ($decorator instanceof Zend_Form_Decorator_Interface) {
+ $name = get_class($decorator);
+ } elseif (is_string($decorator)) {
+ $name = $decorator;
+ $decorator = array(
+ 'decorator' => $name,
+ 'options' => $options,
+ );
+ } elseif (is_array($decorator)) {
+ foreach ($decorator as $name => $spec) {
+ break;
+ }
+ if (is_numeric($name)) {
+ throw new Zend_Form_Exception('Invalid alias provided to addDecorator; must be alphanumeric string');
+ }
+ if (is_string($spec)) {
+ $decorator = array(
+ 'decorator' => $spec,
+ 'options' => $options,
+ );
+ } elseif ($spec instanceof Zend_Form_Decorator_Interface) {
+ $decorator = $spec;
+ }
+ } else {
+ throw new Zend_Form_Exception('Invalid decorator provided to addDecorator; must be string or Zend_Form_Decorator_Interface');
+ }
+
+ $this->_decorators[$name] = $decorator;
+
+ return $this;
+ }
+
+ /**
+ * Add many decorators at once
+ *
+ * @param array $decorators
+ * @throws Zend_Form_Exception
+ * @return Zend_Form
+ */
+ public function addDecorators(array $decorators)
+ {
+ foreach ($decorators as $decoratorName => $decoratorInfo) {
+ if (is_string($decoratorInfo) ||
+ $decoratorInfo instanceof Zend_Form_Decorator_Interface) {
+ if (!is_numeric($decoratorName)) {
+ $this->addDecorator(array($decoratorName => $decoratorInfo));
+ } else {
+ $this->addDecorator($decoratorInfo);
+ }
+ } elseif (is_array($decoratorInfo)) {
+ $argc = count($decoratorInfo);
+ $options = array();
+ if (isset($decoratorInfo['decorator'])) {
+ $decorator = $decoratorInfo['decorator'];
+ if (isset($decoratorInfo['options'])) {
+ $options = $decoratorInfo['options'];
+ }
+ $this->addDecorator($decorator, $options);
+ } else {
+ switch (true) {
+ case (0 == $argc):
+ break;
+ case (1 <= $argc):
+ $decorator = array_shift($decoratorInfo);
+ case (2 <= $argc):
+ $options = array_shift($decoratorInfo);
+ default:
+ $this->addDecorator($decorator, $options);
+ break;
+ }
+ }
+ } else {
+ throw new Zend_Form_Exception('Invalid decorator passed to addDecorators()');
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * Overwrite all decorators
+ *
+ * @param array $decorators
+ * @return Zend_Form
+ */
+ public function setDecorators(array $decorators)
+ {
+ $this->clearDecorators();
+ return $this->addDecorators($decorators);
+ }
+
+ /**
+ * Retrieve a registered decorator
+ *
+ * @param string $name
+ * @return false|Zend_Form_Decorator_Abstract
+ */
+ public function getDecorator($name)
+ {
+ if (!isset($this->_decorators[$name])) {
+ $len = strlen($name);
+ foreach ($this->_decorators as $localName => $decorator) {
+ if ($len > strlen($localName)) {
+ continue;
+ }
+
+ if (0 === substr_compare($localName, $name, -$len, $len, true)) {
+ if (is_array($decorator)) {
+ return $this->_loadDecorator($decorator, $localName);
+ }
+ return $decorator;
+ }
+ }
+ return false;
+ }
+
+ if (is_array($this->_decorators[$name])) {
+ return $this->_loadDecorator($this->_decorators[$name], $name);
+ }
+
+ return $this->_decorators[$name];
+ }
+
+ /**
+ * Retrieve all decorators
+ *
+ * @return array
+ */
+ public function getDecorators()
+ {
+ foreach ($this->_decorators as $key => $value) {
+ if (is_array($value)) {
+ $this->_loadDecorator($value, $key);
+ }
+ }
+ return $this->_decorators;
+ }
+
+ /**
+ * Remove a single decorator
+ *
+ * @param string $name
+ * @return bool
+ */
+ public function removeDecorator($name)
+ {
+ $decorator = $this->getDecorator($name);
+ if ($decorator) {
+ if (array_key_exists($name, $this->_decorators)) {
+ unset($this->_decorators[$name]);
+ } else {
+ $class = get_class($decorator);
+ if (!array_key_exists($class, $this->_decorators)) {
+ return false;
+ }
+ unset($this->_decorators[$class]);
+ }
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Clear all decorators
+ *
+ * @return Zend_Form
+ */
+ public function clearDecorators()
+ {
+ $this->_decorators = array();
+ return $this;
+ }
+
+ /**
+ * Set all element decorators as specified
+ *
+ * @param array $decorators
+ * @param array|null $elements Specific elements to decorate or exclude from decoration
+ * @param bool $include Whether $elements is an inclusion or exclusion list
+ * @return Zend_Form
+ */
+ public function setElementDecorators(array $decorators, array $elements = null, $include = true)
+ {
+ if (is_array($elements)) {
+ if ($include) {
+ $elementObjs = array();
+ foreach ($elements as $name) {
+ if (null !== ($element = $this->getElement($name))) {
+ $elementObjs[] = $element;
+ }
+ }
+ } else {
+ $elementObjs = $this->getElements();
+ foreach ($elements as $name) {
+ if (array_key_exists($name, $elementObjs)) {
+ unset($elementObjs[$name]);
+ }
+ }
+ }
+ } else {
+ $elementObjs = $this->getElements();
+ }
+
+ /** @var Zend_Form_Element $element */
+ foreach ($elementObjs as $element) {
+ $element->setDecorators($decorators);
+ }
+
+ $this->_elementDecorators = $decorators;
+
+ return $this;
+ }
+
+ /**
+ * Set all display group decorators as specified
+ *
+ * @param array $decorators
+ * @return Zend_Form
+ */
+ public function setDisplayGroupDecorators(array $decorators)
+ {
+ /** @var Zend_Form_DisplayGroup $group */
+ foreach ($this->getDisplayGroups() as $group) {
+ $group->setDecorators($decorators);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set all subform decorators as specified
+ *
+ * @param array $decorators
+ * @return Zend_Form
+ */
+ public function setSubFormDecorators(array $decorators)
+ {
+ /** @var Zend_Form_SubForm $form */
+ foreach ($this->getSubForms() as $form) {
+ $form->setDecorators($decorators);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Render form
+ *
+ * @param Zend_View_Interface $view
+ * @return string
+ */
+ public function render(Zend_View_Interface $view = null)
+ {
+ if (null !== $view) {
+ $this->setView($view);
+ }
+
+ $content = '';
+ /** @var Zend_Form_Decorator_Abstract $decorator */
+ foreach ($this->getDecorators() as $decorator) {
+ $decorator->setElement($this);
+ $content = $decorator->render($content);
+ }
+ $this->_setIsRendered();
+ return $content;
+ }
+
+ /**
+ * Serialize as string
+ *
+ * Proxies to {@link render()}.
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ try {
+ $return = $this->render();
+ return $return;
+ } catch (Exception $e) {
+ $message = "Exception caught by form: " . $e->getMessage()
+ . "\nStack Trace:\n" . $e->getTraceAsString();
+ trigger_error($message, E_USER_WARNING);
+ return '';
+ }
+ }
+
+
+ // Localization:
+
+ /**
+ * Set translator object
+ *
+ * @param Zend_Translate|Zend_Translate_Adapter|null $translator
+ * @throws Zend_Form_Exception
+ * @return Zend_Form
+ */
+ public function setTranslator($translator = null)
+ {
+ if (null === $translator) {
+ $this->_translator = null;
+ } elseif ($translator instanceof Zend_Translate_Adapter) {
+ $this->_translator = $translator;
+ } elseif ($translator instanceof Zend_Translate) {
+ $this->_translator = $translator->getAdapter();
+ } else {
+ throw new Zend_Form_Exception('Invalid translator specified');
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set global default translator object
+ *
+ * @param Zend_Translate|Zend_Translate_Adapter|null $translator
+ * @throws Zend_Form_Exception
+ * @return void
+ */
+ public static function setDefaultTranslator($translator = null)
+ {
+ if (null === $translator) {
+ self::$_translatorDefault = null;
+ } elseif ($translator instanceof Zend_Translate_Adapter) {
+ self::$_translatorDefault = $translator;
+ } elseif ($translator instanceof Zend_Translate) {
+ self::$_translatorDefault = $translator->getAdapter();
+ } else {
+ throw new Zend_Form_Exception('Invalid translator specified');
+ }
+ }
+
+ /**
+ * Retrieve translator object
+ *
+ * @return Zend_Translate|null
+ */
+ public function getTranslator()
+ {
+ if ($this->translatorIsDisabled()) {
+ return null;
+ }
+
+ if (null === $this->_translator) {
+ return self::getDefaultTranslator();
+ }
+
+ return $this->_translator;
+ }
+
+ /**
+ * Does this form have its own specific translator?
+ *
+ * @return bool
+ */
+ public function hasTranslator()
+ {
+ return (bool)$this->_translator;
+ }
+
+ /**
+ * Get global default translator object
+ *
+ * @return null|Zend_Translate
+ */
+ public static function getDefaultTranslator()
+ {
+ if (null === self::$_translatorDefault) {
+ if (Zend_Registry::isRegistered('Zend_Translate')) {
+ $translator = Zend_Registry::get('Zend_Translate');
+ if ($translator instanceof Zend_Translate_Adapter) {
+ return $translator;
+ } elseif ($translator instanceof Zend_Translate) {
+ return $translator->getAdapter();
+ }
+ }
+ }
+ return self::$_translatorDefault;
+ }
+
+ /**
+ * Is there a default translation object set?
+ *
+ * @return boolean
+ */
+ public static function hasDefaultTranslator()
+ {
+ return (bool)self::$_translatorDefault;
+ }
+
+ /**
+ * Indicate whether or not translation should be disabled
+ *
+ * @param bool $flag
+ * @return Zend_Form
+ */
+ public function setDisableTranslator($flag)
+ {
+ $this->_translatorDisabled = (bool) $flag;
+ return $this;
+ }
+
+ /**
+ * Is translation disabled?
+ *
+ * @return bool
+ */
+ public function translatorIsDisabled()
+ {
+ return $this->_translatorDisabled;
+ }
+
+ /**
+ * Overloading: access to elements, form groups, and display groups
+ *
+ * @param string $name
+ * @return Zend_Form_Element|Zend_Form|null
+ */
+ public function __get($name)
+ {
+ if (isset($this->_elements[$name])) {
+ return $this->_elements[$name];
+ } elseif (isset($this->_subForms[$name])) {
+ return $this->_subForms[$name];
+ } elseif (isset($this->_displayGroups[$name])) {
+ return $this->_displayGroups[$name];
+ }
+
+ return null;
+ }
+
+ /**
+ * Overloading: access to elements, form groups, and display groups
+ *
+ * @param string $name
+ * @param Zend_Form_Element|Zend_Form $value
+ * @return void
+ * @throws Zend_Form_Exception for invalid $value
+ */
+ public function __set($name, $value)
+ {
+ if ($value instanceof Zend_Form_Element) {
+ $this->addElement($value, $name);
+ return;
+ } elseif ($value instanceof Zend_Form) {
+ $this->addSubForm($value, $name);
+ return;
+ } elseif (is_array($value)) {
+ $this->addDisplayGroup($value, $name);
+ return;
+ }
+
+ if (is_object($value)) {
+ $type = get_class($value);
+ } else {
+ $type = gettype($value);
+ }
+ throw new Zend_Form_Exception('Only form elements and groups may be overloaded; variable of type "' . $type . '" provided');
+ }
+
+ /**
+ * Overloading: access to elements, form groups, and display groups
+ *
+ * @param string $name
+ * @return boolean
+ */
+ public function __isset($name)
+ {
+ if (isset($this->_elements[$name])
+ || isset($this->_subForms[$name])
+ || isset($this->_displayGroups[$name]))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Overloading: access to elements, form groups, and display groups
+ *
+ * @param string $name
+ * @return void
+ */
+ public function __unset($name)
+ {
+ if (isset($this->_elements[$name])) {
+ unset($this->_elements[$name]);
+ } elseif (isset($this->_subForms[$name])) {
+ unset($this->_subForms[$name]);
+ } elseif (isset($this->_displayGroups[$name])) {
+ unset($this->_displayGroups[$name]);
+ }
+ }
+
+ /**
+ * Overloading: allow rendering specific decorators
+ *
+ * Call renderDecoratorName() to render a specific decorator.
+ *
+ * @param string $method
+ * @param array $args
+ * @return string
+ * @throws Zend_Form_Exception for invalid decorator or invalid method call
+ */
+ public function __call($method, $args)
+ {
+ if ('render' == substr($method, 0, 6)) {
+ $decoratorName = substr($method, 6);
+ if (false !== ($decorator = $this->getDecorator($decoratorName))) {
+ $decorator->setElement($this);
+ $seed = '';
+ if (0 < count($args)) {
+ $seed = array_shift($args);
+ }
+ if ($decoratorName === 'FormElements' ||
+ $decoratorName === 'PrepareElements') {
+ $this->_setIsRendered();
+ }
+ return $decorator->render($seed);
+ }
+
+ throw new Zend_Form_Exception(sprintf('Decorator by name %s does not exist', $decoratorName));
+ }
+
+ throw new Zend_Form_Exception(sprintf('Method %s does not exist', $method));
+ }
+
+ // Interfaces: Iterator, Countable
+
+ /**
+ * Current element/subform/display group
+ *
+ * @throws Zend_Form_Exception
+ * @return Zend_Form_Element|Zend_Form_DisplayGroup|Zend_Form
+ */
+ #[\ReturnTypeWillChange]
+ public function current()
+ {
+ $this->_sort();
+ current($this->_order);
+ $key = key($this->_order);
+
+ if (isset($this->_elements[$key])) {
+ return $this->getElement($key);
+ } elseif (isset($this->_subForms[$key])) {
+ return $this->getSubForm($key);
+ } elseif (isset($this->_displayGroups[$key])) {
+ return $this->getDisplayGroup($key);
+ } else {
+ throw new Zend_Form_Exception(sprintf('Corruption detected in form; invalid key ("%s") found in internal iterator', (string) $key));
+ }
+ }
+
+ /**
+ * Current element/subform/display group name
+ *
+ * @return string
+ */
+ public function key(): string
+ {
+ $this->_sort();
+ return key($this->_order);
+ }
+
+ /**
+ * Move pointer to next element/subform/display group
+ *
+ * @return void
+ */
+ public function next(): void
+ {
+ $this->_sort();
+ next($this->_order);
+ }
+
+ /**
+ * Move pointer to beginning of element/subform/display group loop
+ *
+ * @return void
+ */
+ public function rewind(): void
+ {
+ $this->_sort();
+ reset($this->_order);
+ }
+
+ /**
+ * Determine if current element/subform/display group is valid
+ *
+ * @return bool
+ */
+ public function valid(): bool
+ {
+ $this->_sort();
+ return (current($this->_order) !== false);
+ }
+
+ /**
+ * Count of elements/subforms that are iterable
+ *
+ * @return int
+ */
+ public function count(): int
+ {
+ return count($this->_order);
+ }
+
+ /**
+ * Set flag to disable loading default decorators
+ *
+ * @param bool $flag
+ * @return Zend_Form
+ */
+ public function setDisableLoadDefaultDecorators($flag)
+ {
+ $this->_disableLoadDefaultDecorators = (bool) $flag;
+ return $this;
+ }
+
+ /**
+ * Should we load the default decorators?
+ *
+ * @return bool
+ */
+ public function loadDefaultDecoratorsIsDisabled()
+ {
+ return $this->_disableLoadDefaultDecorators;
+ }
+
+ /**
+ * Load the default decorators
+ *
+ * @return Zend_Form
+ */
+ public function loadDefaultDecorators()
+ {
+ if ($this->loadDefaultDecoratorsIsDisabled()) {
+ return $this;
+ }
+
+ $decorators = $this->getDecorators();
+ if (empty($decorators)) {
+ $this->addDecorator('FormElements')
+ ->addDecorator('HtmlTag', array('tag' => 'dl', 'class' => 'zend_form'))
+ ->addDecorator('Form');
+ }
+ return $this;
+ }
+
+ /**
+ * Remove an element from iteration
+ *
+ * @param string $name Element/group/form name
+ * @return void
+ */
+ public function removeFromIteration($name)
+ {
+ if (array_key_exists($name, $this->_order)) {
+ unset($this->_order[$name]);
+ $this->_orderUpdated = true;
+ }
+ }
+
+ /**
+ * Sort items according to their order
+ *
+ * @throws Zend_Form_Exception
+ * @return void
+ */
+ protected function _sort()
+ {
+ if ($this->_orderUpdated) {
+ $items = array();
+ $index = 0;
+ foreach ($this->_order as $key => $order) {
+ if (null === $order) {
+ if (null === ($order = $this->{$key}->getOrder())) {
+ while (array_search($index, $this->_order, true)) {
+ ++$index;
+ }
+ $items[$index] = $key;
+ ++$index;
+ } else {
+ $items[$order] = $key;
+ }
+ } elseif (isset($items[$order]) && $items[$order] !== $key) {
+ throw new Zend_Form_Exception('Form elements ' .
+ $items[$order] . ' and ' . $key .
+ ' have the same order (' .
+ $order . ') - ' .
+ 'this would result in only the last added element to be rendered'
+ );
+ } else {
+ $items[$order] = $key;
+ }
+ }
+
+ $items = array_flip($items);
+ asort($items);
+ $this->_order = $items;
+ $this->_orderUpdated = false;
+ }
+ }
+
+ /**
+ * Lazy-load a decorator
+ *
+ * @param array $decorator Decorator type and options
+ * @param mixed $name Decorator name or alias
+ * @return Zend_Form_Decorator_Interface
+ */
+ protected function _loadDecorator(array $decorator, $name)
+ {
+ $sameName = false;
+ if ($name == $decorator['decorator']) {
+ $sameName = true;
+ }
+
+ $instance = $this->_getDecorator($decorator['decorator'], $decorator['options']);
+ if ($sameName) {
+ $newName = get_class($instance);
+ $decoratorNames = array_keys($this->_decorators);
+ $order = array_flip($decoratorNames);
+ $order[$newName] = $order[$name];
+ $decoratorsExchange = array();
+ unset($order[$name]);
+ asort($order);
+ foreach ($order as $key => $index) {
+ if ($key == $newName) {
+ $decoratorsExchange[$key] = $instance;
+ continue;
+ }
+ $decoratorsExchange[$key] = $this->_decorators[$key];
+ }
+ $this->_decorators = $decoratorsExchange;
+ } else {
+ $this->_decorators[$name] = $instance;
+ }
+
+ return $instance;
+ }
+
+ /**
+ * Retrieve optionally translated custom error messages
+ *
+ * @return array
+ */
+ protected function _getErrorMessages()
+ {
+ $messages = $this->getErrorMessages();
+ $translator = $this->getTranslator();
+ if (null !== $translator) {
+ foreach ($messages as $key => $message) {
+ $messages[$key] = $translator->translate($message);
+ }
+ }
+ return $messages;
+ }
+}