7 * This source file is subject to the new BSD license that is bundled
8 * with this package in the file LICENSE.txt.
9 * It is also available through the world-wide-web at this URL:
10 * http://framework.zend.com/license/new-bsd
11 * If you did not receive a copy of the license and are unable to
12 * obtain it through the world-wide-web, please send an email
13 * to license@zend.com so we can send you a copy immediately.
17 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
18 * @license http://framework.zend.com/license/new-bsd New BSD License
21 /** @see Zend_Filter */
22 require_once 'Zend/Filter.php';
25 require_once 'Zend/Form.php';
27 /** @see Zend_Validate_Interface */
28 require_once 'Zend/Validate/Interface.php';
30 /** @see Zend_Validate_Abstract */
31 require_once 'Zend/Validate/Abstract.php';
39 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
40 * @license http://framework.zend.com/license/new-bsd New BSD License
43 class Zend_Form_Element
implements Zend_Validate_Interface
48 const DECORATOR
= 'DECORATOR';
49 const FILTER
= 'FILTER';
50 const VALIDATE
= 'VALIDATE';
53 * Default view helper to use
56 public $helper = 'formText';
62 protected $_allowEmpty = true;
65 * Flag indicating whether or not to insert NotEmpty validator when element is required
68 protected $_autoInsertNotEmptyValidator = true;
71 * Array to which element belongs
74 protected $_belongsTo;
80 protected $_decorators = array();
86 protected $_description;
89 * Should we disable loading the default decorators?
92 protected $_disableLoadDefaultDecorators = false;
95 * Custom error messages
98 protected $_errorMessages = array();
104 protected $_errors = array();
107 * Separator to use when concatenating aggregate error messages (for
108 * elements having array values)
111 protected $_errorMessageSeparator = '; ';
117 protected $_filters = array();
120 * Ignore flag (used when retrieving values at form level)
123 protected $_ignore = false;
126 * Does the element represent an array?
129 protected $_isArray = false;
132 * Is the error marked as in an invalid state?
135 protected $_isError = false;
138 * Has the element been manually marked as invalid?
141 protected $_isErrorForced = false;
150 * Plugin loaders for filter and validator chains
153 protected $_loaders = array();
156 * Formatted validation error messages
159 protected $_messages = array();
177 protected $_required = false;
180 * @var Zend_Translate
182 protected $_translator;
185 * Is translation disabled?
188 protected $_translatorDisabled = false;
197 * Array of initialized validators
198 * @var array Validators
200 protected $_validators = array();
203 * Array of un-initialized validators
206 protected $_validatorRules = array();
215 * @var Zend_View_Interface
220 * Is a specific decorator being rendered via the magic renderDecorator()?
222 * This is to allow execution of logic inside the render() methods of child
223 * elements during the magic call while skipping the parent render() method.
227 protected $_isPartialRendering = false;
233 * - string: name of element
234 * - array: options with which to configure element
235 * - Zend_Config: Zend_Config with options for configuring element
237 * @param string|array|Zend_Config $spec
238 * @param array|Zend_Config $options
240 * @throws Zend_Form_Exception if no element name after initialization
242 public function __construct($spec, $options = null)
244 if (is_string($spec)) {
245 $this->setName($spec);
246 } elseif (is_array($spec)) {
247 $this->setOptions($spec);
248 } elseif ($spec instanceof Zend_Config
) {
249 $this->setConfig($spec);
252 if (is_string($spec) && is_array($options)) {
253 $this->setOptions($options);
254 } elseif (is_string($spec) && ($options instanceof Zend_Config
)) {
255 $this->setConfig($options);
258 if (null === $this->getName()) {
259 require_once 'Zend/Form/Exception.php';
260 throw new Zend_Form_Exception('Zend_Form_Element requires each element to have a name');
269 * Register ViewHelper decorator by default
271 $this->loadDefaultDecorators();
275 * Initialize object; used by extending classes
279 public function init()
284 * Set flag to disable loading default decorators
287 * @return Zend_Form_Element
289 public function setDisableLoadDefaultDecorators($flag)
291 $this->_disableLoadDefaultDecorators
= (bool) $flag;
296 * Should we load the default decorators?
300 public function loadDefaultDecoratorsIsDisabled()
302 return $this->_disableLoadDefaultDecorators
;
306 * Load default decorators
308 * @return Zend_Form_Element
310 public function loadDefaultDecorators()
312 if ($this->loadDefaultDecoratorsIsDisabled()) {
316 $decorators = $this->getDecorators();
317 if (empty($decorators)) {
318 $getId = create_function('$decorator',
319 'return $decorator->getElement()->getId()
321 $this->addDecorator('ViewHelper')
322 ->addDecorator('Errors')
323 ->addDecorator('Description', array('tag' => 'p', 'class' => 'description'))
324 ->addDecorator('HtmlTag', array('tag' => 'dd',
325 'id' => array('callback' => $getId)))
326 ->addDecorator('Label', array('tag' => 'dt'));
332 * Set object state from options array
334 * @param array $options
335 * @return Zend_Form_Element
337 public function setOptions(array $options)
339 if (isset($options['prefixPath'])) {
340 $this->addPrefixPaths($options['prefixPath']);
341 unset($options['prefixPath']);
344 if (isset($options['disableTranslator'])) {
345 $this->setDisableTranslator($options['disableTranslator']);
346 unset($options['disableTranslator']);
349 unset($options['options']);
350 unset($options['config']);
352 foreach ($options as $key => $value) {
353 $method = 'set' . ucfirst($key);
355 if (in_array($method, array('setTranslator', 'setPluginLoader', 'setView'))) {
356 if (!is_object($value)) {
361 if (method_exists($this, $method)) {
362 // Setter exists; use it
363 $this->$method($value);
365 // Assume it's metadata
366 $this->setAttrib($key, $value);
373 * Set object state from Zend_Config object
375 * @param Zend_Config $config
376 * @return Zend_Form_Element
378 public function setConfig(Zend_Config
$config)
380 return $this->setOptions($config->toArray());
387 * Set translator object for localization
389 * @param Zend_Translate|null $translator
390 * @return Zend_Form_Element
392 public function setTranslator($translator = null)
394 if (null === $translator) {
395 $this->_translator
= null;
396 } elseif ($translator instanceof Zend_Translate_Adapter
) {
397 $this->_translator
= $translator;
398 } elseif ($translator instanceof Zend_Translate
) {
399 $this->_translator
= $translator->getAdapter();
401 require_once 'Zend/Form/Exception.php';
402 throw new Zend_Form_Exception('Invalid translator specified');
408 * Retrieve localization translator object
410 * @return Zend_Translate_Adapter|null
412 public function getTranslator()
414 if ($this->translatorIsDisabled()) {
418 if (null === $this->_translator
) {
419 return Zend_Form
::getDefaultTranslator();
421 return $this->_translator
;
425 * Does this element have its own specific translator?
429 public function hasTranslator()
431 return (bool)$this->_translator
;
435 * Indicate whether or not translation should be disabled
438 * @return Zend_Form_Element
440 public function setDisableTranslator($flag)
442 $this->_translatorDisabled
= (bool) $flag;
447 * Is translation disabled?
451 public function translatorIsDisabled()
453 return $this->_translatorDisabled
;
459 * Filter a name to only allow valid variable characters
461 * @param string $value
462 * @param bool $allowBrackets
465 public function filterName($value, $allowBrackets = false)
467 $charset = '^a-zA-Z0-9_\x7f-\xff';
468 if ($allowBrackets) {
471 return preg_replace('/[' . $charset . ']/', '', (string) $value);
477 * @param string $name
478 * @return Zend_Form_Element
480 public function setName($name)
482 $name = $this->filterName($name);
484 require_once 'Zend/Form/Exception.php';
485 throw new Zend_Form_Exception('Invalid name provided; must contain only valid variable characters and be non-empty');
488 $this->_name
= $name;
493 * Return element name
497 public function getName()
503 * Get fully qualified name
505 * Places name as subitem of array and/or appends brackets.
509 public function getFullyQualifiedName()
511 $name = $this->getName();
513 if (null !== ($belongsTo = $this->getBelongsTo())) {
514 $name = $belongsTo . '[' . $name . ']';
517 if ($this->isArray()) {
529 public function getId()
531 if (isset($this->id
)) {
535 $id = $this->getFullyQualifiedName();
537 // Bail early if no array notation detected
538 if (!strstr($id, '[')) {
542 // Strip array notation
543 if ('[]' == substr($id, -2)) {
544 $id = substr($id, 0, strlen($id) - 2);
546 $id = str_replace('][', '-', $id);
547 $id = str_replace(array(']', '['), '-', $id);
548 $id = trim($id, '-');
556 * @param mixed $value
557 * @return Zend_Form_Element
559 public function setValue($value)
561 $this->_value
= $value;
568 * @param string $value
572 protected function _filterValue(&$value, &$key)
574 foreach ($this->getFilters() as $filter) {
575 $value = $filter->filter($value);
580 * Retrieve filtered element value
584 public function getValue()
586 $valueFiltered = $this->_value
;
588 if ($this->isArray() && is_array($valueFiltered)) {
589 array_walk_recursive($valueFiltered, array($this, '_filterValue'));
591 $this->_filterValue($valueFiltered, $valueFiltered);
594 return $valueFiltered;
598 * Retrieve unfiltered element value
602 public function getUnfilteredValue()
604 return $this->_value
;
610 * @param string $label
611 * @return Zend_Form_Element
613 public function setLabel($label)
615 $this->_label
= (string) $label;
620 * Retrieve element label
624 public function getLabel()
626 $translator = $this->getTranslator();
627 if (null !== $translator) {
628 return $translator->translate($this->_label
);
631 return $this->_label
;
638 * @return Zend_Form_Element
640 public function setOrder($order)
642 $this->_order
= (int) $order;
647 * Retrieve element order
651 public function getOrder()
653 return $this->_order
;
659 * @param bool $flag Default value is true
660 * @return Zend_Form_Element
662 public function setRequired($flag = true)
664 $this->_required
= (bool) $flag;
669 * Is the element required?
673 public function isRequired()
675 return $this->_required
;
679 * Set flag indicating whether a NotEmpty validator should be inserted when element is required
682 * @return Zend_Form_Element
684 public function setAutoInsertNotEmptyValidator($flag)
686 $this->_autoInsertNotEmptyValidator
= (bool) $flag;
691 * Get flag indicating whether a NotEmpty validator should be inserted when element is required
695 public function autoInsertNotEmptyValidator()
697 return $this->_autoInsertNotEmptyValidator
;
701 * Set element description
703 * @param string $description
704 * @return Zend_Form_Element
706 public function setDescription($description)
708 $this->_description
= (string) $description;
713 * Retrieve element description
717 public function getDescription()
719 return $this->_description
;
723 * Set 'allow empty' flag
725 * When the allow empty flag is enabled and the required flag is false, the
726 * element will validate with empty values.
729 * @return Zend_Form_Element
731 public function setAllowEmpty($flag)
733 $this->_allowEmpty
= (bool) $flag;
738 * Get 'allow empty' flag
742 public function getAllowEmpty()
744 return $this->_allowEmpty
;
748 * Set ignore flag (used when retrieving values at form level)
751 * @return Zend_Form_Element
753 public function setIgnore($flag)
755 $this->_ignore
= (bool) $flag;
760 * Get ignore flag (used when retrieving values at form level)
764 public function getIgnore()
766 return $this->_ignore
;
770 * Set flag indicating if element represents an array
773 * @return Zend_Form_Element
775 public function setIsArray($flag)
777 $this->_isArray
= (bool) $flag;
782 * Is the element representing an array?
786 public function isArray()
788 return $this->_isArray
;
792 * Set array to which element belongs
794 * @param string $array
795 * @return Zend_Form_Element
797 public function setBelongsTo($array)
799 $array = $this->filterName($array, true);
800 if (!empty($array)) {
801 $this->_belongsTo
= $array;
808 * Return array name to which element belongs
812 public function getBelongsTo()
814 return $this->_belongsTo
;
818 * Return element type
822 public function getType()
824 if (null === $this->_type
) {
825 $this->_type
= get_class($this);
832 * Set element attribute
834 * @param string $name
835 * @param mixed $value
836 * @return Zend_Form_Element
837 * @throws Zend_Form_Exception for invalid $name values
839 public function setAttrib($name, $value)
841 $name = (string) $name;
842 if ('_' == $name[0]) {
843 require_once 'Zend/Form/Exception.php';
844 throw new Zend_Form_Exception(sprintf('Invalid attribute "%s"; must not contain a leading underscore', $name));
847 if (null === $value) {
850 $this->$name = $value;
857 * Set multiple attributes at once
859 * @param array $attribs
860 * @return Zend_Form_Element
862 public function setAttribs(array $attribs)
864 foreach ($attribs as $key => $value) {
865 $this->setAttrib($key, $value);
872 * Retrieve element attribute
874 * @param string $name
877 public function getAttrib($name)
879 $name = (string) $name;
880 if (isset($this->$name)) {
888 * Return all attributes
892 public function getAttribs()
894 $attribs = get_object_vars($this);
895 foreach ($attribs as $key => $value) {
896 if ('_' == substr($key, 0, 1)) {
897 unset($attribs[$key]);
905 * Overloading: retrieve object property
907 * Prevents access to properties beginning with '_'.
912 public function __get($key)
914 if ('_' == $key[0]) {
915 require_once 'Zend/Form/Exception.php';
916 throw new Zend_Form_Exception(sprintf('Cannot retrieve value for protected/private property "%s"', $key));
919 if (!isset($this->$key)) {
927 * Overloading: set object property
930 * @param mixed $value
933 public function __set($key, $value)
935 $this->setAttrib($key, $value);
939 * Overloading: allow rendering specific decorators
941 * Call renderDecoratorName() to render a specific decorator.
943 * @param string $method
946 * @throws Zend_Form_Exception for invalid decorator or invalid method call
948 public function __call($method, $args)
950 if ('render' == substr($method, 0, 6)) {
951 $this->_isPartialRendering
= true;
953 $this->_isPartialRendering
= false;
954 $decoratorName = substr($method, 6);
955 if (false !== ($decorator = $this->getDecorator($decoratorName))) {
956 $decorator->setElement($this);
958 if (0 < count($args)) {
959 $seed = array_shift($args);
961 return $decorator->render($seed);
964 require_once 'Zend/Form/Element/Exception.php';
965 throw new Zend_Form_Element_Exception(sprintf('Decorator by name %s does not exist', $decoratorName));
968 require_once 'Zend/Form/Element/Exception.php';
969 throw new Zend_Form_Element_Exception(sprintf('Method %s does not exist', $method));
975 * Set plugin loader to use for validator or filter chain
977 * @param Zend_Loader_PluginLoader_Interface $loader
978 * @param string $type 'decorator', 'filter', or 'validate'
979 * @return Zend_Form_Element
980 * @throws Zend_Form_Exception on invalid type
982 public function setPluginLoader(Zend_Loader_PluginLoader_Interface
$loader, $type)
984 $type = strtoupper($type);
986 case self
::DECORATOR
:
989 $this->_loaders
[$type] = $loader;
992 require_once 'Zend/Form/Exception.php';
993 throw new Zend_Form_Exception(sprintf('Invalid type "%s" provided to setPluginLoader()', $type));
998 * Retrieve plugin loader for validator or filter chain
1000 * Instantiates with default rules if none available for that type. Use
1001 * 'decorator', 'filter', or 'validate' for $type.
1003 * @param string $type
1004 * @return Zend_Loader_PluginLoader
1005 * @throws Zend_Loader_Exception on invalid type.
1007 public function getPluginLoader($type)
1009 $type = strtoupper($type);
1012 case self
::VALIDATE
:
1013 $prefixSegment = ucfirst(strtolower($type));
1014 $pathSegment = $prefixSegment;
1015 case self
::DECORATOR
:
1016 if (!isset($prefixSegment)) {
1017 $prefixSegment = 'Form_Decorator';
1018 $pathSegment = 'Form/Decorator';
1020 if (!isset($this->_loaders
[$type])) {
1021 require_once 'Zend/Loader/PluginLoader.php';
1022 $this->_loaders
[$type] = new Zend_Loader_PluginLoader(
1023 array('Zend_' . $prefixSegment . '_' => 'Zend/' . $pathSegment . '/')
1026 return $this->_loaders
[$type];
1028 require_once 'Zend/Form/Exception.php';
1029 throw new Zend_Form_Exception(sprintf('Invalid type "%s" provided to getPluginLoader()', $type));
1034 * Add prefix path for plugin loader
1036 * If no $type specified, assumes it is a base path for both filters and
1037 * validators, and sets each according to the following rules:
1038 * - decorators: $prefix = $prefix . '_Decorator'
1039 * - filters: $prefix = $prefix . '_Filter'
1040 * - validators: $prefix = $prefix . '_Validate'
1042 * Otherwise, the path prefix is set on the appropriate plugin loader.
1044 * @param string $prefix
1045 * @param string $path
1046 * @param string $type
1047 * @return Zend_Form_Element
1048 * @throws Zend_Form_Exception for invalid type
1050 public function addPrefixPath($prefix, $path, $type = null)
1052 $type = strtoupper($type);
1054 case self
::DECORATOR
:
1056 case self
::VALIDATE
:
1057 $loader = $this->getPluginLoader($type);
1058 $loader->addPrefixPath($prefix, $path);
1061 $prefix = rtrim($prefix, '_');
1062 $path = rtrim($path, DIRECTORY_SEPARATOR
);
1063 foreach (array(self
::DECORATOR
, self
::FILTER
, self
::VALIDATE
) as $type) {
1064 $cType = ucfirst(strtolower($type));
1065 $pluginPath = $path . DIRECTORY_SEPARATOR
. $cType . DIRECTORY_SEPARATOR
;
1066 $pluginPrefix = $prefix . '_' . $cType;
1067 $loader = $this->getPluginLoader($type);
1068 $loader->addPrefixPath($pluginPrefix, $pluginPath);
1072 require_once 'Zend/Form/Exception.php';
1073 throw new Zend_Form_Exception(sprintf('Invalid type "%s" provided to getPluginLoader()', $type));
1078 * Add many prefix paths at once
1080 * @param array $spec
1081 * @return Zend_Form_Element
1083 public function addPrefixPaths(array $spec)
1085 if (isset($spec['prefix']) && isset($spec['path'])) {
1086 return $this->addPrefixPath($spec['prefix'], $spec['path']);
1088 foreach ($spec as $type => $paths) {
1089 if (is_numeric($type) && is_array($paths)) {
1091 if (isset($paths['prefix']) && isset($paths['path'])) {
1092 if (isset($paths['type'])) {
1093 $type = $paths['type'];
1095 $this->addPrefixPath($paths['prefix'], $paths['path'], $type);
1097 } elseif (!is_numeric($type)) {
1098 if (!isset($paths['prefix']) ||
!isset($paths['path'])) {
1099 foreach ($paths as $prefix => $spec) {
1100 if (is_array($spec)) {
1101 foreach ($spec as $path) {
1102 if (!is_string($path)) {
1105 $this->addPrefixPath($prefix, $path, $type);
1107 } elseif (is_string($spec)) {
1108 $this->addPrefixPath($prefix, $spec, $type);
1112 $this->addPrefixPath($paths['prefix'], $paths['path'], $type);
1122 * Add validator to validation chain
1124 * Note: will overwrite existing validators if they are of the same class.
1126 * @param string|Zend_Validate_Interface $validator
1127 * @param bool $breakChainOnFailure
1128 * @param array $options
1129 * @return Zend_Form_Element
1130 * @throws Zend_Form_Exception if invalid validator type
1132 public function addValidator($validator, $breakChainOnFailure = false, $options = array())
1134 if ($validator instanceof Zend_Validate_Interface
) {
1135 $name = get_class($validator);
1137 if (!isset($validator->zfBreakChainOnFailure
)) {
1138 $validator->zfBreakChainOnFailure
= $breakChainOnFailure;
1140 } elseif (is_string($validator)) {
1143 'validator' => $validator,
1144 'breakChainOnFailure' => $breakChainOnFailure,
1145 'options' => $options,
1148 require_once 'Zend/Form/Exception.php';
1149 throw new Zend_Form_Exception('Invalid validator provided to addValidator; must be string or Zend_Validate_Interface');
1153 $this->_validators
[$name] = $validator;
1159 * Add multiple validators
1161 * @param array $validators
1162 * @return Zend_Form_Element
1164 public function addValidators(array $validators)
1166 foreach ($validators as $validatorInfo) {
1167 if (is_string($validatorInfo)) {
1168 $this->addValidator($validatorInfo);
1169 } elseif ($validatorInfo instanceof Zend_Validate_Interface
) {
1170 $this->addValidator($validatorInfo);
1171 } elseif (is_array($validatorInfo)) {
1172 $argc = count($validatorInfo);
1173 $breakChainOnFailure = false;
1175 if (isset($validatorInfo['validator'])) {
1176 $validator = $validatorInfo['validator'];
1177 if (isset($validatorInfo['breakChainOnFailure'])) {
1178 $breakChainOnFailure = $validatorInfo['breakChainOnFailure'];
1180 if (isset($validatorInfo['options'])) {
1181 $options = $validatorInfo['options'];
1183 $this->addValidator($validator, $breakChainOnFailure, $options);
1189 $validator = array_shift($validatorInfo);
1191 $breakChainOnFailure = array_shift($validatorInfo);
1193 $options = array_shift($validatorInfo);
1195 $this->addValidator($validator, $breakChainOnFailure, $options);
1200 require_once 'Zend/Form/Exception.php';
1201 throw new Zend_Form_Exception('Invalid validator passed to addValidators()');
1209 * Set multiple validators, overwriting previous validators
1211 * @param array $validators
1212 * @return Zend_Form_Element
1214 public function setValidators(array $validators)
1216 $this->clearValidators();
1217 return $this->addValidators($validators);
1221 * Retrieve a single validator by name
1223 * @param string $name
1224 * @return Zend_Validate_Interface|false False if not found, validator otherwise
1226 public function getValidator($name)
1228 if (!isset($this->_validators
[$name])) {
1229 $len = strlen($name);
1230 foreach ($this->_validators
as $localName => $validator) {
1231 if ($len > strlen($localName)) {
1234 if (0 === substr_compare($localName, $name, -$len, $len, true)) {
1235 if (is_array($validator)) {
1236 return $this->_loadValidator($validator);
1244 if (is_array($this->_validators
[$name])) {
1245 return $this->_loadValidator($this->_validators
[$name]);
1248 return $this->_validators
[$name];
1252 * Retrieve all validators
1256 public function getValidators()
1258 $validators = array();
1259 foreach ($this->_validators
as $key => $value) {
1260 if ($value instanceof Zend_Validate_Interface
) {
1261 $validators[$key] = $value;
1264 $validator = $this->_loadValidator($value);
1265 $validators[get_class($validator)] = $validator;
1271 * Remove a single validator by name
1273 * @param string $name
1276 public function removeValidator($name)
1278 if (isset($this->_validators
[$name])) {
1279 unset($this->_validators
[$name]);
1281 $len = strlen($name);
1282 foreach (array_keys($this->_validators
) as $validator) {
1283 if ($len > strlen($validator)) {
1286 if (0 === substr_compare($validator, $name, -$len, $len, true)) {
1287 unset($this->_validators
[$validator]);
1297 * Clear all validators
1299 * @return Zend_Form_Element
1301 public function clearValidators()
1303 $this->_validators
= array();
1308 * Validate element value
1310 * If a translation adapter is registered, any error messages will be
1311 * translated according to the current locale, using the given error code;
1312 * if no matching translation is found, the original message will be
1315 * Note: The *filtered* value is validated.
1317 * @param mixed $value
1318 * @param mixed $context
1321 public function isValid($value, $context = null)
1323 $this->setValue($value);
1324 $value = $this->getValue();
1326 if ((('' === $value) ||
(null === $value))
1327 && !$this->isRequired()
1328 && $this->getAllowEmpty()
1333 if ($this->isRequired()
1334 && $this->autoInsertNotEmptyValidator()
1335 && !$this->getValidator('NotEmpty'))
1337 $validators = $this->getValidators();
1338 $notEmpty = array('validator' => 'NotEmpty', 'breakChainOnFailure' => true);
1339 array_unshift($validators, $notEmpty);
1340 $this->setValidators($validators);
1343 // Find the correct translator. Zend_Validate_Abstract::getDefaultTranslator()
1344 // will get either the static translator attached to Zend_Validate_Abstract
1345 // or the 'Zend_Translate' from Zend_Registry.
1346 if (Zend_Validate_Abstract
::hasDefaultTranslator() &&
1347 !Zend_Form
::hasDefaultTranslator())
1349 $translator = Zend_Validate_Abstract
::getDefaultTranslator();
1350 if ($this->hasTranslator()) {
1351 // only pick up this element's translator if it was attached directly.
1352 $translator = $this->getTranslator();
1355 $translator = $this->getTranslator();
1358 $this->_messages
= array();
1359 $this->_errors
= array();
1361 $isArray = $this->isArray();
1362 foreach ($this->getValidators() as $key => $validator) {
1363 if (method_exists($validator, 'setTranslator')) {
1364 if (method_exists($validator, 'hasTranslator')) {
1365 if (!$validator->hasTranslator()) {
1366 $validator->setTranslator($translator);
1369 $validator->setTranslator($translator);
1373 if (method_exists($validator, 'setDisableTranslator')) {
1374 $validator->setDisableTranslator($this->translatorIsDisabled());
1377 if ($isArray && is_array($value)) {
1378 $messages = array();
1380 foreach ($value as $val) {
1381 if (!$validator->isValid($val, $context)) {
1383 if ($this->_hasErrorMessages()) {
1384 $messages = $this->_getErrorMessages();
1385 $errors = $messages;
1387 $messages = array_merge($messages, $validator->getMessages());
1388 $errors = array_merge($errors, $validator->getErrors());
1395 } elseif ($validator->isValid($value, $context)) {
1399 if ($this->_hasErrorMessages()) {
1400 $messages = $this->_getErrorMessages();
1401 $errors = $messages;
1403 $messages = $validator->getMessages();
1404 $errors = array_keys($messages);
1409 $this->_messages
= array_merge($this->_messages
, $messages);
1410 $this->_errors
= array_merge($this->_errors
, $errors);
1412 if ($validator->zfBreakChainOnFailure
) {
1417 // If element manually flagged as invalid, return false
1418 if ($this->_isErrorForced
) {
1426 * Add a custom error message to return in the event of failed validation
1428 * @param string $message
1429 * @return Zend_Form_Element
1431 public function addErrorMessage($message)
1433 $this->_errorMessages
[] = (string) $message;
1438 * Add multiple custom error messages to return in the event of failed validation
1440 * @param array $messages
1441 * @return Zend_Form_Element
1443 public function addErrorMessages(array $messages)
1445 foreach ($messages as $message) {
1446 $this->addErrorMessage($message);
1452 * Same as addErrorMessages(), but clears custom error message stack first
1454 * @param array $messages
1455 * @return Zend_Form_Element
1457 public function setErrorMessages(array $messages)
1459 $this->clearErrorMessages();
1460 return $this->addErrorMessages($messages);
1464 * Retrieve custom error messages
1468 public function getErrorMessages()
1470 return $this->_errorMessages
;
1474 * Clear custom error messages stack
1476 * @return Zend_Form_Element
1478 public function clearErrorMessages()
1480 $this->_errorMessages
= array();
1485 * Get errorMessageSeparator
1489 public function getErrorMessageSeparator()
1491 return $this->_errorMessageSeparator
;
1495 * Set errorMessageSeparator
1497 * @param string $separator
1498 * @return Zend_Form_Element
1500 public function setErrorMessageSeparator($separator)
1502 $this->_errorMessageSeparator
= $separator;
1507 * Mark the element as being in a failed validation state
1509 * @return Zend_Form_Element
1511 public function markAsError()
1513 $messages = $this->getMessages();
1514 $customMessages = $this->_getErrorMessages();
1515 $messages = $messages +
$customMessages;
1516 if (empty($messages)) {
1517 $this->_isError
= true;
1519 $this->_messages
= $messages;
1521 $this->_isErrorForced
= true;
1526 * Add an error message and mark element as failed validation
1528 * @param string $message
1529 * @return Zend_Form_Element
1531 public function addError($message)
1533 $this->addErrorMessage($message);
1534 $this->markAsError();
1539 * Add multiple error messages and flag element as failed validation
1541 * @param array $messages
1542 * @return Zend_Form_Element
1544 public function addErrors(array $messages)
1546 foreach ($messages as $message) {
1547 $this->addError($message);
1553 * Overwrite any previously set error messages and flag as failed validation
1555 * @param array $messages
1556 * @return Zend_Form_Element
1558 public function setErrors(array $messages)
1560 $this->clearErrorMessages();
1561 return $this->addErrors($messages);
1565 * Are there errors registered?
1569 public function hasErrors()
1571 return (!empty($this->_messages
) ||
$this->_isError
);
1575 * Retrieve validator chain errors
1579 public function getErrors()
1581 return $this->_errors
;
1585 * Retrieve error messages
1589 public function getMessages()
1591 return $this->_messages
;
1598 * Add a filter to the element
1600 * @param string|Zend_Filter_Interface $filter
1601 * @return Zend_Form_Element
1603 public function addFilter($filter, $options = array())
1605 if ($filter instanceof Zend_Filter_Interface
) {
1606 $name = get_class($filter);
1607 } elseif (is_string($filter)) {
1610 'filter' => $filter,
1611 'options' => $options,
1613 $this->_filters
[$name] = $filter;
1615 require_once 'Zend/Form/Exception.php';
1616 throw new Zend_Form_Exception('Invalid filter provided to addFilter; must be string or Zend_Filter_Interface');
1619 $this->_filters
[$name] = $filter;
1625 * Add filters to element
1627 * @param array $filters
1628 * @return Zend_Form_Element
1630 public function addFilters(array $filters)
1632 foreach ($filters as $filterInfo) {
1633 if (is_string($filterInfo)) {
1634 $this->addFilter($filterInfo);
1635 } elseif ($filterInfo instanceof Zend_Filter_Interface
) {
1636 $this->addFilter($filterInfo);
1637 } elseif (is_array($filterInfo)) {
1638 $argc = count($filterInfo);
1640 if (isset($filterInfo['filter'])) {
1641 $filter = $filterInfo['filter'];
1642 if (isset($filterInfo['options'])) {
1643 $options = $filterInfo['options'];
1645 $this->addFilter($filter, $options);
1651 $filter = array_shift($filterInfo);
1653 $options = array_shift($filterInfo);
1655 $this->addFilter($filter, $options);
1660 require_once 'Zend/Form/Exception.php';
1661 throw new Zend_Form_Exception('Invalid filter passed to addFilters()');
1669 * Add filters to element, overwriting any already existing
1671 * @param array $filters
1672 * @return Zend_Form_Element
1674 public function setFilters(array $filters)
1676 $this->clearFilters();
1677 return $this->addFilters($filters);
1681 * Retrieve a single filter by name
1683 * @param string $name
1684 * @return Zend_Filter_Interface
1686 public function getFilter($name)
1688 if (!isset($this->_filters
[$name])) {
1689 $len = strlen($name);
1690 foreach ($this->_filters
as $localName => $filter) {
1691 if ($len > strlen($localName)) {
1695 if (0 === substr_compare($localName, $name, -$len, $len, true)) {
1696 if (is_array($filter)) {
1697 return $this->_loadFilter($filter);
1705 if (is_array($this->_filters
[$name])) {
1706 return $this->_loadFilter($this->_filters
[$name]);
1709 return $this->_filters
[$name];
1717 public function getFilters()
1720 foreach ($this->_filters
as $key => $value) {
1721 if ($value instanceof Zend_Filter_Interface
) {
1722 $filters[$key] = $value;
1725 $filter = $this->_loadFilter($value);
1726 $filters[get_class($filter)] = $filter;
1732 * Remove a filter by name
1734 * @param string $name
1735 * @return Zend_Form_Element
1737 public function removeFilter($name)
1739 if (isset($this->_filters
[$name])) {
1740 unset($this->_filters
[$name]);
1742 $len = strlen($name);
1743 foreach (array_keys($this->_filters
) as $filter) {
1744 if ($len > strlen($filter)) {
1747 if (0 === substr_compare($filter, $name, -$len, $len, true)) {
1748 unset($this->_filters
[$filter]);
1760 * @return Zend_Form_Element
1762 public function clearFilters()
1764 $this->_filters
= array();
1773 * @param Zend_View_Interface $view
1774 * @return Zend_Form_Element
1776 public function setView(Zend_View_Interface
$view = null)
1778 $this->_view
= $view;
1783 * Retrieve view object
1785 * Retrieves from ViewRenderer if none previously set.
1787 * @return null|Zend_View_Interface
1789 public function getView()
1791 if (null === $this->_view
) {
1792 require_once 'Zend/Controller/Action/HelperBroker.php';
1793 $viewRenderer = Zend_Controller_Action_HelperBroker
::getStaticHelper('viewRenderer');
1794 $this->setView($viewRenderer->view
);
1796 return $this->_view
;
1800 * Instantiate a decorator based on class name or class name fragment
1802 * @param string $name
1803 * @param null|array $options
1804 * @return Zend_Form_Decorator_Interface
1806 protected function _getDecorator($name, $options)
1808 $class = $this->getPluginLoader(self
::DECORATOR
)->load($name);
1809 if (null === $options) {
1810 $decorator = new $class;
1812 $decorator = new $class($options);
1819 * Add a decorator for rendering the element
1821 * @param string|Zend_Form_Decorator_Interface $decorator
1822 * @param array|Zend_Config $options Options with which to initialize decorator
1823 * @return Zend_Form_Element
1825 public function addDecorator($decorator, $options = null)
1827 if ($decorator instanceof Zend_Form_Decorator_Interface
) {
1828 $name = get_class($decorator);
1829 } elseif (is_string($decorator)) {
1832 'decorator' => $name,
1833 'options' => $options,
1835 } elseif (is_array($decorator)) {
1836 foreach ($decorator as $name => $spec) {
1839 if (is_numeric($name)) {
1840 require_once 'Zend/Form/Exception.php';
1841 throw new Zend_Form_Exception('Invalid alias provided to addDecorator; must be alphanumeric string');
1843 if (is_string($spec)) {
1845 'decorator' => $spec,
1846 'options' => $options,
1848 } elseif ($spec instanceof Zend_Form_Decorator_Interface
) {
1852 require_once 'Zend/Form/Exception.php';
1853 throw new Zend_Form_Exception('Invalid decorator provided to addDecorator; must be string or Zend_Form_Decorator_Interface');
1856 $this->_decorators
[$name] = $decorator;
1862 * Add many decorators at once
1864 * @param array $decorators
1865 * @return Zend_Form_Element
1867 public function addDecorators(array $decorators)
1869 foreach ($decorators as $decoratorName => $decoratorInfo) {
1870 if (is_string($decoratorInfo) ||
1871 $decoratorInfo instanceof Zend_Form_Decorator_Interface
) {
1872 if (!is_numeric($decoratorName)) {
1873 $this->addDecorator(array($decoratorName => $decoratorInfo));
1875 $this->addDecorator($decoratorInfo);
1877 } elseif (is_array($decoratorInfo)) {
1878 $argc = count($decoratorInfo);
1880 if (isset($decoratorInfo['decorator'])) {
1881 $decorator = $decoratorInfo['decorator'];
1882 if (isset($decoratorInfo['options'])) {
1883 $options = $decoratorInfo['options'];
1885 $this->addDecorator($decorator, $options);
1891 $decorator = array_shift($decoratorInfo);
1893 $options = array_shift($decoratorInfo);
1895 $this->addDecorator($decorator, $options);
1900 require_once 'Zend/Form/Exception.php';
1901 throw new Zend_Form_Exception('Invalid decorator passed to addDecorators()');
1909 * Overwrite all decorators
1911 * @param array $decorators
1912 * @return Zend_Form_Element
1914 public function setDecorators(array $decorators)
1916 $this->clearDecorators();
1917 return $this->addDecorators($decorators);
1921 * Retrieve a registered decorator
1923 * @param string $name
1924 * @return false|Zend_Form_Decorator_Abstract
1926 public function getDecorator($name)
1928 if (!isset($this->_decorators
[$name])) {
1929 $len = strlen($name);
1930 foreach ($this->_decorators
as $localName => $decorator) {
1931 if ($len > strlen($localName)) {
1935 if (0 === substr_compare($localName, $name, -$len, $len, true)) {
1936 if (is_array($decorator)) {
1937 return $this->_loadDecorator($decorator, $localName);
1945 if (is_array($this->_decorators
[$name])) {
1946 return $this->_loadDecorator($this->_decorators
[$name], $name);
1949 return $this->_decorators
[$name];
1953 * Retrieve all decorators
1957 public function getDecorators()
1959 foreach ($this->_decorators
as $key => $value) {
1960 if (is_array($value)) {
1961 $this->_loadDecorator($value, $key);
1964 return $this->_decorators
;
1968 * Remove a single decorator
1970 * @param string $name
1971 * @return Zend_Form_Element
1973 public function removeDecorator($name)
1975 if (isset($this->_decorators
[$name])) {
1976 unset($this->_decorators
[$name]);
1978 $len = strlen($name);
1979 foreach (array_keys($this->_decorators
) as $decorator) {
1980 if ($len > strlen($decorator)) {
1983 if (0 === substr_compare($decorator, $name, -$len, $len, true)) {
1984 unset($this->_decorators
[$decorator]);
1994 * Clear all decorators
1996 * @return Zend_Form_Element
1998 public function clearDecorators()
2000 $this->_decorators
= array();
2005 * Render form element
2007 * @param Zend_View_Interface $view
2010 public function render(Zend_View_Interface
$view = null)
2012 if ($this->_isPartialRendering
) {
2016 if (null !== $view) {
2017 $this->setView($view);
2021 foreach ($this->getDecorators() as $decorator) {
2022 $decorator->setElement($this);
2023 $content = $decorator->render($content);
2029 * String representation of form element
2031 * Proxies to {@link render()}.
2035 public function __toString()
2038 $return = $this->render();
2040 } catch (Exception
$e) {
2041 trigger_error($e->getMessage(), E_USER_WARNING
);
2047 * Lazy-load a filter
2049 * @param array $filter
2050 * @return Zend_Filter_Interface
2052 protected function _loadFilter(array $filter)
2054 $origName = $filter['filter'];
2055 $name = $this->getPluginLoader(self
::FILTER
)->load($filter['filter']);
2057 if (array_key_exists($name, $this->_filters
)) {
2058 require_once 'Zend/Form/Exception.php';
2059 throw new Zend_Form_Exception(sprintf('Filter instance already exists for filter "%s"', $origName));
2062 if (empty($filter['options'])) {
2063 $instance = new $name;
2065 $r = new ReflectionClass($name);
2066 if ($r->hasMethod('__construct')) {
2067 $instance = $r->newInstanceArgs((array) $filter['options']);
2069 $instance = $r->newInstance();
2073 if ($origName != $name) {
2074 $filterNames = array_keys($this->_filters
);
2075 $order = array_flip($filterNames);
2076 $order[$name] = $order[$origName];
2077 $filtersExchange = array();
2078 unset($order[$origName]);
2080 foreach ($order as $key => $index) {
2081 if ($key == $name) {
2082 $filtersExchange[$key] = $instance;
2085 $filtersExchange[$key] = $this->_filters
[$key];
2087 $this->_filters
= $filtersExchange;
2089 $this->_filters
[$name] = $instance;
2096 * Lazy-load a validator
2098 * @param array $validator Validator definition
2099 * @return Zend_Validate_Interface
2101 protected function _loadValidator(array $validator)
2103 $origName = $validator['validator'];
2104 $name = $this->getPluginLoader(self
::VALIDATE
)->load($validator['validator']);
2106 if (array_key_exists($name, $this->_validators
)) {
2107 require_once 'Zend/Form/Exception.php';
2108 throw new Zend_Form_Exception(sprintf('Validator instance already exists for validator "%s"', $origName));
2112 if (isset($validator['options']) && array_key_exists('messages', (array)$validator['options'])) {
2113 $messages = $validator['options']['messages'];
2114 unset($validator['options']['messages']);
2117 if (empty($validator['options'])) {
2118 $instance = new $name;
2120 $r = new ReflectionClass($name);
2121 if ($r->hasMethod('__construct')) {
2123 if (is_array($validator['options'])) {
2124 $keys = array_keys($validator['options']);
2125 foreach($keys as $key) {
2126 if (is_numeric($key)) {
2134 $instance = $r->newInstanceArgs((array) $validator['options']);
2136 $instance = $r->newInstance($validator['options']);
2139 $instance = $r->newInstance();
2144 if (is_array($messages)) {
2145 $instance->setMessages($messages);
2146 } elseif (is_string($messages)) {
2147 $instance->setMessage($messages);
2150 $instance->zfBreakChainOnFailure
= $validator['breakChainOnFailure'];
2152 if ($origName != $name) {
2153 $validatorNames = array_keys($this->_validators
);
2154 $order = array_flip($validatorNames);
2155 $order[$name] = $order[$origName];
2156 $validatorsExchange = array();
2157 unset($order[$origName]);
2159 foreach ($order as $key => $index) {
2160 if ($key == $name) {
2161 $validatorsExchange[$key] = $instance;
2164 $validatorsExchange[$key] = $this->_validators
[$key];
2166 $this->_validators
= $validatorsExchange;
2168 $this->_validators
[$name] = $instance;
2175 * Lazy-load a decorator
2177 * @param array $decorator Decorator type and options
2178 * @param mixed $name Decorator name or alias
2179 * @return Zend_Form_Decorator_Interface
2181 protected function _loadDecorator(array $decorator, $name)
2184 if ($name == $decorator['decorator']) {
2188 $instance = $this->_getDecorator($decorator['decorator'], $decorator['options']);
2190 $newName = get_class($instance);
2191 $decoratorNames = array_keys($this->_decorators
);
2192 $order = array_flip($decoratorNames);
2193 $order[$newName] = $order[$name];
2194 $decoratorsExchange = array();
2195 unset($order[$name]);
2197 foreach ($order as $key => $index) {
2198 if ($key == $newName) {
2199 $decoratorsExchange[$key] = $instance;
2202 $decoratorsExchange[$key] = $this->_decorators
[$key];
2204 $this->_decorators
= $decoratorsExchange;
2206 $this->_decorators
[$name] = $instance;
2213 * Retrieve error messages and perform translation and value substitution
2217 protected function _getErrorMessages()
2219 $translator = $this->getTranslator();
2220 $messages = $this->getErrorMessages();
2221 $value = $this->getValue();
2222 foreach ($messages as $key => $message) {
2223 if (null !== $translator) {
2224 $message = $translator->translate($message);
2226 if (($this->isArray() ||
is_array($value))
2229 $aggregateMessages = array();
2230 foreach ($value as $val) {
2231 $aggregateMessages[] = str_replace('%value%', $val, $message);
2233 $messages[$key] = implode($this->getErrorMessageSeparator(), $aggregateMessages);
2235 $messages[$key] = str_replace('%value%', $value, $message);
2242 * Are there custom error messages registered?
2246 protected function _hasErrorMessages()
2248 return !empty($this->_errorMessages
);