File indexing completed on 2024-12-22 05:37:16
0001 <?php 0002 /** 0003 * Zend Framework 0004 * 0005 * LICENSE 0006 * 0007 * This source file is subject to the new BSD license that is bundled 0008 * with this package in the file LICENSE.txt. 0009 * It is also available through the world-wide-web at this URL: 0010 * http://framework.zend.com/license/new-bsd 0011 * If you did not receive a copy of the license and are unable to 0012 * obtain it through the world-wide-web, please send an email 0013 * to license@zend.com so we can send you a copy immediately. 0014 * 0015 * @category Zend 0016 * @package Zend_Form 0017 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0018 * @license http://framework.zend.com/license/new-bsd New BSD License 0019 */ 0020 0021 /** @see Zend_Validate_Interface */ 0022 // require_once 'Zend/Validate/Interface.php'; 0023 0024 /** 0025 * Zend_Form 0026 * 0027 * @category Zend 0028 * @package Zend_Form 0029 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0030 * @license http://framework.zend.com/license/new-bsd New BSD License 0031 * @version $Id$ 0032 */ 0033 class Zend_Form implements Iterator, Countable, Zend_Validate_Interface 0034 { 0035 /**#@+ 0036 * Plugin loader type constants 0037 */ 0038 const DECORATOR = 'DECORATOR'; 0039 const ELEMENT = 'ELEMENT'; 0040 /**#@-*/ 0041 0042 /**#@+ 0043 * Method type constants 0044 */ 0045 const METHOD_DELETE = 'delete'; 0046 const METHOD_GET = 'get'; 0047 const METHOD_POST = 'post'; 0048 const METHOD_PUT = 'put'; 0049 /**#@-*/ 0050 0051 /**#@+ 0052 * Encoding type constants 0053 */ 0054 const ENCTYPE_URLENCODED = 'application/x-www-form-urlencoded'; 0055 const ENCTYPE_MULTIPART = 'multipart/form-data'; 0056 /**#@-*/ 0057 0058 /** 0059 * Form metadata and attributes 0060 * @var array 0061 */ 0062 protected $_attribs = array(); 0063 0064 /** 0065 * Decorators for rendering 0066 * @var array 0067 */ 0068 protected $_decorators = array(); 0069 0070 /** 0071 * Default display group class 0072 * @var string 0073 */ 0074 protected $_defaultDisplayGroupClass = 'Zend_Form_DisplayGroup'; 0075 0076 /** 0077 * Form description 0078 * @var string 0079 */ 0080 protected $_description; 0081 0082 /** 0083 * Should we disable loading the default decorators? 0084 * @var bool 0085 */ 0086 protected $_disableLoadDefaultDecorators = false; 0087 0088 /** 0089 * Display group prefix paths 0090 * @var array 0091 */ 0092 protected $_displayGroupPrefixPaths = array(); 0093 0094 /** 0095 * Groups of elements grouped for display purposes 0096 * @var array 0097 */ 0098 protected $_displayGroups = array(); 0099 0100 /** 0101 * Global decorators to apply to all elements 0102 * @var null|array 0103 */ 0104 protected $_elementDecorators; 0105 0106 /** 0107 * Prefix paths to use when creating elements 0108 * @var array 0109 */ 0110 protected $_elementPrefixPaths = array(); 0111 0112 /** 0113 * Form elements 0114 * @var array 0115 */ 0116 protected $_elements = array(); 0117 0118 /** 0119 * Array to which elements belong (if any) 0120 * @var string 0121 */ 0122 protected $_elementsBelongTo; 0123 0124 /** 0125 * Custom form-level error messages 0126 * @var array 0127 */ 0128 protected $_errorMessages = array(); 0129 0130 /** 0131 * Are there errors in the form? 0132 * @var bool 0133 */ 0134 protected $_errorsExist = false; 0135 0136 /** 0137 * Has the form been manually flagged as an error? 0138 * @var bool 0139 */ 0140 protected $_errorsForced = false; 0141 0142 /** 0143 * Form order 0144 * @var int|null 0145 */ 0146 protected $_formOrder; 0147 0148 /** 0149 * Whether or not form elements are members of an array 0150 * @var bool 0151 */ 0152 protected $_isArray = false; 0153 0154 /** 0155 * Form legend 0156 * @var string 0157 */ 0158 protected $_legend; 0159 0160 /** 0161 * Plugin loaders 0162 * @var array 0163 */ 0164 protected $_loaders = array(); 0165 0166 /** 0167 * Allowed form methods 0168 * @var array 0169 */ 0170 protected $_methods = array('delete', 'get', 'post', 'put'); 0171 0172 /** 0173 * Order in which to display and iterate elements 0174 * @var array 0175 */ 0176 protected $_order = array(); 0177 0178 /** 0179 * Whether internal order has been updated or not 0180 * @var bool 0181 */ 0182 protected $_orderUpdated = false; 0183 0184 /** 0185 * Sub form prefix paths 0186 * @var array 0187 */ 0188 protected $_subFormPrefixPaths = array(); 0189 0190 /** 0191 * Sub forms 0192 * @var array 0193 */ 0194 protected $_subForms = array(); 0195 0196 /** 0197 * @var Zend_Translate 0198 */ 0199 protected $_translator; 0200 0201 /** 0202 * Global default translation adapter 0203 * @var Zend_Translate 0204 */ 0205 protected static $_translatorDefault; 0206 0207 /** 0208 * is the translator disabled? 0209 * @var bool 0210 */ 0211 protected $_translatorDisabled = false; 0212 0213 /** 0214 * @var Zend_View_Interface 0215 */ 0216 protected $_view; 0217 0218 /** 0219 * @var bool 0220 */ 0221 protected $_isRendered = false; 0222 0223 /** 0224 * Constructor 0225 * 0226 * Registers form view helper as decorator 0227 * 0228 * @param mixed $options 0229 */ 0230 public function __construct($options = null) 0231 { 0232 if (is_array($options)) { 0233 $this->setOptions($options); 0234 } elseif ($options instanceof Zend_Config) { 0235 $this->setConfig($options); 0236 } 0237 0238 // Extensions... 0239 $this->init(); 0240 0241 $this->loadDefaultDecorators(); 0242 } 0243 0244 /** 0245 * Clone form object and all children 0246 * 0247 * @return void 0248 */ 0249 public function __clone() 0250 { 0251 $elements = array(); 0252 foreach ($this->getElements() as $name => $element) { 0253 $elements[] = clone $element; 0254 } 0255 $this->setElements($elements); 0256 0257 $subForms = array(); 0258 foreach ($this->getSubForms() as $name => $subForm) { 0259 $subForms[$name] = clone $subForm; 0260 } 0261 $this->setSubForms($subForms); 0262 0263 $displayGroups = array(); 0264 foreach ($this->_displayGroups as $group) { 0265 /** @var Zend_Form_DisplayGroup $clone */ 0266 $clone = clone $group; 0267 $elements = array(); 0268 foreach ($clone->getElements() as $name => $e) { 0269 $elements[] = $this->getElement($name); 0270 } 0271 $clone->setElements($elements); 0272 $displayGroups[] = $clone; 0273 } 0274 $this->setDisplayGroups($displayGroups); 0275 } 0276 0277 /** 0278 * Reset values of form 0279 * 0280 * @return Zend_Form 0281 */ 0282 public function reset() 0283 { 0284 /** @var Zend_Form_Element $element */ 0285 foreach ($this->getElements() as $element) { 0286 $element->setValue(null); 0287 } 0288 /** @var Zend_Form_SubForm $subForm */ 0289 foreach ($this->getSubForms() as $subForm) { 0290 $subForm->reset(); 0291 } 0292 0293 return $this; 0294 } 0295 0296 /** 0297 * Initialize form (used by extending classes) 0298 * 0299 * @return void 0300 */ 0301 public function init() 0302 { 0303 } 0304 0305 /** 0306 * Set form state from options array 0307 * 0308 * @param array $options 0309 * @return Zend_Form 0310 */ 0311 public function setOptions(array $options) 0312 { 0313 if (isset($options['prefixPath'])) { 0314 $this->addPrefixPaths($options['prefixPath']); 0315 unset($options['prefixPath']); 0316 } 0317 0318 if (isset($options['elementPrefixPath'])) { 0319 $this->addElementPrefixPaths($options['elementPrefixPath']); 0320 unset($options['elementPrefixPath']); 0321 } 0322 0323 if (isset($options['displayGroupPrefixPath'])) { 0324 $this->addDisplayGroupPrefixPaths($options['displayGroupPrefixPath']); 0325 unset($options['displayGroupPrefixPath']); 0326 } 0327 0328 if (isset($options['elementDecorators'])) { 0329 $this->_elementDecorators = $options['elementDecorators']; 0330 unset($options['elementDecorators']); 0331 } 0332 0333 if (isset($options['elements'])) { 0334 $this->setElements($options['elements']); 0335 unset($options['elements']); 0336 } 0337 0338 if (isset($options['defaultDisplayGroupClass'])) { 0339 $this->setDefaultDisplayGroupClass($options['defaultDisplayGroupClass']); 0340 unset($options['defaultDisplayGroupClass']); 0341 } 0342 0343 if (isset($options['displayGroupDecorators'])) { 0344 $displayGroupDecorators = $options['displayGroupDecorators']; 0345 unset($options['displayGroupDecorators']); 0346 } 0347 0348 if (isset($options['elementsBelongTo'])) { 0349 $elementsBelongTo = $options['elementsBelongTo']; 0350 unset($options['elementsBelongTo']); 0351 } 0352 0353 if (isset($options['attribs'])) { 0354 $this->addAttribs($options['attribs']); 0355 unset($options['attribs']); 0356 } 0357 0358 if (isset($options['subForms'])) { 0359 $this->addSubForms($options['subForms']); 0360 unset($options['subForms']); 0361 } 0362 0363 $forbidden = array( 0364 'Options', 'Config', 'PluginLoader', 'SubForms', 'Translator', 0365 'Attrib', 'Default', 0366 ); 0367 0368 foreach ($options as $key => $value) { 0369 $normalized = ucfirst($key); 0370 if (in_array($normalized, $forbidden)) { 0371 continue; 0372 } 0373 0374 $method = 'set' . $normalized; 0375 if (method_exists($this, $method)) { 0376 if($normalized == 'View' && !($value instanceof Zend_View_Interface)) { 0377 continue; 0378 } 0379 $this->$method($value); 0380 } else { 0381 $this->setAttrib($key, $value); 0382 } 0383 } 0384 0385 if (isset($displayGroupDecorators)) { 0386 $this->setDisplayGroupDecorators($displayGroupDecorators); 0387 } 0388 0389 if (isset($elementsBelongTo)) { 0390 $this->setElementsBelongTo($elementsBelongTo); 0391 } 0392 0393 return $this; 0394 } 0395 0396 /** 0397 * Set form state from config object 0398 * 0399 * @param Zend_Config $config 0400 * @return Zend_Form 0401 */ 0402 public function setConfig(Zend_Config $config) 0403 { 0404 return $this->setOptions($config->toArray()); 0405 } 0406 0407 0408 // Loaders 0409 0410 /** 0411 * Set plugin loaders for use with decorators and elements 0412 * 0413 * @param Zend_Loader_PluginLoader_Interface $loader 0414 * @param string $type 'decorator' or 'element' 0415 * @return Zend_Form 0416 * @throws Zend_Form_Exception on invalid type 0417 */ 0418 public function setPluginLoader(Zend_Loader_PluginLoader_Interface $loader, $type = null) 0419 { 0420 $type = strtoupper($type); 0421 switch ($type) { 0422 case self::DECORATOR: 0423 case self::ELEMENT: 0424 $this->_loaders[$type] = $loader; 0425 return $this; 0426 default: 0427 // require_once 'Zend/Form/Exception.php'; 0428 throw new Zend_Form_Exception(sprintf('Invalid type "%s" provided to setPluginLoader()', $type)); 0429 } 0430 } 0431 0432 /** 0433 * Retrieve plugin loader for given type 0434 * 0435 * $type may be one of: 0436 * - decorator 0437 * - element 0438 * 0439 * If a plugin loader does not exist for the given type, defaults are 0440 * created. 0441 * 0442 * @param string $type 0443 * @return Zend_Loader_PluginLoader_Interface 0444 * @throws Zend_Form_Exception 0445 */ 0446 public function getPluginLoader($type = null) 0447 { 0448 $type = strtoupper($type); 0449 if (!isset($this->_loaders[$type])) { 0450 switch ($type) { 0451 case self::DECORATOR: 0452 $prefixSegment = 'Form_Decorator'; 0453 $pathSegment = 'Form/Decorator'; 0454 break; 0455 case self::ELEMENT: 0456 $prefixSegment = 'Form_Element'; 0457 $pathSegment = 'Form/Element'; 0458 break; 0459 default: 0460 // require_once 'Zend/Form/Exception.php'; 0461 throw new Zend_Form_Exception(sprintf('Invalid type "%s" provided to getPluginLoader()', $type)); 0462 } 0463 0464 // require_once 'Zend/Loader/PluginLoader.php'; 0465 $this->_loaders[$type] = new Zend_Loader_PluginLoader( 0466 array('Zend_' . $prefixSegment . '_' => 'Zend/' . $pathSegment . '/') 0467 ); 0468 } 0469 0470 return $this->_loaders[$type]; 0471 } 0472 0473 /** 0474 * Add prefix path for plugin loader 0475 * 0476 * If no $type specified, assumes it is a base path for both filters and 0477 * validators, and sets each according to the following rules: 0478 * - decorators: $prefix = $prefix . '_Decorator' 0479 * - elements: $prefix = $prefix . '_Element' 0480 * 0481 * Otherwise, the path prefix is set on the appropriate plugin loader. 0482 * 0483 * If $type is 'decorator', sets the path in the decorator plugin loader 0484 * for all elements. Additionally, if no $type is provided, 0485 * the prefix and path is added to both decorator and element 0486 * plugin loader with following settings: 0487 * $prefix . '_Decorator', $path . '/Decorator/' 0488 * $prefix . '_Element', $path . '/Element/' 0489 * 0490 * @param string $prefix 0491 * @param string $path 0492 * @param string $type 0493 * @return Zend_Form 0494 * @throws Zend_Form_Exception for invalid type 0495 */ 0496 public function addPrefixPath($prefix, $path, $type = null) 0497 { 0498 $type = strtoupper($type); 0499 switch ($type) { 0500 case self::DECORATOR: 0501 case self::ELEMENT: 0502 $loader = $this->getPluginLoader($type); 0503 $loader->addPrefixPath($prefix, $path); 0504 return $this; 0505 case null: 0506 $nsSeparator = (false !== strpos($prefix, '\\'))?'\\':'_'; 0507 $prefix = rtrim($prefix, $nsSeparator); 0508 $path = rtrim($path, DIRECTORY_SEPARATOR); 0509 foreach (array(self::DECORATOR, self::ELEMENT) as $type) { 0510 $cType = ucfirst(strtolower($type)); 0511 $pluginPath = $path . DIRECTORY_SEPARATOR . $cType . DIRECTORY_SEPARATOR; 0512 $pluginPrefix = $prefix . $nsSeparator . $cType; 0513 $loader = $this->getPluginLoader($type); 0514 $loader->addPrefixPath($pluginPrefix, $pluginPath); 0515 } 0516 return $this; 0517 default: 0518 // require_once 'Zend/Form/Exception.php'; 0519 throw new Zend_Form_Exception(sprintf('Invalid type "%s" provided to getPluginLoader()', $type)); 0520 } 0521 } 0522 0523 /** 0524 * Add many prefix paths at once 0525 * 0526 * @param array $spec 0527 * @return Zend_Form 0528 */ 0529 public function addPrefixPaths(array $spec) 0530 { 0531 if (isset($spec['prefix']) && isset($spec['path'])) { 0532 return $this->addPrefixPath($spec['prefix'], $spec['path']); 0533 } 0534 foreach ($spec as $type => $paths) { 0535 if (is_numeric($type) && is_array($paths)) { 0536 $type = null; 0537 if (isset($paths['prefix']) && isset($paths['path'])) { 0538 if (isset($paths['type'])) { 0539 $type = $paths['type']; 0540 } 0541 $this->addPrefixPath($paths['prefix'], $paths['path'], $type); 0542 } 0543 } elseif (!is_numeric($type)) { 0544 if (!isset($paths['prefix']) || !isset($paths['path'])) { 0545 continue; 0546 } 0547 $this->addPrefixPath($paths['prefix'], $paths['path'], $type); 0548 } 0549 } 0550 return $this; 0551 } 0552 0553 /** 0554 * Add prefix path for all elements 0555 * 0556 * @param string $prefix 0557 * @param string $path 0558 * @param string $type 0559 * @return Zend_Form 0560 */ 0561 public function addElementPrefixPath($prefix, $path, $type = null) 0562 { 0563 $this->_elementPrefixPaths[] = array( 0564 'prefix' => $prefix, 0565 'path' => $path, 0566 'type' => $type, 0567 ); 0568 0569 /** @var Zend_Form_Element $element */ 0570 foreach ($this->getElements() as $element) { 0571 $element->addPrefixPath($prefix, $path, $type); 0572 } 0573 0574 /** @var Zend_Form_SubForm $subForm */ 0575 foreach ($this->getSubForms() as $subForm) { 0576 $subForm->addElementPrefixPath($prefix, $path, $type); 0577 } 0578 0579 return $this; 0580 } 0581 0582 /** 0583 * Add prefix paths for all elements 0584 * 0585 * @param array $spec 0586 * @return Zend_Form 0587 */ 0588 public function addElementPrefixPaths(array $spec) 0589 { 0590 $this->_elementPrefixPaths = $this->_elementPrefixPaths + $spec; 0591 0592 /** @var Zend_Form_Element $element */ 0593 foreach ($this->getElements() as $element) { 0594 $element->addPrefixPaths($spec); 0595 } 0596 0597 return $this; 0598 } 0599 0600 /** 0601 * Add prefix path for all display groups 0602 * 0603 * @param string $prefix 0604 * @param string $path 0605 * @return Zend_Form 0606 */ 0607 public function addDisplayGroupPrefixPath($prefix, $path) 0608 { 0609 $this->_displayGroupPrefixPaths[] = array( 0610 'prefix' => $prefix, 0611 'path' => $path, 0612 ); 0613 0614 /** @var Zend_Form_DisplayGroup $group */ 0615 foreach ($this->getDisplayGroups() as $group) { 0616 $group->addPrefixPath($prefix, $path); 0617 } 0618 0619 return $this; 0620 } 0621 0622 /** 0623 * Add multiple display group prefix paths at once 0624 * 0625 * @param array $spec 0626 * @return Zend_Form 0627 */ 0628 public function addDisplayGroupPrefixPaths(array $spec) 0629 { 0630 foreach ($spec as $key => $value) { 0631 if (is_string($value) && !is_numeric($key)) { 0632 $this->addDisplayGroupPrefixPath($key, $value); 0633 continue; 0634 } 0635 0636 if (is_string($value) && is_numeric($key)) { 0637 continue; 0638 } 0639 0640 if (is_array($value)) { 0641 $count = count($value); 0642 if (array_keys($value) === range(0, $count - 1)) { 0643 if ($count < 2) { 0644 continue; 0645 } 0646 $prefix = array_shift($value); 0647 $path = array_shift($value); 0648 $this->addDisplayGroupPrefixPath($prefix, $path); 0649 continue; 0650 } 0651 if (array_key_exists('prefix', $value) && array_key_exists('path', $value)) { 0652 $this->addDisplayGroupPrefixPath($value['prefix'], $value['path']); 0653 } 0654 } 0655 } 0656 return $this; 0657 } 0658 0659 // Form metadata: 0660 0661 /** 0662 * Set form attribute 0663 * 0664 * @param string $key 0665 * @param mixed $value 0666 * @return Zend_Form 0667 */ 0668 public function setAttrib($key, $value) 0669 { 0670 $key = (string) $key; 0671 $this->_attribs[$key] = $value; 0672 return $this; 0673 } 0674 0675 /** 0676 * Add multiple form attributes at once 0677 * 0678 * @param array $attribs 0679 * @return Zend_Form 0680 */ 0681 public function addAttribs(array $attribs) 0682 { 0683 foreach ($attribs as $key => $value) { 0684 $this->setAttrib($key, $value); 0685 } 0686 return $this; 0687 } 0688 0689 /** 0690 * Set multiple form attributes at once 0691 * 0692 * Overwrites any previously set attributes. 0693 * 0694 * @param array $attribs 0695 * @return Zend_Form 0696 */ 0697 public function setAttribs(array $attribs) 0698 { 0699 $this->clearAttribs(); 0700 return $this->addAttribs($attribs); 0701 } 0702 0703 /** 0704 * Retrieve a single form attribute 0705 * 0706 * @param string $key 0707 * @return mixed 0708 */ 0709 public function getAttrib($key) 0710 { 0711 $key = (string) $key; 0712 if (!isset($this->_attribs[$key])) { 0713 return null; 0714 } 0715 0716 return $this->_attribs[$key]; 0717 } 0718 0719 /** 0720 * Retrieve all form attributes/metadata 0721 * 0722 * @return array 0723 */ 0724 public function getAttribs() 0725 { 0726 return $this->_attribs; 0727 } 0728 0729 /** 0730 * Remove attribute 0731 * 0732 * @param string $key 0733 * @return bool 0734 */ 0735 public function removeAttrib($key) 0736 { 0737 if (isset($this->_attribs[$key])) { 0738 unset($this->_attribs[$key]); 0739 return true; 0740 } 0741 0742 return false; 0743 } 0744 0745 /** 0746 * Clear all form attributes 0747 * 0748 * @return Zend_Form 0749 */ 0750 public function clearAttribs() 0751 { 0752 $this->_attribs = array(); 0753 return $this; 0754 } 0755 0756 /** 0757 * Set form action 0758 * 0759 * @param string $action 0760 * @return Zend_Form 0761 */ 0762 public function setAction($action) 0763 { 0764 return $this->setAttrib('action', (string) $action); 0765 } 0766 0767 /** 0768 * Get form action 0769 * 0770 * Sets default to '' if not set. 0771 * 0772 * @return string 0773 */ 0774 public function getAction() 0775 { 0776 $action = $this->getAttrib('action'); 0777 if (null === $action) { 0778 $action = ''; 0779 $this->setAction($action); 0780 } 0781 return $action; 0782 } 0783 0784 /** 0785 * Set form method 0786 * 0787 * Only values in {@link $_methods()} allowed 0788 * 0789 * @param string $method 0790 * @return Zend_Form 0791 * @throws Zend_Form_Exception 0792 */ 0793 public function setMethod($method) 0794 { 0795 $method = strtolower($method); 0796 if (!in_array($method, $this->_methods)) { 0797 // require_once 'Zend/Form/Exception.php'; 0798 throw new Zend_Form_Exception(sprintf('"%s" is an invalid form method', $method)); 0799 } 0800 $this->setAttrib('method', $method); 0801 return $this; 0802 } 0803 0804 /** 0805 * Retrieve form method 0806 * 0807 * @return string 0808 */ 0809 public function getMethod() 0810 { 0811 if (null === ($method = $this->getAttrib('method'))) { 0812 $method = self::METHOD_POST; 0813 $this->setAttrib('method', $method); 0814 } 0815 return strtolower($method); 0816 } 0817 0818 /** 0819 * Set encoding type 0820 * 0821 * @param string $value 0822 * @return Zend_Form 0823 */ 0824 public function setEnctype($value) 0825 { 0826 $this->setAttrib('enctype', $value); 0827 return $this; 0828 } 0829 0830 /** 0831 * Get encoding type 0832 * 0833 * @return string 0834 */ 0835 public function getEnctype() 0836 { 0837 if (null === ($enctype = $this->getAttrib('enctype'))) { 0838 $enctype = self::ENCTYPE_URLENCODED; 0839 $this->setAttrib('enctype', $enctype); 0840 } 0841 return $this->getAttrib('enctype'); 0842 } 0843 0844 /** 0845 * Filter a name to only allow valid variable characters 0846 * 0847 * @param string $value 0848 * @param bool $allowBrackets 0849 * @return string 0850 */ 0851 public function filterName($value, $allowBrackets = false) 0852 { 0853 $charset = '^a-zA-Z0-9_\x7f-\xff'; 0854 if ($allowBrackets) { 0855 $charset .= '\[\]'; 0856 } 0857 return preg_replace('/[' . $charset . ']/', '', (string) $value); 0858 } 0859 0860 /** 0861 * Set form name 0862 * 0863 * @param string $name 0864 * @return Zend_Form 0865 * @throws Zend_Form_Exception 0866 */ 0867 public function setName($name) 0868 { 0869 $name = $this->filterName($name); 0870 if ('' === (string)$name) { 0871 // require_once 'Zend/Form/Exception.php'; 0872 throw new Zend_Form_Exception('Invalid name provided; must contain only valid variable characters and be non-empty'); 0873 } 0874 0875 return $this->setAttrib('name', $name); 0876 } 0877 0878 /** 0879 * Get name attribute 0880 * 0881 * @return null|string 0882 */ 0883 public function getName() 0884 { 0885 return $this->getAttrib('name'); 0886 } 0887 0888 /** 0889 * Get fully qualified name 0890 * 0891 * Places name as subitem of array and/or appends brackets. 0892 * 0893 * @return string 0894 */ 0895 public function getFullyQualifiedName() 0896 { 0897 return $this->getName(); 0898 } 0899 0900 /** 0901 * Get element id 0902 * 0903 * @return string 0904 */ 0905 public function getId() 0906 { 0907 if (null !== ($id = $this->getAttrib('id'))) { 0908 return $id; 0909 } 0910 0911 $id = $this->getFullyQualifiedName(); 0912 0913 // Bail early if no array notation detected 0914 if (!strstr($id, '[')) { 0915 return $id; 0916 } 0917 0918 // Strip array notation 0919 if ('[]' == substr($id, -2)) { 0920 $id = substr($id, 0, strlen($id) - 2); 0921 } 0922 $id = str_replace('][', '-', $id); 0923 $id = str_replace(array(']', '['), '-', $id); 0924 $id = trim($id, '-'); 0925 0926 return $id; 0927 } 0928 0929 /** 0930 * Set form legend 0931 * 0932 * @param string $value 0933 * @return Zend_Form 0934 */ 0935 public function setLegend($value) 0936 { 0937 $this->_legend = (string) $value; 0938 return $this; 0939 } 0940 0941 /** 0942 * Get form legend 0943 * 0944 * @return string 0945 */ 0946 public function getLegend() 0947 { 0948 return $this->_legend; 0949 } 0950 0951 /** 0952 * Set form description 0953 * 0954 * @param string $value 0955 * @return Zend_Form 0956 */ 0957 public function setDescription($value) 0958 { 0959 $this->_description = (string) $value; 0960 return $this; 0961 } 0962 0963 /** 0964 * Retrieve form description 0965 * 0966 * @return string 0967 */ 0968 public function getDescription() 0969 { 0970 return $this->_description; 0971 } 0972 0973 /** 0974 * Set form order 0975 * 0976 * @param int $index 0977 * @return Zend_Form 0978 */ 0979 public function setOrder($index) 0980 { 0981 $this->_formOrder = (int) $index; 0982 return $this; 0983 } 0984 0985 /** 0986 * Get form order 0987 * 0988 * @return int|null 0989 */ 0990 public function getOrder() 0991 { 0992 return $this->_formOrder; 0993 } 0994 0995 /** 0996 * When calling renderFormElements or render this method 0997 * is used to set $_isRendered member to prevent repeatedly 0998 * merging belongsTo setting 0999 */ 1000 protected function _setIsRendered() 1001 { 1002 $this->_isRendered = true; 1003 return $this; 1004 } 1005 1006 /** 1007 * Get the value of $_isRendered member 1008 */ 1009 protected function _getIsRendered() 1010 { 1011 return (bool)$this->_isRendered; 1012 } 1013 1014 // Element interaction: 1015 1016 /** 1017 * Add a new element 1018 * 1019 * $element may be either a string element type, or an object of type 1020 * Zend_Form_Element. If a string element type is provided, $name must be 1021 * provided, and $options may be optionally provided for configuring the 1022 * element. 1023 * 1024 * If a Zend_Form_Element is provided, $name may be optionally provided, 1025 * and any provided $options will be ignored. 1026 * 1027 * @param string|Zend_Form_Element $element 1028 * @param string $name 1029 * @param array|Zend_Config $options 1030 * @throws Zend_Form_Exception on invalid element 1031 * @return Zend_Form 1032 */ 1033 public function addElement($element, $name = null, $options = null) 1034 { 1035 if (is_string($element)) { 1036 if (null === $name) { 1037 // require_once 'Zend/Form/Exception.php'; 1038 throw new Zend_Form_Exception( 1039 'Elements specified by string must have an accompanying name' 1040 ); 1041 } 1042 1043 $this->_elements[$name] = $this->createElement($element, $name, $options); 1044 } elseif ($element instanceof Zend_Form_Element) { 1045 $prefixPaths = array(); 1046 $prefixPaths['decorator'] = $this->getPluginLoader('decorator')->getPaths(); 1047 if (!empty($this->_elementPrefixPaths)) { 1048 $prefixPaths = array_merge($prefixPaths, $this->_elementPrefixPaths); 1049 } 1050 1051 if (is_array($this->_elementDecorators) 1052 && 0 == count($element->getDecorators()) 1053 ) { 1054 $element->setDecorators($this->_elementDecorators); 1055 } 1056 1057 if (null === $name) { 1058 $name = $element->getName(); 1059 } 1060 1061 $this->_elements[$name] = $element; 1062 $this->_elements[$name]->addPrefixPaths($prefixPaths); 1063 } else { 1064 // require_once 'Zend/Form/Exception.php'; 1065 throw new Zend_Form_Exception( 1066 'Element must be specified by string or Zend_Form_Element instance' 1067 ); 1068 } 1069 1070 $this->_order[$name] = $this->_elements[$name]->getOrder(); 1071 $this->_orderUpdated = true; 1072 $this->_setElementsBelongTo($name); 1073 1074 return $this; 1075 } 1076 1077 /** 1078 * Create an element 1079 * 1080 * Acts as a factory for creating elements. Elements created with this 1081 * method will not be attached to the form, but will contain element 1082 * settings as specified in the form object (including plugin loader 1083 * prefix paths, default decorators, etc.). 1084 * 1085 * @param string $type 1086 * @param string $name 1087 * @param array|Zend_Config $options 1088 * @throws Zend_Form_Exception 1089 * @return Zend_Form_Element 1090 */ 1091 public function createElement($type, $name, $options = null) 1092 { 1093 if (!is_string($type)) { 1094 // require_once 'Zend/Form/Exception.php'; 1095 throw new Zend_Form_Exception('Element type must be a string indicating type'); 1096 } 1097 1098 if (!is_string($name)) { 1099 // require_once 'Zend/Form/Exception.php'; 1100 throw new Zend_Form_Exception('Element name must be a string'); 1101 } 1102 1103 $prefixPaths = array(); 1104 $prefixPaths['decorator'] = $this->getPluginLoader('decorator')->getPaths(); 1105 if (!empty($this->_elementPrefixPaths)) { 1106 $prefixPaths = array_merge($prefixPaths, $this->_elementPrefixPaths); 1107 } 1108 1109 if ($options instanceof Zend_Config) { 1110 $options = $options->toArray(); 1111 } 1112 1113 if ((null === $options) || !is_array($options)) { 1114 $options = array('prefixPath' => $prefixPaths); 1115 1116 if (is_array($this->_elementDecorators)) { 1117 $options['decorators'] = $this->_elementDecorators; 1118 } 1119 } elseif (is_array($options)) { 1120 if (array_key_exists('prefixPath', $options)) { 1121 $options['prefixPath'] = array_merge($prefixPaths, $options['prefixPath']); 1122 } else { 1123 $options['prefixPath'] = $prefixPaths; 1124 } 1125 1126 if (is_array($this->_elementDecorators) 1127 && !array_key_exists('decorators', $options) 1128 ) { 1129 $options['decorators'] = $this->_elementDecorators; 1130 } 1131 } 1132 1133 $class = $this->getPluginLoader(self::ELEMENT)->load($type); 1134 $element = new $class($name, $options); 1135 1136 return $element; 1137 } 1138 1139 /** 1140 * Add multiple elements at once 1141 * 1142 * @param array $elements 1143 * @return Zend_Form 1144 */ 1145 public function addElements(array $elements) 1146 { 1147 foreach ($elements as $key => $spec) { 1148 $name = null; 1149 if (!is_numeric($key)) { 1150 $name = $key; 1151 } 1152 1153 if (is_string($spec) || ($spec instanceof Zend_Form_Element)) { 1154 $this->addElement($spec, $name); 1155 continue; 1156 } 1157 1158 if (is_array($spec)) { 1159 $argc = count($spec); 1160 $options = array(); 1161 if (isset($spec['type'])) { 1162 $type = $spec['type']; 1163 if (isset($spec['name'])) { 1164 $name = $spec['name']; 1165 } 1166 if (isset($spec['options'])) { 1167 $options = $spec['options']; 1168 } 1169 $this->addElement($type, $name, $options); 1170 } else { 1171 switch ($argc) { 1172 case 0: 1173 continue; 1174 case (1 <= $argc): 1175 $type = array_shift($spec); 1176 case (2 <= $argc): 1177 if (null === $name) { 1178 $name = array_shift($spec); 1179 } else { 1180 $options = array_shift($spec); 1181 } 1182 case (3 <= $argc): 1183 if (empty($options)) { 1184 $options = array_shift($spec); 1185 } 1186 default: 1187 $this->addElement($type, $name, $options); 1188 } 1189 } 1190 } 1191 } 1192 return $this; 1193 } 1194 1195 /** 1196 * Set form elements (overwrites existing elements) 1197 * 1198 * @param array $elements 1199 * @return Zend_Form 1200 */ 1201 public function setElements(array $elements) 1202 { 1203 $this->clearElements(); 1204 return $this->addElements($elements); 1205 } 1206 1207 /** 1208 * Retrieve a single element 1209 * 1210 * @param string $name 1211 * @return Zend_Form_Element|null 1212 */ 1213 public function getElement($name) 1214 { 1215 if (array_key_exists($name, $this->_elements)) { 1216 return $this->_elements[$name]; 1217 } 1218 return null; 1219 } 1220 1221 /** 1222 * Retrieve all elements 1223 * 1224 * @return array 1225 */ 1226 public function getElements() 1227 { 1228 return $this->_elements; 1229 } 1230 1231 /** 1232 * Remove element 1233 * 1234 * @param string $name 1235 * @return boolean 1236 */ 1237 public function removeElement($name) 1238 { 1239 $name = (string) $name; 1240 if (isset($this->_elements[$name])) { 1241 unset($this->_elements[$name]); 1242 if (array_key_exists($name, $this->_order)) { 1243 unset($this->_order[$name]); 1244 $this->_orderUpdated = true; 1245 } else { 1246 /** @var Zend_Form_DisplayGroup $group */ 1247 foreach ($this->_displayGroups as $group) { 1248 if (null !== $group->getElement($name)) { 1249 $group->removeElement($name); 1250 } 1251 } 1252 } 1253 return true; 1254 } 1255 1256 return false; 1257 } 1258 1259 /** 1260 * Remove all form elements 1261 * 1262 * @return Zend_Form 1263 */ 1264 public function clearElements() 1265 { 1266 foreach (array_keys($this->_elements) as $key) { 1267 if (array_key_exists($key, $this->_order)) { 1268 unset($this->_order[$key]); 1269 } 1270 } 1271 $this->_elements = array(); 1272 $this->_orderUpdated = true; 1273 return $this; 1274 } 1275 1276 /** 1277 * Set default values for elements 1278 * 1279 * Sets values for all elements specified in the array of $defaults. 1280 * 1281 * @param array $defaults 1282 * @return Zend_Form 1283 */ 1284 public function setDefaults(array $defaults) 1285 { 1286 $eBelongTo = null; 1287 1288 if ($this->isArray()) { 1289 $eBelongTo = $this->getElementsBelongTo(); 1290 $defaults = $this->_dissolveArrayValue($defaults, $eBelongTo); 1291 } 1292 /** @var Zend_Form_Element $element */ 1293 foreach ($this->getElements() as $name => $element) { 1294 $check = $defaults; 1295 if (($belongsTo = $element->getBelongsTo()) !== $eBelongTo) { 1296 $check = $this->_dissolveArrayValue($defaults, $belongsTo); 1297 } 1298 if (array_key_exists($name, (array)$check)) { 1299 $this->setDefault($name, $check[$name]); 1300 $defaults = $this->_dissolveArrayUnsetKey($defaults, $belongsTo, $name); 1301 } 1302 } 1303 /** @var Zend_Form_SubForm $form */ 1304 foreach ($this->getSubForms() as $name => $form) { 1305 if (!$form->isArray() && array_key_exists($name, $defaults)) { 1306 $form->setDefaults($defaults[$name]); 1307 } else { 1308 $form->setDefaults($defaults); 1309 } 1310 } 1311 return $this; 1312 } 1313 1314 /** 1315 * Set default value for an element 1316 * 1317 * @param string $name 1318 * @param mixed $value 1319 * @return Zend_Form 1320 */ 1321 public function setDefault($name, $value) 1322 { 1323 $name = (string) $name; 1324 if ($element = $this->getElement($name)) { 1325 $element->setValue($value); 1326 } else { 1327 if (is_scalar($value)) { 1328 /** @var Zend_Form_SubForm $subForm */ 1329 foreach ($this->getSubForms() as $subForm) { 1330 $subForm->setDefault($name, $value); 1331 } 1332 } elseif (is_array($value) && ($subForm = $this->getSubForm($name))) { 1333 $subForm->setDefaults($value); 1334 } 1335 } 1336 return $this; 1337 } 1338 1339 /** 1340 * Retrieve value for single element 1341 * 1342 * @param string $name 1343 * @return mixed 1344 */ 1345 public function getValue($name) 1346 { 1347 if ($element = $this->getElement($name)) { 1348 return $element->getValue(); 1349 } 1350 1351 if ($subForm = $this->getSubForm($name)) { 1352 return $subForm->getValues(true); 1353 } 1354 1355 /** @var Zend_Form_SubForm $subForm */ 1356 foreach ($this->getSubForms() as $subForm) { 1357 if ($name == $subForm->getElementsBelongTo()) { 1358 return $subForm->getValues(true); 1359 } 1360 } 1361 return null; 1362 } 1363 1364 /** 1365 * Retrieve all form element values 1366 * 1367 * @param bool $suppressArrayNotation 1368 * @return array 1369 */ 1370 public function getValues($suppressArrayNotation = false) 1371 { 1372 $values = array(); 1373 $eBelongTo = null; 1374 1375 if ($this->isArray()) { 1376 $eBelongTo = $this->getElementsBelongTo(); 1377 } 1378 /** @var Zend_Form_Element $element */ 1379 foreach ($this->getElements() as $key => $element) { 1380 if (!$element->getIgnore()) { 1381 $merge = array(); 1382 if (($belongsTo = $element->getBelongsTo()) !== $eBelongTo) { 1383 if ('' !== (string)$belongsTo) { 1384 $key = $belongsTo . '[' . $key . ']'; 1385 } 1386 } 1387 $merge = $this->_attachToArray($element->getValue(), $key); 1388 $values = $this->_array_replace_recursive($values, $merge); 1389 } 1390 } 1391 /** @var Zend_Form_SubForm $subForm */ 1392 foreach ($this->getSubForms() as $key => $subForm) { 1393 $merge = array(); 1394 if (!$subForm->isArray()) { 1395 $merge[$key] = $subForm->getValues(); 1396 } else { 1397 $merge = $this->_attachToArray($subForm->getValues(true), 1398 $subForm->getElementsBelongTo()); 1399 } 1400 $values = $this->_array_replace_recursive($values, $merge); 1401 } 1402 1403 if (!$suppressArrayNotation && 1404 $this->isArray() && 1405 !$this->_getIsRendered()) { 1406 $values = $this->_attachToArray($values, $this->getElementsBelongTo()); 1407 } 1408 1409 return $values; 1410 } 1411 1412 /** 1413 * Returns only the valid values from the given form input. 1414 * 1415 * For models that can be saved in a partially valid state, for example when following the builder, 1416 * prototype or state patterns it is particularly interessting to retrieve all the current valid 1417 * values to persist them. 1418 * 1419 * @param array $data 1420 * @param bool $suppressArrayNotation 1421 * @return array 1422 */ 1423 public function getValidValues($data, $suppressArrayNotation = false) 1424 { 1425 $values = array(); 1426 $eBelongTo = null; 1427 1428 if ($this->isArray()) { 1429 $eBelongTo = $this->getElementsBelongTo(); 1430 $data = $this->_dissolveArrayValue($data, $eBelongTo); 1431 } 1432 $context = $data; 1433 /** @var Zend_Form_Element $element */ 1434 foreach ($this->getElements() as $key => $element) { 1435 if (!$element->getIgnore()) { 1436 $check = $data; 1437 if (($belongsTo = $element->getBelongsTo()) !== $eBelongTo) { 1438 $check = $this->_dissolveArrayValue($data, $belongsTo); 1439 } 1440 if (isset($check[$key])) { 1441 if($element->isValid($check[$key], $context)) { 1442 $merge = array(); 1443 if ($belongsTo !== $eBelongTo && '' !== (string)$belongsTo) { 1444 $key = $belongsTo . '[' . $key . ']'; 1445 } 1446 $merge = $this->_attachToArray($element->getValue(), $key); 1447 $values = $this->_array_replace_recursive($values, $merge); 1448 } 1449 $data = $this->_dissolveArrayUnsetKey($data, $belongsTo, $key); 1450 } 1451 } 1452 } 1453 /** @var Zend_Form_SubForm $form */ 1454 foreach ($this->getSubForms() as $key => $form) { 1455 $merge = array(); 1456 if (isset($data[$key]) && !$form->isArray()) { 1457 $tmp = $form->getValidValues($data[$key]); 1458 if (!empty($tmp)) { 1459 $merge[$key] = $tmp; 1460 } 1461 } else { 1462 $tmp = $form->getValidValues($data, true); 1463 if (!empty($tmp)) { 1464 $merge = $this->_attachToArray($tmp, $form->getElementsBelongTo()); 1465 } 1466 } 1467 $values = $this->_array_replace_recursive($values, $merge); 1468 } 1469 if (!$suppressArrayNotation && 1470 $this->isArray() && 1471 !empty($values) && 1472 !$this->_getIsRendered()) { 1473 $values = $this->_attachToArray($values, $this->getElementsBelongTo()); 1474 } 1475 1476 return $values; 1477 } 1478 1479 /** 1480 * Get unfiltered element value 1481 * 1482 * @param string $name 1483 * @return mixed 1484 */ 1485 public function getUnfilteredValue($name) 1486 { 1487 if ($element = $this->getElement($name)) { 1488 return $element->getUnfilteredValue(); 1489 } 1490 return null; 1491 } 1492 1493 /** 1494 * Retrieve all unfiltered element values 1495 * 1496 * @return array 1497 */ 1498 public function getUnfilteredValues() 1499 { 1500 $values = array(); 1501 /** @var Zend_Form_Element $element */ 1502 foreach ($this->getElements() as $key => $element) { 1503 $values[$key] = $element->getUnfilteredValue(); 1504 } 1505 1506 return $values; 1507 } 1508 1509 /** 1510 * Set all elements' filters 1511 * 1512 * @param array $filters 1513 * @return Zend_Form 1514 */ 1515 public function setElementFilters(array $filters) 1516 { 1517 /** @var Zend_Form_Element $element */ 1518 foreach ($this->getElements() as $element) { 1519 $element->setFilters($filters); 1520 } 1521 return $this; 1522 } 1523 1524 /** 1525 * Set name of array elements belong to 1526 * 1527 * @param string $array 1528 * @return Zend_Form 1529 */ 1530 public function setElementsBelongTo($array) 1531 { 1532 $origName = $this->getElementsBelongTo(); 1533 $name = $this->filterName($array, true); 1534 if ('' === $name) { 1535 $name = null; 1536 } 1537 $this->_elementsBelongTo = $name; 1538 1539 if (null === $name) { 1540 $this->setIsArray(false); 1541 if (null !== $origName) { 1542 $this->_setElementsBelongTo(); 1543 } 1544 } else { 1545 $this->setIsArray(true); 1546 $this->_setElementsBelongTo(); 1547 } 1548 1549 return $this; 1550 } 1551 1552 /** 1553 * Set array to which elements belong 1554 * 1555 * @param string $name Element name 1556 * @return void 1557 */ 1558 protected function _setElementsBelongTo($name = null) 1559 { 1560 $array = $this->getElementsBelongTo(); 1561 1562 if (null === $array) { 1563 return; 1564 } 1565 1566 if (null === $name) { 1567 /** @var Zend_Form_Element $element */ 1568 foreach ($this->getElements() as $element) { 1569 $element->setBelongsTo($array); 1570 } 1571 } else { 1572 if (null !== ($element = $this->getElement($name))) { 1573 $element->setBelongsTo($array); 1574 } 1575 } 1576 } 1577 1578 /** 1579 * Get name of array elements belong to 1580 * 1581 * @return string|null 1582 */ 1583 public function getElementsBelongTo() 1584 { 1585 if ((null === $this->_elementsBelongTo) && $this->isArray()) { 1586 $name = $this->getName(); 1587 if ('' !== (string)$name) { 1588 return $name; 1589 } 1590 } 1591 return $this->_elementsBelongTo; 1592 } 1593 1594 /** 1595 * Set flag indicating elements belong to array 1596 * 1597 * @param bool $flag Value of flag 1598 * @return Zend_Form 1599 */ 1600 public function setIsArray($flag) 1601 { 1602 $this->_isArray = (bool) $flag; 1603 return $this; 1604 } 1605 1606 /** 1607 * Get flag indicating if elements belong to an array 1608 * 1609 * @return bool 1610 */ 1611 public function isArray() 1612 { 1613 return $this->_isArray; 1614 } 1615 1616 // Element groups: 1617 1618 /** 1619 * Add a form group/subform 1620 * 1621 * @param Zend_Form $form 1622 * @param string $name 1623 * @param int $order 1624 * @return Zend_Form 1625 */ 1626 public function addSubForm(Zend_Form $form, $name, $order = null) 1627 { 1628 $name = (string) $name; 1629 /** @var Zend_Loader_PluginLoader $loader */ 1630 foreach ($this->_loaders as $type => $loader) { 1631 $loaderPaths = $loader->getPaths(); 1632 foreach ($loaderPaths as $prefix => $paths) { 1633 foreach ($paths as $path) { 1634 $form->addPrefixPath($prefix, $path, $type); 1635 } 1636 } 1637 } 1638 1639 if (!empty($this->_elementPrefixPaths)) { 1640 foreach ($this->_elementPrefixPaths as $spec) { 1641 list($prefix, $path, $type) = array_values($spec); 1642 $form->addElementPrefixPath($prefix, $path, $type); 1643 } 1644 } 1645 1646 if (!empty($this->_displayGroupPrefixPaths)) { 1647 foreach ($this->_displayGroupPrefixPaths as $spec) { 1648 list($prefix, $path) = array_values($spec); 1649 $form->addDisplayGroupPrefixPath($prefix, $path); 1650 } 1651 } 1652 1653 if (null !== $order) { 1654 $form->setOrder($order); 1655 } 1656 1657 if (($oldName = $form->getName()) && 1658 $oldName !== $name && 1659 $oldName === $form->getElementsBelongTo()) { 1660 $form->setElementsBelongTo($name); 1661 } 1662 1663 $form->setName($name); 1664 $this->_subForms[$name] = $form; 1665 $this->_order[$name] = $order; 1666 $this->_orderUpdated = true; 1667 return $this; 1668 } 1669 1670 /** 1671 * Add multiple form subForms/subforms at once 1672 * 1673 * @param array $subForms 1674 * @return Zend_Form 1675 */ 1676 public function addSubForms(array $subForms) 1677 { 1678 foreach ($subForms as $key => $spec) { 1679 $name = (string) $key; 1680 if ($spec instanceof Zend_Form) { 1681 $this->addSubForm($spec, $name); 1682 continue; 1683 } 1684 1685 if (is_array($spec)) { 1686 $argc = count($spec); 1687 $order = null; 1688 switch ($argc) { 1689 case 0: 1690 continue; 1691 case (1 <= $argc): 1692 $subForm = array_shift($spec); 1693 1694 if (!$subForm instanceof Zend_Form) { 1695 $subForm = new Zend_Form_SubForm($subForm); 1696 } 1697 case (2 <= $argc): 1698 $name = array_shift($spec); 1699 case (3 <= $argc): 1700 $order = array_shift($spec); 1701 default: 1702 $this->addSubForm($subForm, $name, $order); 1703 } 1704 } 1705 } 1706 return $this; 1707 } 1708 1709 /** 1710 * Set multiple form subForms/subforms (overwrites) 1711 * 1712 * @param array $subForms 1713 * @return Zend_Form 1714 */ 1715 public function setSubForms(array $subForms) 1716 { 1717 $this->clearSubForms(); 1718 return $this->addSubForms($subForms); 1719 } 1720 1721 /** 1722 * Retrieve a form subForm/subform 1723 * 1724 * @param string $name 1725 * @return Zend_Form|null 1726 */ 1727 public function getSubForm($name) 1728 { 1729 $name = (string) $name; 1730 if (isset($this->_subForms[$name])) { 1731 return $this->_subForms[$name]; 1732 } 1733 return null; 1734 } 1735 1736 /** 1737 * Retrieve all form subForms/subforms 1738 * 1739 * @return array 1740 */ 1741 public function getSubForms() 1742 { 1743 return $this->_subForms; 1744 } 1745 1746 /** 1747 * Remove form subForm/subform 1748 * 1749 * @param string $name 1750 * @return boolean 1751 */ 1752 public function removeSubForm($name) 1753 { 1754 $name = (string) $name; 1755 if (array_key_exists($name, $this->_subForms)) { 1756 unset($this->_subForms[$name]); 1757 if (array_key_exists($name, $this->_order)) { 1758 unset($this->_order[$name]); 1759 $this->_orderUpdated = true; 1760 } 1761 return true; 1762 } 1763 1764 return false; 1765 } 1766 1767 /** 1768 * Remove all form subForms/subforms 1769 * 1770 * @return Zend_Form 1771 */ 1772 public function clearSubForms() 1773 { 1774 foreach (array_keys($this->_subForms) as $key) { 1775 if (array_key_exists($key, $this->_order)) { 1776 unset($this->_order[$key]); 1777 } 1778 } 1779 $this->_subForms = array(); 1780 $this->_orderUpdated = true; 1781 return $this; 1782 } 1783 1784 1785 // Display groups: 1786 1787 /** 1788 * Set default display group class 1789 * 1790 * @param string $class 1791 * @return Zend_Form 1792 */ 1793 public function setDefaultDisplayGroupClass($class) 1794 { 1795 $this->_defaultDisplayGroupClass = (string) $class; 1796 return $this; 1797 } 1798 1799 /** 1800 * Retrieve default display group class 1801 * 1802 * @return string 1803 */ 1804 public function getDefaultDisplayGroupClass() 1805 { 1806 return $this->_defaultDisplayGroupClass; 1807 } 1808 1809 /** 1810 * Add a display group 1811 * 1812 * Groups named elements for display purposes. 1813 * 1814 * If a referenced element does not yet exist in the form, it is omitted. 1815 * 1816 * @param array $elements 1817 * @param string $name 1818 * @param array|Zend_Config $options 1819 * @return Zend_Form 1820 * @throws Zend_Form_Exception if no valid elements provided 1821 */ 1822 public function addDisplayGroup(array $elements, $name, $options = null) 1823 { 1824 $group = array(); 1825 foreach ($elements as $element) { 1826 if($element instanceof Zend_Form_Element) { 1827 $elementName = $element->getName(); 1828 if (!isset($this->_elements[$elementName])) { 1829 $this->addElement($element); 1830 } 1831 $element = $elementName; 1832 } 1833 1834 if (isset($this->_elements[$element])) { 1835 $add = $this->getElement($element); 1836 if (null !== $add) { 1837 $group[] = $add; 1838 } 1839 } 1840 } 1841 if (empty($group)) { 1842 // require_once 'Zend/Form/Exception.php'; 1843 throw new Zend_Form_Exception('No valid elements specified for display group'); 1844 } 1845 1846 $name = (string) $name; 1847 1848 if (is_array($options)) { 1849 $options['form'] = $this; 1850 $options['elements'] = $group; 1851 } elseif ($options instanceof Zend_Config) { 1852 $options = $options->toArray(); 1853 $options['form'] = $this; 1854 $options['elements'] = $group; 1855 } else { 1856 $options = array( 1857 'form' => $this, 1858 'elements' => $group, 1859 ); 1860 } 1861 1862 if (isset($options['displayGroupClass'])) { 1863 $class = $options['displayGroupClass']; 1864 unset($options['displayGroupClass']); 1865 } else { 1866 $class = $this->getDefaultDisplayGroupClass(); 1867 } 1868 1869 if (!class_exists($class)) { 1870 // require_once 'Zend/Loader.php'; 1871 Zend_Loader::loadClass($class); 1872 } 1873 $this->_displayGroups[$name] = new $class( 1874 $name, 1875 $this->getPluginLoader(self::DECORATOR), 1876 $options 1877 ); 1878 1879 if (!empty($this->_displayGroupPrefixPaths)) { 1880 $this->_displayGroups[$name]->addPrefixPaths($this->_displayGroupPrefixPaths); 1881 } 1882 1883 $this->_order[$name] = $this->_displayGroups[$name]->getOrder(); 1884 $this->_orderUpdated = true; 1885 return $this; 1886 } 1887 1888 /** 1889 * Add a display group object (used with cloning) 1890 * 1891 * @param Zend_Form_DisplayGroup $group 1892 * @param string|null $name 1893 * @throws Zend_Form_Exception 1894 * @return Zend_Form 1895 */ 1896 protected function _addDisplayGroupObject(Zend_Form_DisplayGroup $group, $name = null) 1897 { 1898 if (null === $name) { 1899 $name = $group->getName(); 1900 if ('' === (string)$name) { 1901 // require_once 'Zend/Form/Exception.php'; 1902 throw new Zend_Form_Exception('Invalid display group added; requires name'); 1903 } 1904 } 1905 1906 $this->_displayGroups[$name] = $group; 1907 $group->setForm($this); 1908 1909 if (!empty($this->_displayGroupPrefixPaths)) { 1910 $this->_displayGroups[$name]->addPrefixPaths($this->_displayGroupPrefixPaths); 1911 } 1912 1913 $this->_order[$name] = $this->_displayGroups[$name]->getOrder(); 1914 $this->_orderUpdated = true; 1915 return $this; 1916 } 1917 1918 /** 1919 * Add multiple display groups at once 1920 * 1921 * @param array $groups 1922 * @return Zend_Form 1923 */ 1924 public function addDisplayGroups(array $groups) 1925 { 1926 foreach ($groups as $key => $spec) { 1927 $name = null; 1928 if (!is_numeric($key)) { 1929 $name = $key; 1930 } 1931 1932 if ($spec instanceof Zend_Form_DisplayGroup) { 1933 $this->_addDisplayGroupObject($spec); 1934 } 1935 1936 if (!is_array($spec) || empty($spec)) { 1937 continue; 1938 } 1939 1940 $argc = count($spec); 1941 $options = array(); 1942 1943 if (isset($spec['elements'])) { 1944 $elements = $spec['elements']; 1945 if (isset($spec['name'])) { 1946 $name = $spec['name']; 1947 } 1948 if (isset($spec['options'])) { 1949 $options = $spec['options']; 1950 } 1951 $this->addDisplayGroup($elements, $name, $options); 1952 } else { 1953 switch ($argc) { 1954 case (1 <= $argc): 1955 $elements = array_shift($spec); 1956 if (!is_array($elements) && (null !== $name)) { 1957 $elements = array_merge((array) $elements, $spec); 1958 $this->addDisplayGroup($elements, $name); 1959 break; 1960 } 1961 case (2 <= $argc): 1962 if (null !== $name) { 1963 $options = array_shift($spec); 1964 $this->addDisplayGroup($elements, $name, $options); 1965 break; 1966 } 1967 $name = array_shift($spec); 1968 case (3 <= $argc): 1969 $options = array_shift($spec); 1970 default: 1971 $this->addDisplayGroup($elements, $name, $options); 1972 } 1973 } 1974 } 1975 return $this; 1976 } 1977 1978 /** 1979 * Add multiple display groups (overwrites) 1980 * 1981 * @param array $groups 1982 * @return Zend_Form 1983 */ 1984 public function setDisplayGroups(array $groups) 1985 { 1986 return $this->clearDisplayGroups() 1987 ->addDisplayGroups($groups); 1988 } 1989 1990 /** 1991 * Return a display group 1992 * 1993 * @param string $name 1994 * @return Zend_Form_DisplayGroup|null 1995 */ 1996 public function getDisplayGroup($name) 1997 { 1998 $name = (string) $name; 1999 if (isset($this->_displayGroups[$name])) { 2000 return $this->_displayGroups[$name]; 2001 } 2002 2003 return null; 2004 } 2005 2006 /** 2007 * Return all display groups 2008 * 2009 * @return array 2010 */ 2011 public function getDisplayGroups() 2012 { 2013 return $this->_displayGroups; 2014 } 2015 2016 /** 2017 * Remove a display group by name 2018 * 2019 * @param string $name 2020 * @return boolean 2021 */ 2022 public function removeDisplayGroup($name) 2023 { 2024 $name = (string) $name; 2025 if (array_key_exists($name, $this->_displayGroups)) { 2026 /** @var Zend_Form_Element $element */ 2027 foreach ($this->_displayGroups[$name] as $key => $element) { 2028 if (array_key_exists($key, $this->_elements)) { 2029 $this->_order[$key] = $element->getOrder(); 2030 $this->_orderUpdated = true; 2031 } 2032 } 2033 unset($this->_displayGroups[$name]); 2034 2035 if (array_key_exists($name, $this->_order)) { 2036 unset($this->_order[$name]); 2037 $this->_orderUpdated = true; 2038 } 2039 return true; 2040 } 2041 2042 return false; 2043 } 2044 2045 /** 2046 * Remove all display groups 2047 * 2048 * @return Zend_Form 2049 */ 2050 public function clearDisplayGroups() 2051 { 2052 foreach ($this->_displayGroups as $key => $group) { 2053 if (array_key_exists($key, $this->_order)) { 2054 unset($this->_order[$key]); 2055 } 2056 /** @var Zend_Form_Element $element */ 2057 foreach ($group as $name => $element) { 2058 if (isset($this->_elements[$name])) { 2059 $this->_order[$name] = $element->getOrder(); 2060 } 2061 $this->_order[$name] = $element->getOrder(); 2062 } 2063 } 2064 $this->_displayGroups = array(); 2065 $this->_orderUpdated = true; 2066 return $this; 2067 } 2068 2069 2070 // Processing 2071 2072 /** 2073 * Populate form 2074 * 2075 * Proxies to {@link setDefaults()} 2076 * 2077 * @param array $values 2078 * @return Zend_Form 2079 */ 2080 public function populate(array $values) 2081 { 2082 return $this->setDefaults($values); 2083 } 2084 2085 /** 2086 * Determine array key name from given value 2087 * 2088 * Given a value such as foo[bar][baz], returns the last element (in this case, 'baz'). 2089 * 2090 * @param string $value 2091 * @return string 2092 */ 2093 protected function _getArrayName($value) 2094 { 2095 if (!is_string($value) || '' === $value) { 2096 return $value; 2097 } 2098 2099 if (!strstr($value, '[')) { 2100 return $value; 2101 } 2102 2103 $endPos = strlen($value) - 1; 2104 if (']' != $value[$endPos]) { 2105 return $value; 2106 } 2107 2108 $start = strrpos($value, '[') + 1; 2109 $name = substr($value, $start, $endPos - $start); 2110 return $name; 2111 } 2112 2113 /** 2114 * Extract the value by walking the array using given array path. 2115 * 2116 * Given an array path such as foo[bar][baz], returns the value of the last 2117 * element (in this case, 'baz'). 2118 * 2119 * @param array $value Array to walk 2120 * @param string $arrayPath Array notation path of the part to extract 2121 * @return string 2122 */ 2123 protected function _dissolveArrayValue($value, $arrayPath) 2124 { 2125 // As long as we have more levels 2126 while ($arrayPos = strpos($arrayPath, '[')) { 2127 // Get the next key in the path 2128 $arrayKey = trim(substr($arrayPath, 0, $arrayPos), ']'); 2129 2130 // Set the potentially final value or the next search point in the array 2131 if (isset($value[$arrayKey])) { 2132 $value = $value[$arrayKey]; 2133 } 2134 2135 // Set the next search point in the path 2136 $arrayPath = trim(substr($arrayPath, $arrayPos + 1), ']'); 2137 } 2138 2139 if (isset($value[$arrayPath])) { 2140 $value = $value[$arrayPath]; 2141 } 2142 2143 return $value; 2144 } 2145 2146 /** 2147 * Given an array, an optional arrayPath and a key this method 2148 * dissolves the arrayPath and unsets the key within the array 2149 * if it exists. 2150 * 2151 * @param array $array 2152 * @param string|null $arrayPath 2153 * @param string $key 2154 * @return array 2155 */ 2156 protected function _dissolveArrayUnsetKey($array, $arrayPath, $key) 2157 { 2158 $unset =& $array; 2159 $path = trim(strtr((string)$arrayPath, array('[' => '/', ']' => '')), '/'); 2160 $segs = ('' !== $path) ? explode('/', $path) : array(); 2161 2162 foreach ($segs as $seg) { 2163 if (!array_key_exists($seg, (array)$unset)) { 2164 return $array; 2165 } 2166 $unset =& $unset[$seg]; 2167 } 2168 if (array_key_exists($key, (array)$unset)) { 2169 unset($unset[$key]); 2170 } 2171 return $array; 2172 } 2173 2174 /** 2175 * Converts given arrayPath to an array and attaches given value at the end of it. 2176 * 2177 * @param mixed $value The value to attach 2178 * @param string $arrayPath Given array path to convert and attach to. 2179 * @return array 2180 */ 2181 protected function _attachToArray($value, $arrayPath) 2182 { 2183 // As long as we have more levels 2184 while ($arrayPos = strrpos($arrayPath, '[')) { 2185 // Get the next key in the path 2186 $arrayKey = trim(substr($arrayPath, $arrayPos + 1), ']'); 2187 2188 // Attach 2189 $value = array($arrayKey => $value); 2190 2191 // Set the next search point in the path 2192 $arrayPath = trim(substr($arrayPath, 0, $arrayPos), ']'); 2193 } 2194 2195 $value = array($arrayPath => $value); 2196 2197 return $value; 2198 } 2199 2200 /** 2201 * Returns a one dimensional numerical indexed array with the 2202 * Elements, SubForms and Elements from DisplayGroups as Values. 2203 * 2204 * Subitems are inserted based on their order Setting if set, 2205 * otherwise they are appended, the resulting numerical index 2206 * may differ from the order value. 2207 * 2208 * @access protected 2209 * @return array 2210 */ 2211 public function getElementsAndSubFormsOrdered() 2212 { 2213 $ordered = array(); 2214 foreach ($this->_order as $name => $order) { 2215 $order = isset($order) ? $order : count($ordered); 2216 if ($this->$name instanceof Zend_Form_Element || 2217 $this->$name instanceof Zend_Form) { 2218 array_splice($ordered, $order, 0, array($this->$name)); 2219 } else if ($this->$name instanceof Zend_Form_DisplayGroup) { 2220 $subordered = array(); 2221 /** @var Zend_Form_Element $element */ 2222 foreach ($this->$name->getElements() as $element) { 2223 $suborder = $element->getOrder(); 2224 $suborder = (null !== $suborder) ? $suborder : count($subordered); 2225 array_splice($subordered, $suborder, 0, array($element)); 2226 } 2227 if (!empty($subordered)) { 2228 array_splice($ordered, $order, 0, $subordered); 2229 } 2230 } 2231 } 2232 return $ordered; 2233 } 2234 2235 /** 2236 * This is a helper function until php 5.3 is widespreaded 2237 * 2238 * @param array $into 2239 * @return array 2240 */ 2241 protected function _array_replace_recursive(array $into) 2242 { 2243 $fromArrays = array_slice(func_get_args(),1); 2244 2245 foreach ($fromArrays as $from) { 2246 foreach ($from as $key => $value) { 2247 if (is_array($value)) { 2248 if (!isset($into[$key])) { 2249 $into[$key] = array(); 2250 } 2251 $into[$key] = $this->_array_replace_recursive($into[$key], $from[$key]); 2252 } else { 2253 $into[$key] = $value; 2254 } 2255 } 2256 } 2257 return $into; 2258 } 2259 2260 /** 2261 * Validate the form 2262 * 2263 * @param array $data 2264 * @throws Zend_Form_Exception 2265 * @return bool 2266 */ 2267 public function isValid($data) 2268 { 2269 if (!is_array($data)) { 2270 // require_once 'Zend/Form/Exception.php'; 2271 throw new Zend_Form_Exception(__METHOD__ . ' expects an array'); 2272 } 2273 $translator = $this->getTranslator(); 2274 $valid = true; 2275 $eBelongTo = null; 2276 2277 if ($this->isArray()) { 2278 $eBelongTo = $this->getElementsBelongTo(); 2279 $data = $this->_dissolveArrayValue($data, $eBelongTo); 2280 } 2281 $context = $data; 2282 /** @var Zend_Form_Element $element */ 2283 foreach ($this->getElements() as $key => $element) { 2284 if (null !== $translator && $this->hasTranslator() 2285 && !$element->hasTranslator()) { 2286 $element->setTranslator($translator); 2287 } 2288 $check = $data; 2289 if (($belongsTo = $element->getBelongsTo()) !== $eBelongTo) { 2290 $check = $this->_dissolveArrayValue($data, $belongsTo); 2291 } 2292 if (!isset($check[$key])) { 2293 $valid = $element->isValid(null, $context) && $valid; 2294 } else { 2295 $valid = $element->isValid($check[$key], $context) && $valid; 2296 $data = $this->_dissolveArrayUnsetKey($data, $belongsTo, $key); 2297 } 2298 } 2299 /** @var Zend_Form_SubForm $form */ 2300 foreach ($this->getSubForms() as $key => $form) { 2301 if (null !== $translator && $this->hasTranslator() 2302 && !$form->hasTranslator()) { 2303 $form->setTranslator($translator); 2304 } 2305 if (isset($data[$key]) && !$form->isArray()) { 2306 $valid = $form->isValid($data[$key]) && $valid; 2307 } else { 2308 $valid = $form->isValid($data) && $valid; 2309 } 2310 } 2311 2312 $this->_errorsExist = !$valid; 2313 2314 // If manually flagged as an error, return invalid status 2315 if ($this->_errorsForced) { 2316 return false; 2317 } 2318 2319 return $valid; 2320 } 2321 2322 /** 2323 * Validate a partial form 2324 * 2325 * Does not check for required flags. 2326 * 2327 * @param array $data 2328 * @return boolean 2329 */ 2330 public function isValidPartial(array $data) 2331 { 2332 $eBelongTo = null; 2333 2334 if ($this->isArray()) { 2335 $eBelongTo = $this->getElementsBelongTo(); 2336 $data = $this->_dissolveArrayValue($data, $eBelongTo); 2337 } 2338 2339 $translator = $this->getTranslator(); 2340 $valid = true; 2341 $context = $data; 2342 2343 /** @var Zend_Form_Element $element */ 2344 foreach ($this->getElements() as $key => $element) { 2345 $check = $data; 2346 if (($belongsTo = $element->getBelongsTo()) !== $eBelongTo) { 2347 $check = $this->_dissolveArrayValue($data, $belongsTo); 2348 } 2349 if (isset($check[$key])) { 2350 if (null !== $translator && !$element->hasTranslator()) { 2351 $element->setTranslator($translator); 2352 } 2353 $valid = $element->isValid($check[$key], $context) && $valid; 2354 $data = $this->_dissolveArrayUnsetKey($data, $belongsTo, $key); 2355 } 2356 } 2357 /** @var Zend_Form_SubForm $form */ 2358 foreach ($this->getSubForms() as $key => $form) { 2359 if (null !== $translator && !$form->hasTranslator()) { 2360 $form->setTranslator($translator); 2361 } 2362 if (isset($data[$key]) && !$form->isArray()) { 2363 $valid = $form->isValidPartial($data[$key]) && $valid; 2364 } else { 2365 $valid = $form->isValidPartial($data) && $valid; 2366 } 2367 } 2368 2369 $this->_errorsExist = !$valid; 2370 return $valid; 2371 } 2372 2373 /** 2374 * Process submitted AJAX data 2375 * 2376 * Checks if provided $data is valid, via {@link isValidPartial()}. If so, 2377 * it returns JSON-encoded boolean true. If not, it returns JSON-encoded 2378 * error messages (as returned by {@link getMessages()}). 2379 * 2380 * @param array $data 2381 * @return string JSON-encoded boolean true or error messages 2382 */ 2383 public function processAjax(array $data) 2384 { 2385 // require_once 'Zend/Json.php'; 2386 if ($this->isValidPartial($data)) { 2387 return Zend_Json::encode(true); 2388 } 2389 $messages = $this->getMessages(); 2390 return Zend_Json::encode($messages); 2391 } 2392 2393 /** 2394 * Add a custom error message to return in the event of failed validation 2395 * 2396 * @param string $message 2397 * @return Zend_Form 2398 */ 2399 public function addErrorMessage($message) 2400 { 2401 $this->_errorMessages[] = (string) $message; 2402 return $this; 2403 } 2404 2405 /** 2406 * Add multiple custom error messages to return in the event of failed validation 2407 * 2408 * @param array $messages 2409 * @return Zend_Form 2410 */ 2411 public function addErrorMessages(array $messages) 2412 { 2413 foreach ($messages as $message) { 2414 $this->addErrorMessage($message); 2415 } 2416 return $this; 2417 } 2418 2419 /** 2420 * Same as addErrorMessages(), but clears custom error message stack first 2421 * 2422 * @param array $messages 2423 * @return Zend_Form 2424 */ 2425 public function setErrorMessages(array $messages) 2426 { 2427 $this->clearErrorMessages(); 2428 return $this->addErrorMessages($messages); 2429 } 2430 2431 /** 2432 * Retrieve custom error messages 2433 * 2434 * @return array 2435 */ 2436 public function getErrorMessages() 2437 { 2438 return $this->_errorMessages; 2439 } 2440 2441 /** 2442 * Clear custom error messages stack 2443 * 2444 * @return Zend_Form 2445 */ 2446 public function clearErrorMessages() 2447 { 2448 $this->_errorMessages = array(); 2449 return $this; 2450 } 2451 2452 /** 2453 * Mark the element as being in a failed validation state 2454 * 2455 * @return Zend_Form 2456 */ 2457 public function markAsError() 2458 { 2459 $this->_errorsExist = true; 2460 $this->_errorsForced = true; 2461 return $this; 2462 } 2463 2464 /** 2465 * Add an error message and mark element as failed validation 2466 * 2467 * @param string $message 2468 * @return Zend_Form 2469 */ 2470 public function addError($message) 2471 { 2472 $this->addErrorMessage($message); 2473 $this->markAsError(); 2474 return $this; 2475 } 2476 2477 /** 2478 * Add multiple error messages and flag element as failed validation 2479 * 2480 * @param array $messages 2481 * @return Zend_Form 2482 */ 2483 public function addErrors(array $messages) 2484 { 2485 foreach ($messages as $message) { 2486 $this->addError($message); 2487 } 2488 return $this; 2489 } 2490 2491 /** 2492 * Overwrite any previously set error messages and flag as failed validation 2493 * 2494 * @param array $messages 2495 * @return Zend_Form 2496 */ 2497 public function setErrors(array $messages) 2498 { 2499 $this->clearErrorMessages(); 2500 return $this->addErrors($messages); 2501 } 2502 2503 2504 public function persistData() 2505 { 2506 } 2507 2508 /** 2509 * Are there errors in the form? 2510 * 2511 * @deprecated since 1.11.1 - use hasErrors() instead 2512 * @return bool 2513 */ 2514 public function isErrors() 2515 { 2516 return $this->hasErrors(); 2517 } 2518 2519 /** 2520 * Are there errors in the form? 2521 * 2522 * @return bool 2523 */ 2524 public function hasErrors() 2525 { 2526 $errors = $this->_errorsExist; 2527 2528 if (!$errors) { 2529 /** @var Zend_Form_Element $element */ 2530 foreach ($this->getElements() as $element) { 2531 if ($element->hasErrors()) { 2532 $errors = true; 2533 break; 2534 } 2535 } 2536 2537 /** @var Zend_Form_SubForm $subForm */ 2538 foreach ($this->getSubForms() as $subForm) { 2539 if ($subForm->hasErrors()) { 2540 $errors = true; 2541 break; 2542 } 2543 } 2544 } 2545 2546 return $errors; 2547 } 2548 2549 /** 2550 * Get error codes for all elements failing validation 2551 * 2552 * @param string $name 2553 * @param bool $suppressArrayNotation 2554 * @return array 2555 */ 2556 public function getErrors($name = null, $suppressArrayNotation = false) 2557 { 2558 $errors = array(); 2559 if (null !== $name) { 2560 if (isset($this->_elements[$name])) { 2561 return $this->getElement($name)->getErrors(); 2562 } else if (isset($this->_subForms[$name])) { 2563 return $this->getSubForm($name)->getErrors(null, true); 2564 } 2565 } 2566 2567 /** @var Zend_Form_Element $element */ 2568 foreach ($this->_elements as $key => $element) { 2569 $errors[$key] = $element->getErrors(); 2570 } 2571 /** @var Zend_Form_SubForm $subForm */ 2572 foreach ($this->getSubForms() as $key => $subForm) { 2573 $merge = array(); 2574 if (!$subForm->isArray()) { 2575 $merge[$key] = $subForm->getErrors(); 2576 } else { 2577 $merge = $this->_attachToArray($subForm->getErrors(null, true), 2578 $subForm->getElementsBelongTo()); 2579 } 2580 $errors = $this->_array_replace_recursive($errors, $merge); 2581 } 2582 2583 if (!$suppressArrayNotation && 2584 $this->isArray() && 2585 !$this->_getIsRendered()) { 2586 $errors = $this->_attachToArray($errors, $this->getElementsBelongTo()); 2587 } 2588 2589 return $errors; 2590 } 2591 2592 /** 2593 * Retrieve error messages from elements failing validations 2594 * 2595 * @param string $name 2596 * @param bool $suppressArrayNotation 2597 * @return array 2598 */ 2599 public function getMessages($name = null, $suppressArrayNotation = false) 2600 { 2601 if (null !== $name) { 2602 if (isset($this->_elements[$name])) { 2603 return $this->getElement($name)->getMessages(); 2604 } else if (isset($this->_subForms[$name])) { 2605 return $this->getSubForm($name)->getMessages(null, true); 2606 } 2607 /** @var Zend_Form_SubForm $subForm */ 2608 foreach ($this->getSubForms() as $key => $subForm) { 2609 if ($subForm->isArray()) { 2610 $belongTo = $subForm->getElementsBelongTo(); 2611 if ($name == $this->_getArrayName($belongTo)) { 2612 return $subForm->getMessages(null, true); 2613 } 2614 } 2615 } 2616 } 2617 2618 $customMessages = $this->_getErrorMessages(); 2619 if ($this->isErrors() && !empty($customMessages)) { 2620 return $customMessages; 2621 } 2622 2623 $messages = array(); 2624 2625 /** @var Zend_Form_Element $element */ 2626 foreach ($this->getElements() as $name => $element) { 2627 $eMessages = $element->getMessages(); 2628 if (!empty($eMessages)) { 2629 $messages[$name] = $eMessages; 2630 } 2631 } 2632 2633 /** @var Zend_Form_SubForm $subForm */ 2634 foreach ($this->getSubForms() as $key => $subForm) { 2635 $merge = $subForm->getMessages(null, true); 2636 if (!empty($merge)) { 2637 if (!$subForm->isArray()) { 2638 $merge = array($key => $merge); 2639 } else { 2640 $merge = $this->_attachToArray($merge, 2641 $subForm->getElementsBelongTo()); 2642 } 2643 $messages = $this->_array_replace_recursive($messages, $merge); 2644 } 2645 } 2646 2647 if (!$suppressArrayNotation && 2648 $this->isArray() && 2649 !$this->_getIsRendered()) { 2650 $messages = $this->_attachToArray($messages, $this->getElementsBelongTo()); 2651 } 2652 2653 return $messages; 2654 } 2655 2656 /** 2657 * Retrieve translated custom error messages 2658 * Proxies to {@link _getErrorMessages()}. 2659 * 2660 * @return array 2661 */ 2662 public function getCustomMessages() 2663 { 2664 return $this->_getErrorMessages(); 2665 } 2666 2667 2668 // Rendering 2669 2670 /** 2671 * Set view object 2672 * 2673 * @param Zend_View_Interface $view 2674 * @return Zend_Form 2675 */ 2676 public function setView(Zend_View_Interface $view = null) 2677 { 2678 $this->_view = $view; 2679 return $this; 2680 } 2681 2682 /** 2683 * Retrieve view object 2684 * 2685 * If none registered, attempts to pull from ViewRenderer. 2686 * 2687 * @return Zend_View_Interface|null 2688 */ 2689 public function getView() 2690 { 2691 if (null === $this->_view) { 2692 // require_once 'Zend/Controller/Action/HelperBroker.php'; 2693 $viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer'); 2694 $this->setView($viewRenderer->view); 2695 } 2696 2697 return $this->_view; 2698 } 2699 2700 /** 2701 * Instantiate a decorator based on class name or class name fragment 2702 * 2703 * @param string $name 2704 * @param null|array $options 2705 * @return Zend_Form_Decorator_Interface 2706 */ 2707 protected function _getDecorator($name, $options) 2708 { 2709 $class = $this->getPluginLoader(self::DECORATOR)->load($name); 2710 if (null === $options) { 2711 $decorator = new $class; 2712 } else { 2713 $decorator = new $class($options); 2714 } 2715 2716 return $decorator; 2717 } 2718 2719 /** 2720 * Add a decorator for rendering the element 2721 * 2722 * @param string|Zend_Form_Decorator_Interface $decorator 2723 * @param array|Zend_Config $options Options with which to initialize decorator 2724 * @throws Zend_Form_Exception 2725 * @return Zend_Form 2726 */ 2727 public function addDecorator($decorator, $options = null) 2728 { 2729 if ($decorator instanceof Zend_Form_Decorator_Interface) { 2730 $name = get_class($decorator); 2731 } elseif (is_string($decorator)) { 2732 $name = $decorator; 2733 $decorator = array( 2734 'decorator' => $name, 2735 'options' => $options, 2736 ); 2737 } elseif (is_array($decorator)) { 2738 foreach ($decorator as $name => $spec) { 2739 break; 2740 } 2741 if (is_numeric($name)) { 2742 // require_once 'Zend/Form/Exception.php'; 2743 throw new Zend_Form_Exception('Invalid alias provided to addDecorator; must be alphanumeric string'); 2744 } 2745 if (is_string($spec)) { 2746 $decorator = array( 2747 'decorator' => $spec, 2748 'options' => $options, 2749 ); 2750 } elseif ($spec instanceof Zend_Form_Decorator_Interface) { 2751 $decorator = $spec; 2752 } 2753 } else { 2754 // require_once 'Zend/Form/Exception.php'; 2755 throw new Zend_Form_Exception('Invalid decorator provided to addDecorator; must be string or Zend_Form_Decorator_Interface'); 2756 } 2757 2758 $this->_decorators[$name] = $decorator; 2759 2760 return $this; 2761 } 2762 2763 /** 2764 * Add many decorators at once 2765 * 2766 * @param array $decorators 2767 * @throws Zend_Form_Exception 2768 * @return Zend_Form 2769 */ 2770 public function addDecorators(array $decorators) 2771 { 2772 foreach ($decorators as $decoratorName => $decoratorInfo) { 2773 if (is_string($decoratorInfo) || 2774 $decoratorInfo instanceof Zend_Form_Decorator_Interface) { 2775 if (!is_numeric($decoratorName)) { 2776 $this->addDecorator(array($decoratorName => $decoratorInfo)); 2777 } else { 2778 $this->addDecorator($decoratorInfo); 2779 } 2780 } elseif (is_array($decoratorInfo)) { 2781 $argc = count($decoratorInfo); 2782 $options = array(); 2783 if (isset($decoratorInfo['decorator'])) { 2784 $decorator = $decoratorInfo['decorator']; 2785 if (isset($decoratorInfo['options'])) { 2786 $options = $decoratorInfo['options']; 2787 } 2788 $this->addDecorator($decorator, $options); 2789 } else { 2790 switch (true) { 2791 case (0 == $argc): 2792 break; 2793 case (1 <= $argc): 2794 $decorator = array_shift($decoratorInfo); 2795 case (2 <= $argc): 2796 $options = array_shift($decoratorInfo); 2797 default: 2798 $this->addDecorator($decorator, $options); 2799 break; 2800 } 2801 } 2802 } else { 2803 // require_once 'Zend/Form/Exception.php'; 2804 throw new Zend_Form_Exception('Invalid decorator passed to addDecorators()'); 2805 } 2806 } 2807 2808 return $this; 2809 } 2810 2811 /** 2812 * Overwrite all decorators 2813 * 2814 * @param array $decorators 2815 * @return Zend_Form 2816 */ 2817 public function setDecorators(array $decorators) 2818 { 2819 $this->clearDecorators(); 2820 return $this->addDecorators($decorators); 2821 } 2822 2823 /** 2824 * Retrieve a registered decorator 2825 * 2826 * @param string $name 2827 * @return false|Zend_Form_Decorator_Abstract 2828 */ 2829 public function getDecorator($name) 2830 { 2831 if (!isset($this->_decorators[$name])) { 2832 $len = strlen($name); 2833 foreach ($this->_decorators as $localName => $decorator) { 2834 if ($len > strlen($localName)) { 2835 continue; 2836 } 2837 2838 if (0 === substr_compare($localName, $name, -$len, $len, true)) { 2839 if (is_array($decorator)) { 2840 return $this->_loadDecorator($decorator, $localName); 2841 } 2842 return $decorator; 2843 } 2844 } 2845 return false; 2846 } 2847 2848 if (is_array($this->_decorators[$name])) { 2849 return $this->_loadDecorator($this->_decorators[$name], $name); 2850 } 2851 2852 return $this->_decorators[$name]; 2853 } 2854 2855 /** 2856 * Retrieve all decorators 2857 * 2858 * @return array 2859 */ 2860 public function getDecorators() 2861 { 2862 foreach ($this->_decorators as $key => $value) { 2863 if (is_array($value)) { 2864 $this->_loadDecorator($value, $key); 2865 } 2866 } 2867 return $this->_decorators; 2868 } 2869 2870 /** 2871 * Remove a single decorator 2872 * 2873 * @param string $name 2874 * @return bool 2875 */ 2876 public function removeDecorator($name) 2877 { 2878 $decorator = $this->getDecorator($name); 2879 if ($decorator) { 2880 if (array_key_exists($name, $this->_decorators)) { 2881 unset($this->_decorators[$name]); 2882 } else { 2883 $class = get_class($decorator); 2884 if (!array_key_exists($class, $this->_decorators)) { 2885 return false; 2886 } 2887 unset($this->_decorators[$class]); 2888 } 2889 return true; 2890 } 2891 2892 return false; 2893 } 2894 2895 /** 2896 * Clear all decorators 2897 * 2898 * @return Zend_Form 2899 */ 2900 public function clearDecorators() 2901 { 2902 $this->_decorators = array(); 2903 return $this; 2904 } 2905 2906 /** 2907 * Set all element decorators as specified 2908 * 2909 * @param array $decorators 2910 * @param array|null $elements Specific elements to decorate or exclude from decoration 2911 * @param bool $include Whether $elements is an inclusion or exclusion list 2912 * @return Zend_Form 2913 */ 2914 public function setElementDecorators(array $decorators, array $elements = null, $include = true) 2915 { 2916 if (is_array($elements)) { 2917 if ($include) { 2918 $elementObjs = array(); 2919 foreach ($elements as $name) { 2920 if (null !== ($element = $this->getElement($name))) { 2921 $elementObjs[] = $element; 2922 } 2923 } 2924 } else { 2925 $elementObjs = $this->getElements(); 2926 foreach ($elements as $name) { 2927 if (array_key_exists($name, $elementObjs)) { 2928 unset($elementObjs[$name]); 2929 } 2930 } 2931 } 2932 } else { 2933 $elementObjs = $this->getElements(); 2934 } 2935 2936 /** @var Zend_Form_Element $element */ 2937 foreach ($elementObjs as $element) { 2938 $element->setDecorators($decorators); 2939 } 2940 2941 $this->_elementDecorators = $decorators; 2942 2943 return $this; 2944 } 2945 2946 /** 2947 * Set all display group decorators as specified 2948 * 2949 * @param array $decorators 2950 * @return Zend_Form 2951 */ 2952 public function setDisplayGroupDecorators(array $decorators) 2953 { 2954 /** @var Zend_Form_DisplayGroup $group */ 2955 foreach ($this->getDisplayGroups() as $group) { 2956 $group->setDecorators($decorators); 2957 } 2958 2959 return $this; 2960 } 2961 2962 /** 2963 * Set all subform decorators as specified 2964 * 2965 * @param array $decorators 2966 * @return Zend_Form 2967 */ 2968 public function setSubFormDecorators(array $decorators) 2969 { 2970 /** @var Zend_Form_SubForm $form */ 2971 foreach ($this->getSubForms() as $form) { 2972 $form->setDecorators($decorators); 2973 } 2974 2975 return $this; 2976 } 2977 2978 /** 2979 * Render form 2980 * 2981 * @param Zend_View_Interface $view 2982 * @return string 2983 */ 2984 public function render(Zend_View_Interface $view = null) 2985 { 2986 if (null !== $view) { 2987 $this->setView($view); 2988 } 2989 2990 $content = ''; 2991 /** @var Zend_Form_Decorator_Abstract $decorator */ 2992 foreach ($this->getDecorators() as $decorator) { 2993 $decorator->setElement($this); 2994 $content = $decorator->render($content); 2995 } 2996 $this->_setIsRendered(); 2997 return $content; 2998 } 2999 3000 /** 3001 * Serialize as string 3002 * 3003 * Proxies to {@link render()}. 3004 * 3005 * @return string 3006 */ 3007 public function __toString() 3008 { 3009 try { 3010 $return = $this->render(); 3011 return $return; 3012 } catch (Exception $e) { 3013 $message = "Exception caught by form: " . $e->getMessage() 3014 . "\nStack Trace:\n" . $e->getTraceAsString(); 3015 trigger_error($message, E_USER_WARNING); 3016 return ''; 3017 } 3018 } 3019 3020 3021 // Localization: 3022 3023 /** 3024 * Set translator object 3025 * 3026 * @param Zend_Translate|Zend_Translate_Adapter|null $translator 3027 * @throws Zend_Form_Exception 3028 * @return Zend_Form 3029 */ 3030 public function setTranslator($translator = null) 3031 { 3032 if (null === $translator) { 3033 $this->_translator = null; 3034 } elseif ($translator instanceof Zend_Translate_Adapter) { 3035 $this->_translator = $translator; 3036 } elseif ($translator instanceof Zend_Translate) { 3037 $this->_translator = $translator->getAdapter(); 3038 } else { 3039 // require_once 'Zend/Form/Exception.php'; 3040 throw new Zend_Form_Exception('Invalid translator specified'); 3041 } 3042 3043 return $this; 3044 } 3045 3046 /** 3047 * Set global default translator object 3048 * 3049 * @param Zend_Translate|Zend_Translate_Adapter|null $translator 3050 * @throws Zend_Form_Exception 3051 * @return void 3052 */ 3053 public static function setDefaultTranslator($translator = null) 3054 { 3055 if (null === $translator) { 3056 self::$_translatorDefault = null; 3057 } elseif ($translator instanceof Zend_Translate_Adapter) { 3058 self::$_translatorDefault = $translator; 3059 } elseif ($translator instanceof Zend_Translate) { 3060 self::$_translatorDefault = $translator->getAdapter(); 3061 } else { 3062 // require_once 'Zend/Form/Exception.php'; 3063 throw new Zend_Form_Exception('Invalid translator specified'); 3064 } 3065 } 3066 3067 /** 3068 * Retrieve translator object 3069 * 3070 * @return Zend_Translate|null 3071 */ 3072 public function getTranslator() 3073 { 3074 if ($this->translatorIsDisabled()) { 3075 return null; 3076 } 3077 3078 if (null === $this->_translator) { 3079 return self::getDefaultTranslator(); 3080 } 3081 3082 return $this->_translator; 3083 } 3084 3085 /** 3086 * Does this form have its own specific translator? 3087 * 3088 * @return bool 3089 */ 3090 public function hasTranslator() 3091 { 3092 return (bool)$this->_translator; 3093 } 3094 3095 /** 3096 * Get global default translator object 3097 * 3098 * @return null|Zend_Translate 3099 */ 3100 public static function getDefaultTranslator() 3101 { 3102 if (null === self::$_translatorDefault) { 3103 // require_once 'Zend/Registry.php'; 3104 if (Zend_Registry::isRegistered('Zend_Translate')) { 3105 $translator = Zend_Registry::get('Zend_Translate'); 3106 if ($translator instanceof Zend_Translate_Adapter) { 3107 return $translator; 3108 } elseif ($translator instanceof Zend_Translate) { 3109 return $translator->getAdapter(); 3110 } 3111 } 3112 } 3113 return self::$_translatorDefault; 3114 } 3115 3116 /** 3117 * Is there a default translation object set? 3118 * 3119 * @return boolean 3120 */ 3121 public static function hasDefaultTranslator() 3122 { 3123 return (bool)self::$_translatorDefault; 3124 } 3125 3126 /** 3127 * Indicate whether or not translation should be disabled 3128 * 3129 * @param bool $flag 3130 * @return Zend_Form 3131 */ 3132 public function setDisableTranslator($flag) 3133 { 3134 $this->_translatorDisabled = (bool) $flag; 3135 return $this; 3136 } 3137 3138 /** 3139 * Is translation disabled? 3140 * 3141 * @return bool 3142 */ 3143 public function translatorIsDisabled() 3144 { 3145 return $this->_translatorDisabled; 3146 } 3147 3148 /** 3149 * Overloading: access to elements, form groups, and display groups 3150 * 3151 * @param string $name 3152 * @return Zend_Form_Element|Zend_Form|null 3153 */ 3154 public function __get($name) 3155 { 3156 if (isset($this->_elements[$name])) { 3157 return $this->_elements[$name]; 3158 } elseif (isset($this->_subForms[$name])) { 3159 return $this->_subForms[$name]; 3160 } elseif (isset($this->_displayGroups[$name])) { 3161 return $this->_displayGroups[$name]; 3162 } 3163 3164 return null; 3165 } 3166 3167 /** 3168 * Overloading: access to elements, form groups, and display groups 3169 * 3170 * @param string $name 3171 * @param Zend_Form_Element|Zend_Form $value 3172 * @return void 3173 * @throws Zend_Form_Exception for invalid $value 3174 */ 3175 public function __set($name, $value) 3176 { 3177 if ($value instanceof Zend_Form_Element) { 3178 $this->addElement($value, $name); 3179 return; 3180 } elseif ($value instanceof Zend_Form) { 3181 $this->addSubForm($value, $name); 3182 return; 3183 } elseif (is_array($value)) { 3184 $this->addDisplayGroup($value, $name); 3185 return; 3186 } 3187 3188 // require_once 'Zend/Form/Exception.php'; 3189 if (is_object($value)) { 3190 $type = get_class($value); 3191 } else { 3192 $type = gettype($value); 3193 } 3194 throw new Zend_Form_Exception('Only form elements and groups may be overloaded; variable of type "' . $type . '" provided'); 3195 } 3196 3197 /** 3198 * Overloading: access to elements, form groups, and display groups 3199 * 3200 * @param string $name 3201 * @return boolean 3202 */ 3203 public function __isset($name) 3204 { 3205 if (isset($this->_elements[$name]) 3206 || isset($this->_subForms[$name]) 3207 || isset($this->_displayGroups[$name])) 3208 { 3209 return true; 3210 } 3211 3212 return false; 3213 } 3214 3215 /** 3216 * Overloading: access to elements, form groups, and display groups 3217 * 3218 * @param string $name 3219 * @return void 3220 */ 3221 public function __unset($name) 3222 { 3223 if (isset($this->_elements[$name])) { 3224 unset($this->_elements[$name]); 3225 } elseif (isset($this->_subForms[$name])) { 3226 unset($this->_subForms[$name]); 3227 } elseif (isset($this->_displayGroups[$name])) { 3228 unset($this->_displayGroups[$name]); 3229 } 3230 } 3231 3232 /** 3233 * Overloading: allow rendering specific decorators 3234 * 3235 * Call renderDecoratorName() to render a specific decorator. 3236 * 3237 * @param string $method 3238 * @param array $args 3239 * @return string 3240 * @throws Zend_Form_Exception for invalid decorator or invalid method call 3241 */ 3242 public function __call($method, $args) 3243 { 3244 if ('render' == substr($method, 0, 6)) { 3245 $decoratorName = substr($method, 6); 3246 if (false !== ($decorator = $this->getDecorator($decoratorName))) { 3247 $decorator->setElement($this); 3248 $seed = ''; 3249 if (0 < count($args)) { 3250 $seed = array_shift($args); 3251 } 3252 if ($decoratorName === 'FormElements' || 3253 $decoratorName === 'PrepareElements') { 3254 $this->_setIsRendered(); 3255 } 3256 return $decorator->render($seed); 3257 } 3258 3259 // require_once 'Zend/Form/Exception.php'; 3260 throw new Zend_Form_Exception(sprintf('Decorator by name %s does not exist', $decoratorName)); 3261 } 3262 3263 // require_once 'Zend/Form/Exception.php'; 3264 throw new Zend_Form_Exception(sprintf('Method %s does not exist', $method)); 3265 } 3266 3267 // Interfaces: Iterator, Countable 3268 3269 /** 3270 * Current element/subform/display group 3271 * 3272 * @throws Zend_Form_Exception 3273 * @return Zend_Form_Element|Zend_Form_DisplayGroup|Zend_Form 3274 */ 3275 public function current() 3276 { 3277 $this->_sort(); 3278 current($this->_order); 3279 $key = key($this->_order); 3280 3281 if (isset($this->_elements[$key])) { 3282 return $this->getElement($key); 3283 } elseif (isset($this->_subForms[$key])) { 3284 return $this->getSubForm($key); 3285 } elseif (isset($this->_displayGroups[$key])) { 3286 return $this->getDisplayGroup($key); 3287 } else { 3288 // require_once 'Zend/Form/Exception.php'; 3289 throw new Zend_Form_Exception(sprintf('Corruption detected in form; invalid key ("%s") found in internal iterator', (string) $key)); 3290 } 3291 } 3292 3293 /** 3294 * Current element/subform/display group name 3295 * 3296 * @return string 3297 */ 3298 public function key() 3299 { 3300 $this->_sort(); 3301 return key($this->_order); 3302 } 3303 3304 /** 3305 * Move pointer to next element/subform/display group 3306 * 3307 * @return void 3308 */ 3309 public function next() 3310 { 3311 $this->_sort(); 3312 next($this->_order); 3313 } 3314 3315 /** 3316 * Move pointer to beginning of element/subform/display group loop 3317 * 3318 * @return void 3319 */ 3320 public function rewind() 3321 { 3322 $this->_sort(); 3323 reset($this->_order); 3324 } 3325 3326 /** 3327 * Determine if current element/subform/display group is valid 3328 * 3329 * @return bool 3330 */ 3331 public function valid() 3332 { 3333 $this->_sort(); 3334 return (current($this->_order) !== false); 3335 } 3336 3337 /** 3338 * Count of elements/subforms that are iterable 3339 * 3340 * @return int 3341 */ 3342 public function count() 3343 { 3344 return count($this->_order); 3345 } 3346 3347 /** 3348 * Set flag to disable loading default decorators 3349 * 3350 * @param bool $flag 3351 * @return Zend_Form 3352 */ 3353 public function setDisableLoadDefaultDecorators($flag) 3354 { 3355 $this->_disableLoadDefaultDecorators = (bool) $flag; 3356 return $this; 3357 } 3358 3359 /** 3360 * Should we load the default decorators? 3361 * 3362 * @return bool 3363 */ 3364 public function loadDefaultDecoratorsIsDisabled() 3365 { 3366 return $this->_disableLoadDefaultDecorators; 3367 } 3368 3369 /** 3370 * Load the default decorators 3371 * 3372 * @return Zend_Form 3373 */ 3374 public function loadDefaultDecorators() 3375 { 3376 if ($this->loadDefaultDecoratorsIsDisabled()) { 3377 return $this; 3378 } 3379 3380 $decorators = $this->getDecorators(); 3381 if (empty($decorators)) { 3382 $this->addDecorator('FormElements') 3383 ->addDecorator('HtmlTag', array('tag' => 'dl', 'class' => 'zend_form')) 3384 ->addDecorator('Form'); 3385 } 3386 return $this; 3387 } 3388 3389 /** 3390 * Remove an element from iteration 3391 * 3392 * @param string $name Element/group/form name 3393 * @return void 3394 */ 3395 public function removeFromIteration($name) 3396 { 3397 if (array_key_exists($name, $this->_order)) { 3398 unset($this->_order[$name]); 3399 $this->_orderUpdated = true; 3400 } 3401 } 3402 3403 /** 3404 * Sort items according to their order 3405 * 3406 * @throws Zend_Form_Exception 3407 * @return void 3408 */ 3409 protected function _sort() 3410 { 3411 if ($this->_orderUpdated) { 3412 $items = array(); 3413 $index = 0; 3414 foreach ($this->_order as $key => $order) { 3415 if (null === $order) { 3416 if (null === ($order = $this->{$key}->getOrder())) { 3417 while (array_search($index, $this->_order, true)) { 3418 ++$index; 3419 } 3420 $items[$index] = $key; 3421 ++$index; 3422 } else { 3423 $items[$order] = $key; 3424 } 3425 } elseif (isset($items[$order]) && $items[$order] !== $key) { 3426 throw new Zend_Form_Exception('Form elements ' . 3427 $items[$order] . ' and ' . $key . 3428 ' have the same order (' . 3429 $order . ') - ' . 3430 'this would result in only the last added element to be rendered' 3431 ); 3432 } else { 3433 $items[$order] = $key; 3434 } 3435 } 3436 3437 $items = array_flip($items); 3438 asort($items); 3439 $this->_order = $items; 3440 $this->_orderUpdated = false; 3441 } 3442 } 3443 3444 /** 3445 * Lazy-load a decorator 3446 * 3447 * @param array $decorator Decorator type and options 3448 * @param mixed $name Decorator name or alias 3449 * @return Zend_Form_Decorator_Interface 3450 */ 3451 protected function _loadDecorator(array $decorator, $name) 3452 { 3453 $sameName = false; 3454 if ($name == $decorator['decorator']) { 3455 $sameName = true; 3456 } 3457 3458 $instance = $this->_getDecorator($decorator['decorator'], $decorator['options']); 3459 if ($sameName) { 3460 $newName = get_class($instance); 3461 $decoratorNames = array_keys($this->_decorators); 3462 $order = array_flip($decoratorNames); 3463 $order[$newName] = $order[$name]; 3464 $decoratorsExchange = array(); 3465 unset($order[$name]); 3466 asort($order); 3467 foreach ($order as $key => $index) { 3468 if ($key == $newName) { 3469 $decoratorsExchange[$key] = $instance; 3470 continue; 3471 } 3472 $decoratorsExchange[$key] = $this->_decorators[$key]; 3473 } 3474 $this->_decorators = $decoratorsExchange; 3475 } else { 3476 $this->_decorators[$name] = $instance; 3477 } 3478 3479 return $instance; 3480 } 3481 3482 /** 3483 * Retrieve optionally translated custom error messages 3484 * 3485 * @return array 3486 */ 3487 protected function _getErrorMessages() 3488 { 3489 $messages = $this->getErrorMessages(); 3490 $translator = $this->getTranslator(); 3491 if (null !== $translator) { 3492 foreach ($messages as $key => $message) { 3493 $messages[$key] = $translator->translate($message); 3494 } 3495 } 3496 return $messages; 3497 } 3498 }