File indexing completed on 2024-12-22 05:36:43
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_Filter */ 0022 // require_once 'Zend/Filter.php'; 0023 0024 /** @see Zend_Form */ 0025 // require_once 'Zend/Form.php'; 0026 0027 /** @see Zend_Validate_Interface */ 0028 // require_once 'Zend/Validate/Interface.php'; 0029 0030 /** @see Zend_Validate_Abstract */ 0031 // require_once 'Zend/Validate/Abstract.php'; 0032 0033 /** 0034 * Zend_Form_Element 0035 * 0036 * @category Zend 0037 * @package Zend_Form 0038 * @subpackage Element 0039 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0040 * @license http://framework.zend.com/license/new-bsd New BSD License 0041 * @version $Id$ 0042 */ 0043 class Zend_Form_Element implements Zend_Validate_Interface 0044 { 0045 /** 0046 * Element Constants 0047 */ 0048 const DECORATOR = 'DECORATOR'; 0049 const FILTER = 'FILTER'; 0050 const VALIDATE = 'VALIDATE'; 0051 0052 /** 0053 * Default view helper to use 0054 * @var string 0055 */ 0056 public $helper = 'formText'; 0057 0058 /** 0059 * 'Allow empty' flag 0060 * @var bool 0061 */ 0062 protected $_allowEmpty = true; 0063 0064 /** 0065 * Flag indicating whether or not to insert NotEmpty validator when element is required 0066 * @var bool 0067 */ 0068 protected $_autoInsertNotEmptyValidator = true; 0069 0070 /** 0071 * Array to which element belongs 0072 * @var string 0073 */ 0074 protected $_belongsTo; 0075 0076 /** 0077 * Element decorators 0078 * @var array 0079 */ 0080 protected $_decorators = array(); 0081 0082 /** 0083 * Element description 0084 * @var string 0085 */ 0086 protected $_description; 0087 0088 /** 0089 * Should we disable loading the default decorators? 0090 * @var bool 0091 */ 0092 protected $_disableLoadDefaultDecorators = false; 0093 0094 /** 0095 * Custom error messages 0096 * @var array 0097 */ 0098 protected $_errorMessages = array(); 0099 0100 /** 0101 * Validation errors 0102 * @var array 0103 */ 0104 protected $_errors = array(); 0105 0106 /** 0107 * Separator to use when concatenating aggregate error messages (for 0108 * elements having array values) 0109 * @var string 0110 */ 0111 protected $_errorMessageSeparator = '; '; 0112 0113 /** 0114 * Element filters 0115 * @var array 0116 */ 0117 protected $_filters = array(); 0118 0119 /** 0120 * Ignore flag (used when retrieving values at form level) 0121 * @var bool 0122 */ 0123 protected $_ignore = false; 0124 0125 /** 0126 * Does the element represent an array? 0127 * @var bool 0128 */ 0129 protected $_isArray = false; 0130 0131 /** 0132 * Is the error marked as in an invalid state? 0133 * @var bool 0134 */ 0135 protected $_isError = false; 0136 0137 /** 0138 * Has the element been manually marked as invalid? 0139 * @var bool 0140 */ 0141 protected $_isErrorForced = false; 0142 0143 /** 0144 * Element label 0145 * @var string 0146 */ 0147 protected $_label; 0148 0149 /** 0150 * Plugin loaders for filter and validator chains 0151 * @var array 0152 */ 0153 protected $_loaders = array(); 0154 0155 /** 0156 * Formatted validation error messages 0157 * @var array 0158 */ 0159 protected $_messages = array(); 0160 0161 /** 0162 * Element name 0163 * @var string 0164 */ 0165 protected $_name; 0166 0167 /** 0168 * Order of element 0169 * @var int 0170 */ 0171 protected $_order; 0172 0173 /** 0174 * Required flag 0175 * @var bool 0176 */ 0177 protected $_required = false; 0178 0179 /** 0180 * @var Zend_Translate 0181 */ 0182 protected $_translator; 0183 0184 /** 0185 * Is translation disabled? 0186 * @var bool 0187 */ 0188 protected $_translatorDisabled = false; 0189 0190 /** 0191 * Element type 0192 * @var string 0193 */ 0194 protected $_type; 0195 0196 /** 0197 * Array of initialized validators 0198 * @var array Validators 0199 */ 0200 protected $_validators = array(); 0201 0202 /** 0203 * Array of un-initialized validators 0204 * @var array 0205 */ 0206 protected $_validatorRules = array(); 0207 0208 /** 0209 * Element value 0210 * @var mixed 0211 */ 0212 protected $_value; 0213 0214 /** 0215 * @var Zend_View_Interface 0216 */ 0217 protected $_view; 0218 0219 /** 0220 * Is a specific decorator being rendered via the magic renderDecorator()? 0221 * 0222 * This is to allow execution of logic inside the render() methods of child 0223 * elements during the magic call while skipping the parent render() method. 0224 * 0225 * @var bool 0226 */ 0227 protected $_isPartialRendering = false; 0228 0229 /** 0230 * Use one error message for array elements with concatenated values 0231 * 0232 * @var bool 0233 */ 0234 protected $_concatJustValuesInErrorMessage = false; 0235 0236 /** 0237 * Constructor 0238 * 0239 * $spec may be: 0240 * - string: name of element 0241 * - array: options with which to configure element 0242 * - Zend_Config: Zend_Config with options for configuring element 0243 * 0244 * @param string|array|Zend_Config $spec 0245 * @param array|Zend_Config $options 0246 * @return void 0247 * @throws Zend_Form_Exception if no element name after initialization 0248 */ 0249 public function __construct($spec, $options = null) 0250 { 0251 if (is_string($spec)) { 0252 $this->setName($spec); 0253 } elseif (is_array($spec)) { 0254 $this->setOptions($spec); 0255 } elseif ($spec instanceof Zend_Config) { 0256 $this->setConfig($spec); 0257 } 0258 0259 if (is_string($spec) && is_array($options)) { 0260 $this->setOptions($options); 0261 } elseif (is_string($spec) && ($options instanceof Zend_Config)) { 0262 $this->setConfig($options); 0263 } 0264 0265 if (null === $this->getName()) { 0266 // require_once 'Zend/Form/Exception.php'; 0267 throw new Zend_Form_Exception('Zend_Form_Element requires each element to have a name'); 0268 } 0269 0270 /** 0271 * Extensions 0272 */ 0273 $this->init(); 0274 0275 /** 0276 * Register ViewHelper decorator by default 0277 */ 0278 $this->loadDefaultDecorators(); 0279 } 0280 0281 /** 0282 * Initialize object; used by extending classes 0283 * 0284 * @return void 0285 */ 0286 public function init() 0287 { 0288 } 0289 0290 /** 0291 * Set flag to disable loading default decorators 0292 * 0293 * @param bool $flag 0294 * @return Zend_Form_Element 0295 */ 0296 public function setDisableLoadDefaultDecorators($flag) 0297 { 0298 $this->_disableLoadDefaultDecorators = (bool) $flag; 0299 return $this; 0300 } 0301 0302 /** 0303 * Should we load the default decorators? 0304 * 0305 * @return bool 0306 */ 0307 public function loadDefaultDecoratorsIsDisabled() 0308 { 0309 return $this->_disableLoadDefaultDecorators; 0310 } 0311 0312 /** 0313 * Load default decorators 0314 * 0315 * @return Zend_Form_Element 0316 */ 0317 public function loadDefaultDecorators() 0318 { 0319 if ($this->loadDefaultDecoratorsIsDisabled()) { 0320 return $this; 0321 } 0322 0323 $decorators = $this->getDecorators(); 0324 if (empty($decorators)) { 0325 $this->addDecorator('ViewHelper') 0326 ->addDecorator('Errors') 0327 ->addDecorator('Description', array('tag' => 'p', 'class' => 'description')) 0328 ->addDecorator('HtmlTag', array( 0329 'tag' => 'dd', 0330 'id' => array('callback' => array(get_class($this), 'resolveElementId')) 0331 )) 0332 ->addDecorator('Label', array('tag' => 'dt')); 0333 } 0334 return $this; 0335 } 0336 0337 /** 0338 * Used to resolve and return an element ID 0339 * 0340 * Passed to the HtmlTag decorator as a callback in order to provide an ID. 0341 * 0342 * @param Zend_Form_Decorator_Interface $decorator 0343 * @return string 0344 */ 0345 public static function resolveElementId(Zend_Form_Decorator_Interface $decorator) 0346 { 0347 return $decorator->getElement()->getId() . '-element'; 0348 } 0349 0350 /** 0351 * Set object state from options array 0352 * 0353 * @param array $options 0354 * @return Zend_Form_Element 0355 */ 0356 public function setOptions(array $options) 0357 { 0358 if (isset($options['prefixPath'])) { 0359 $this->addPrefixPaths($options['prefixPath']); 0360 unset($options['prefixPath']); 0361 } 0362 0363 if (isset($options['disableTranslator'])) { 0364 $this->setDisableTranslator($options['disableTranslator']); 0365 unset($options['disableTranslator']); 0366 } 0367 0368 unset($options['options']); 0369 unset($options['config']); 0370 0371 foreach ($options as $key => $value) { 0372 $method = 'set' . ucfirst($key); 0373 0374 if (in_array($method, array('setTranslator', 'setPluginLoader', 'setView'))) { 0375 if (!is_object($value)) { 0376 continue; 0377 } 0378 } 0379 0380 if (method_exists($this, $method)) { 0381 // Setter exists; use it 0382 $this->$method($value); 0383 } else { 0384 // Assume it's metadata 0385 $this->setAttrib($key, $value); 0386 } 0387 } 0388 return $this; 0389 } 0390 0391 /** 0392 * Set object state from Zend_Config object 0393 * 0394 * @param Zend_Config $config 0395 * @return Zend_Form_Element 0396 */ 0397 public function setConfig(Zend_Config $config) 0398 { 0399 return $this->setOptions($config->toArray()); 0400 } 0401 0402 0403 // Localization: 0404 0405 /** 0406 * Set translator object for localization 0407 * 0408 * @param Zend_Translate|null $translator 0409 * @return Zend_Form_Element 0410 */ 0411 public function setTranslator($translator = null) 0412 { 0413 if (null === $translator) { 0414 $this->_translator = null; 0415 } elseif ($translator instanceof Zend_Translate_Adapter) { 0416 $this->_translator = $translator; 0417 } elseif ($translator instanceof Zend_Translate) { 0418 $this->_translator = $translator->getAdapter(); 0419 } else { 0420 // require_once 'Zend/Form/Exception.php'; 0421 throw new Zend_Form_Exception('Invalid translator specified'); 0422 } 0423 return $this; 0424 } 0425 0426 /** 0427 * Retrieve localization translator object 0428 * 0429 * @return Zend_Translate_Adapter|null 0430 */ 0431 public function getTranslator() 0432 { 0433 if ($this->translatorIsDisabled()) { 0434 return null; 0435 } 0436 0437 if (null === $this->_translator) { 0438 return Zend_Form::getDefaultTranslator(); 0439 } 0440 return $this->_translator; 0441 } 0442 0443 /** 0444 * Does this element have its own specific translator? 0445 * 0446 * @return bool 0447 */ 0448 public function hasTranslator() 0449 { 0450 return (bool)$this->_translator; 0451 } 0452 0453 /** 0454 * Indicate whether or not translation should be disabled 0455 * 0456 * @param bool $flag 0457 * @return Zend_Form_Element 0458 */ 0459 public function setDisableTranslator($flag) 0460 { 0461 $this->_translatorDisabled = (bool) $flag; 0462 return $this; 0463 } 0464 0465 /** 0466 * Is translation disabled? 0467 * 0468 * @return bool 0469 */ 0470 public function translatorIsDisabled() 0471 { 0472 return $this->_translatorDisabled; 0473 } 0474 0475 // Metadata 0476 0477 /** 0478 * Filter a name to only allow valid variable characters 0479 * 0480 * @param string $value 0481 * @param bool $allowBrackets 0482 * @return string 0483 */ 0484 public function filterName($value, $allowBrackets = false) 0485 { 0486 $charset = '^a-zA-Z0-9_\x7f-\xff'; 0487 if ($allowBrackets) { 0488 $charset .= '\[\]'; 0489 } 0490 return preg_replace('/[' . $charset . ']/', '', (string) $value); 0491 } 0492 0493 /** 0494 * Set element name 0495 * 0496 * @param string $name 0497 * @return Zend_Form_Element 0498 */ 0499 public function setName($name) 0500 { 0501 $name = $this->filterName($name); 0502 if ('' === $name) { 0503 // require_once 'Zend/Form/Exception.php'; 0504 throw new Zend_Form_Exception('Invalid name provided; must contain only valid variable characters and be non-empty'); 0505 } 0506 0507 $this->_name = $name; 0508 return $this; 0509 } 0510 0511 /** 0512 * Return element name 0513 * 0514 * @return string 0515 */ 0516 public function getName() 0517 { 0518 return $this->_name; 0519 } 0520 0521 /** 0522 * Get fully qualified name 0523 * 0524 * Places name as subitem of array and/or appends brackets. 0525 * 0526 * @return string 0527 */ 0528 public function getFullyQualifiedName() 0529 { 0530 $name = $this->getName(); 0531 0532 if (null !== ($belongsTo = $this->getBelongsTo())) { 0533 $name = $belongsTo . '[' . $name . ']'; 0534 } 0535 0536 if ($this->isArray()) { 0537 $name .= '[]'; 0538 } 0539 0540 return $name; 0541 } 0542 0543 /** 0544 * Get element id 0545 * 0546 * @return string 0547 */ 0548 public function getId() 0549 { 0550 if (isset($this->id)) { 0551 return $this->id; 0552 } 0553 0554 $id = $this->getFullyQualifiedName(); 0555 0556 // Bail early if no array notation detected 0557 if (!strstr($id, '[')) { 0558 return $id; 0559 } 0560 0561 // Strip array notation 0562 if ('[]' == substr($id, -2)) { 0563 $id = substr($id, 0, strlen($id) - 2); 0564 } 0565 $id = str_replace('][', '-', $id); 0566 $id = str_replace(array(']', '['), '-', $id); 0567 $id = trim($id, '-'); 0568 0569 return $id; 0570 } 0571 0572 /** 0573 * Set element value 0574 * 0575 * @param mixed $value 0576 * @return Zend_Form_Element 0577 */ 0578 public function setValue($value) 0579 { 0580 $this->_value = $value; 0581 return $this; 0582 } 0583 0584 /** 0585 * Filter a value 0586 * 0587 * @param string $value 0588 * @param string $key 0589 * @return void 0590 */ 0591 protected function _filterValue(&$value, &$key) 0592 { 0593 foreach ($this->getFilters() as $filter) { 0594 $value = $filter->filter($value); 0595 } 0596 } 0597 0598 /** 0599 * Retrieve filtered element value 0600 * 0601 * @return mixed 0602 */ 0603 public function getValue() 0604 { 0605 $valueFiltered = $this->_value; 0606 0607 if ($this->isArray() && is_array($valueFiltered)) { 0608 array_walk_recursive($valueFiltered, array($this, '_filterValue')); 0609 } else { 0610 $this->_filterValue($valueFiltered, $valueFiltered); 0611 } 0612 0613 return $valueFiltered; 0614 } 0615 0616 /** 0617 * Retrieve unfiltered element value 0618 * 0619 * @return mixed 0620 */ 0621 public function getUnfilteredValue() 0622 { 0623 return $this->_value; 0624 } 0625 0626 /** 0627 * Set element label 0628 * 0629 * @param string $label 0630 * @return Zend_Form_Element 0631 */ 0632 public function setLabel($label) 0633 { 0634 $this->_label = (string) $label; 0635 return $this; 0636 } 0637 0638 /** 0639 * Retrieve element label 0640 * 0641 * @return string 0642 */ 0643 public function getLabel() 0644 { 0645 $translator = $this->getTranslator(); 0646 if (null !== $translator) { 0647 return $translator->translate($this->_label); 0648 } 0649 0650 return $this->_label; 0651 } 0652 0653 /** 0654 * Set element order 0655 * 0656 * @param int $order 0657 * @return Zend_Form_Element 0658 */ 0659 public function setOrder($order) 0660 { 0661 $this->_order = (int) $order; 0662 return $this; 0663 } 0664 0665 /** 0666 * Retrieve element order 0667 * 0668 * @return int 0669 */ 0670 public function getOrder() 0671 { 0672 return $this->_order; 0673 } 0674 0675 /** 0676 * Set required flag 0677 * 0678 * @param bool $flag Default value is true 0679 * @return Zend_Form_Element 0680 */ 0681 public function setRequired($flag = true) 0682 { 0683 $this->_required = (bool) $flag; 0684 return $this; 0685 } 0686 0687 /** 0688 * Is the element required? 0689 * 0690 * @return bool 0691 */ 0692 public function isRequired() 0693 { 0694 return $this->_required; 0695 } 0696 0697 /** 0698 * Set flag indicating whether a NotEmpty validator should be inserted when element is required 0699 * 0700 * @param bool $flag 0701 * @return Zend_Form_Element 0702 */ 0703 public function setAutoInsertNotEmptyValidator($flag) 0704 { 0705 $this->_autoInsertNotEmptyValidator = (bool) $flag; 0706 return $this; 0707 } 0708 0709 /** 0710 * Get flag indicating whether a NotEmpty validator should be inserted when element is required 0711 * 0712 * @return bool 0713 */ 0714 public function autoInsertNotEmptyValidator() 0715 { 0716 return $this->_autoInsertNotEmptyValidator; 0717 } 0718 0719 /** 0720 * Set element description 0721 * 0722 * @param string $description 0723 * @return Zend_Form_Element 0724 */ 0725 public function setDescription($description) 0726 { 0727 $this->_description = (string) $description; 0728 return $this; 0729 } 0730 0731 /** 0732 * Retrieve element description 0733 * 0734 * @return string 0735 */ 0736 public function getDescription() 0737 { 0738 return $this->_description; 0739 } 0740 0741 /** 0742 * Set 'allow empty' flag 0743 * 0744 * When the allow empty flag is enabled and the required flag is false, the 0745 * element will validate with empty values. 0746 * 0747 * @param bool $flag 0748 * @return Zend_Form_Element 0749 */ 0750 public function setAllowEmpty($flag) 0751 { 0752 $this->_allowEmpty = (bool) $flag; 0753 return $this; 0754 } 0755 0756 /** 0757 * Get 'allow empty' flag 0758 * 0759 * @return bool 0760 */ 0761 public function getAllowEmpty() 0762 { 0763 return $this->_allowEmpty; 0764 } 0765 0766 /** 0767 * Set ignore flag (used when retrieving values at form level) 0768 * 0769 * @param bool $flag 0770 * @return Zend_Form_Element 0771 */ 0772 public function setIgnore($flag) 0773 { 0774 $this->_ignore = (bool) $flag; 0775 return $this; 0776 } 0777 0778 /** 0779 * Get ignore flag (used when retrieving values at form level) 0780 * 0781 * @return bool 0782 */ 0783 public function getIgnore() 0784 { 0785 return $this->_ignore; 0786 } 0787 0788 /** 0789 * Set flag indicating if element represents an array 0790 * 0791 * @param bool $flag 0792 * @return Zend_Form_Element 0793 */ 0794 public function setIsArray($flag) 0795 { 0796 $this->_isArray = (bool) $flag; 0797 return $this; 0798 } 0799 0800 /** 0801 * Is the element representing an array? 0802 * 0803 * @return bool 0804 */ 0805 public function isArray() 0806 { 0807 return $this->_isArray; 0808 } 0809 0810 /** 0811 * Set array to which element belongs 0812 * 0813 * @param string $array 0814 * @return Zend_Form_Element 0815 */ 0816 public function setBelongsTo($array) 0817 { 0818 $array = $this->filterName($array, true); 0819 if (!empty($array)) { 0820 $this->_belongsTo = $array; 0821 } 0822 0823 return $this; 0824 } 0825 0826 /** 0827 * Return array name to which element belongs 0828 * 0829 * @return string 0830 */ 0831 public function getBelongsTo() 0832 { 0833 return $this->_belongsTo; 0834 } 0835 0836 /** 0837 * Return element type 0838 * 0839 * @return string 0840 */ 0841 public function getType() 0842 { 0843 if (null === $this->_type) { 0844 $this->_type = get_class($this); 0845 } 0846 0847 return $this->_type; 0848 } 0849 0850 /** 0851 * Set element attribute 0852 * 0853 * @param string $name 0854 * @param mixed $value 0855 * @return Zend_Form_Element 0856 * @throws Zend_Form_Exception for invalid $name values 0857 */ 0858 public function setAttrib($name, $value) 0859 { 0860 $name = (string) $name; 0861 if ('_' == $name[0]) { 0862 // require_once 'Zend/Form/Exception.php'; 0863 throw new Zend_Form_Exception(sprintf('Invalid attribute "%s"; must not contain a leading underscore', $name)); 0864 } 0865 0866 if (null === $value) { 0867 unset($this->$name); 0868 } else { 0869 $this->$name = $value; 0870 } 0871 0872 return $this; 0873 } 0874 0875 /** 0876 * Set multiple attributes at once 0877 * 0878 * @param array $attribs 0879 * @return Zend_Form_Element 0880 */ 0881 public function setAttribs(array $attribs) 0882 { 0883 foreach ($attribs as $key => $value) { 0884 $this->setAttrib($key, $value); 0885 } 0886 0887 return $this; 0888 } 0889 0890 /** 0891 * Retrieve element attribute 0892 * 0893 * @param string $name 0894 * @return string 0895 */ 0896 public function getAttrib($name) 0897 { 0898 $name = (string) $name; 0899 if (isset($this->$name)) { 0900 return $this->$name; 0901 } 0902 0903 return null; 0904 } 0905 0906 /** 0907 * Return all attributes 0908 * 0909 * @return array 0910 */ 0911 public function getAttribs() 0912 { 0913 $attribs = get_object_vars($this); 0914 unset($attribs['helper']); 0915 foreach ($attribs as $key => $value) { 0916 if ('_' == substr($key, 0, 1)) { 0917 unset($attribs[$key]); 0918 } 0919 } 0920 0921 return $attribs; 0922 } 0923 0924 /** 0925 * Use one error message for array elements with concatenated values 0926 * 0927 * @param boolean $concatJustValuesInErrorMessage 0928 * @return Zend_Form_Element 0929 */ 0930 public function setConcatJustValuesInErrorMessage($concatJustValuesInErrorMessage) 0931 { 0932 $this->_concatJustValuesInErrorMessage = $concatJustValuesInErrorMessage; 0933 return $this; 0934 } 0935 0936 /** 0937 * Use one error message for array elements with concatenated values 0938 * 0939 * @return boolean 0940 */ 0941 public function getConcatJustValuesInErrorMessage() 0942 { 0943 return $this->_concatJustValuesInErrorMessage; 0944 } 0945 0946 /** 0947 * Overloading: retrieve object property 0948 * 0949 * Prevents access to properties beginning with '_'. 0950 * 0951 * @param string $key 0952 * @return mixed 0953 */ 0954 public function __get($key) 0955 { 0956 if ('_' == $key[0]) { 0957 // require_once 'Zend/Form/Exception.php'; 0958 throw new Zend_Form_Exception(sprintf('Cannot retrieve value for protected/private property "%s"', $key)); 0959 } 0960 0961 if (!isset($this->$key)) { 0962 return null; 0963 } 0964 0965 return $this->$key; 0966 } 0967 0968 /** 0969 * Overloading: set object property 0970 * 0971 * @param string $key 0972 * @param mixed $value 0973 * @return voide 0974 */ 0975 public function __set($key, $value) 0976 { 0977 $this->setAttrib($key, $value); 0978 } 0979 0980 /** 0981 * Overloading: allow rendering specific decorators 0982 * 0983 * Call renderDecoratorName() to render a specific decorator. 0984 * 0985 * @param string $method 0986 * @param array $args 0987 * @return string 0988 * @throws Zend_Form_Exception for invalid decorator or invalid method call 0989 */ 0990 public function __call($method, $args) 0991 { 0992 if ('render' == substr($method, 0, 6)) { 0993 $this->_isPartialRendering = true; 0994 $this->render(); 0995 $this->_isPartialRendering = false; 0996 $decoratorName = substr($method, 6); 0997 if (false !== ($decorator = $this->getDecorator($decoratorName))) { 0998 $decorator->setElement($this); 0999 $seed = ''; 1000 if (0 < count($args)) { 1001 $seed = array_shift($args); 1002 } 1003 return $decorator->render($seed); 1004 } 1005 1006 // require_once 'Zend/Form/Element/Exception.php'; 1007 throw new Zend_Form_Element_Exception(sprintf('Decorator by name %s does not exist', $decoratorName)); 1008 } 1009 1010 // require_once 'Zend/Form/Element/Exception.php'; 1011 throw new Zend_Form_Element_Exception(sprintf('Method %s does not exist', $method)); 1012 } 1013 1014 // Loaders 1015 1016 /** 1017 * Set plugin loader to use for validator or filter chain 1018 * 1019 * @param Zend_Loader_PluginLoader_Interface $loader 1020 * @param string $type 'decorator', 'filter', or 'validate' 1021 * @return Zend_Form_Element 1022 * @throws Zend_Form_Exception on invalid type 1023 */ 1024 public function setPluginLoader(Zend_Loader_PluginLoader_Interface $loader, $type) 1025 { 1026 $type = strtoupper($type); 1027 switch ($type) { 1028 case self::DECORATOR: 1029 case self::FILTER: 1030 case self::VALIDATE: 1031 $this->_loaders[$type] = $loader; 1032 return $this; 1033 default: 1034 // require_once 'Zend/Form/Exception.php'; 1035 throw new Zend_Form_Exception(sprintf('Invalid type "%s" provided to setPluginLoader()', $type)); 1036 } 1037 } 1038 1039 /** 1040 * Retrieve plugin loader for validator or filter chain 1041 * 1042 * Instantiates with default rules if none available for that type. Use 1043 * 'decorator', 'filter', or 'validate' for $type. 1044 * 1045 * @param string $type 1046 * @return Zend_Loader_PluginLoader 1047 * @throws Zend_Loader_Exception on invalid type. 1048 */ 1049 public function getPluginLoader($type) 1050 { 1051 $type = strtoupper($type); 1052 switch ($type) { 1053 case self::FILTER: 1054 case self::VALIDATE: 1055 $prefixSegment = ucfirst(strtolower($type)); 1056 $pathSegment = $prefixSegment; 1057 case self::DECORATOR: 1058 if (!isset($prefixSegment)) { 1059 $prefixSegment = 'Form_Decorator'; 1060 $pathSegment = 'Form/Decorator'; 1061 } 1062 if (!isset($this->_loaders[$type])) { 1063 // require_once 'Zend/Loader/PluginLoader.php'; 1064 $this->_loaders[$type] = new Zend_Loader_PluginLoader( 1065 array('Zend_' . $prefixSegment . '_' => 'Zend/' . $pathSegment . '/') 1066 ); 1067 } 1068 return $this->_loaders[$type]; 1069 default: 1070 // require_once 'Zend/Form/Exception.php'; 1071 throw new Zend_Form_Exception(sprintf('Invalid type "%s" provided to getPluginLoader()', $type)); 1072 } 1073 } 1074 1075 /** 1076 * Add prefix path for plugin loader 1077 * 1078 * If no $type specified, assumes it is a base path for both filters and 1079 * validators, and sets each according to the following rules: 1080 * - decorators: $prefix = $prefix . '_Decorator' 1081 * - filters: $prefix = $prefix . '_Filter' 1082 * - validators: $prefix = $prefix . '_Validate' 1083 * 1084 * Otherwise, the path prefix is set on the appropriate plugin loader. 1085 * 1086 * @param string $prefix 1087 * @param string $path 1088 * @param string $type 1089 * @return Zend_Form_Element 1090 * @throws Zend_Form_Exception for invalid type 1091 */ 1092 public function addPrefixPath($prefix, $path, $type = null) 1093 { 1094 $type = strtoupper($type); 1095 switch ($type) { 1096 case self::DECORATOR: 1097 case self::FILTER: 1098 case self::VALIDATE: 1099 $loader = $this->getPluginLoader($type); 1100 $loader->addPrefixPath($prefix, $path); 1101 return $this; 1102 case null: 1103 $nsSeparator = (false !== strpos($prefix, '\\'))?'\\':'_'; 1104 $prefix = rtrim($prefix, $nsSeparator) . $nsSeparator; 1105 $path = rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR; 1106 foreach (array(self::DECORATOR, self::FILTER, self::VALIDATE) as $type) { 1107 $cType = ucfirst(strtolower($type)); 1108 $loader = $this->getPluginLoader($type); 1109 $loader->addPrefixPath($prefix . $cType, $path . $cType . DIRECTORY_SEPARATOR); 1110 } 1111 return $this; 1112 default: 1113 // require_once 'Zend/Form/Exception.php'; 1114 throw new Zend_Form_Exception(sprintf('Invalid type "%s" provided to getPluginLoader()', $type)); 1115 } 1116 } 1117 1118 /** 1119 * Add many prefix paths at once 1120 * 1121 * @param array $spec 1122 * @return Zend_Form_Element 1123 */ 1124 public function addPrefixPaths(array $spec) 1125 { 1126 if (isset($spec['prefix']) && isset($spec['path'])) { 1127 return $this->addPrefixPath($spec['prefix'], $spec['path']); 1128 } 1129 foreach ($spec as $type => $paths) { 1130 if (is_numeric($type) && is_array($paths)) { 1131 $type = null; 1132 if (isset($paths['prefix']) && isset($paths['path'])) { 1133 if (isset($paths['type'])) { 1134 $type = $paths['type']; 1135 } 1136 $this->addPrefixPath($paths['prefix'], $paths['path'], $type); 1137 } 1138 } elseif (!is_numeric($type)) { 1139 if (!isset($paths['prefix']) || !isset($paths['path'])) { 1140 foreach ($paths as $prefix => $spec) { 1141 if (is_array($spec)) { 1142 foreach ($spec as $path) { 1143 if (!is_string($path)) { 1144 continue; 1145 } 1146 $this->addPrefixPath($prefix, $path, $type); 1147 } 1148 } elseif (is_string($spec)) { 1149 $this->addPrefixPath($prefix, $spec, $type); 1150 } 1151 } 1152 } else { 1153 $this->addPrefixPath($paths['prefix'], $paths['path'], $type); 1154 } 1155 } 1156 } 1157 return $this; 1158 } 1159 1160 // Validation 1161 1162 /** 1163 * Add validator to validation chain 1164 * 1165 * Note: will overwrite existing validators if they are of the same class. 1166 * 1167 * @param string|Zend_Validate_Interface $validator 1168 * @param bool $breakChainOnFailure 1169 * @param array $options 1170 * @return Zend_Form_Element 1171 * @throws Zend_Form_Exception if invalid validator type 1172 */ 1173 public function addValidator($validator, $breakChainOnFailure = false, $options = array()) 1174 { 1175 if ($validator instanceof Zend_Validate_Interface) { 1176 $name = get_class($validator); 1177 1178 if (!isset($validator->zfBreakChainOnFailure)) { 1179 $validator->zfBreakChainOnFailure = $breakChainOnFailure; 1180 } 1181 } elseif (is_string($validator)) { 1182 $name = $validator; 1183 $validator = array( 1184 'validator' => $validator, 1185 'breakChainOnFailure' => $breakChainOnFailure, 1186 'options' => $options, 1187 ); 1188 } else { 1189 // require_once 'Zend/Form/Exception.php'; 1190 throw new Zend_Form_Exception('Invalid validator provided to addValidator; must be string or Zend_Validate_Interface'); 1191 } 1192 1193 1194 $this->_validators[$name] = $validator; 1195 1196 return $this; 1197 } 1198 1199 /** 1200 * Add multiple validators 1201 * 1202 * @param array $validators 1203 * @return Zend_Form_Element 1204 */ 1205 public function addValidators(array $validators) 1206 { 1207 foreach ($validators as $validatorInfo) { 1208 if (is_string($validatorInfo)) { 1209 $this->addValidator($validatorInfo); 1210 } elseif ($validatorInfo instanceof Zend_Validate_Interface) { 1211 $this->addValidator($validatorInfo); 1212 } elseif (is_array($validatorInfo)) { 1213 $argc = count($validatorInfo); 1214 $breakChainOnFailure = false; 1215 $options = array(); 1216 if (isset($validatorInfo['validator'])) { 1217 $validator = $validatorInfo['validator']; 1218 if (isset($validatorInfo['breakChainOnFailure'])) { 1219 $breakChainOnFailure = $validatorInfo['breakChainOnFailure']; 1220 } 1221 if (isset($validatorInfo['options'])) { 1222 $options = $validatorInfo['options']; 1223 } 1224 $this->addValidator($validator, $breakChainOnFailure, $options); 1225 } else { 1226 switch (true) { 1227 case (0 == $argc): 1228 break; 1229 case (1 <= $argc): 1230 $validator = array_shift($validatorInfo); 1231 case (2 <= $argc): 1232 $breakChainOnFailure = array_shift($validatorInfo); 1233 case (3 <= $argc): 1234 $options = array_shift($validatorInfo); 1235 default: 1236 $this->addValidator($validator, $breakChainOnFailure, $options); 1237 break; 1238 } 1239 } 1240 } else { 1241 // require_once 'Zend/Form/Exception.php'; 1242 throw new Zend_Form_Exception('Invalid validator passed to addValidators()'); 1243 } 1244 } 1245 1246 return $this; 1247 } 1248 1249 /** 1250 * Set multiple validators, overwriting previous validators 1251 * 1252 * @param array $validators 1253 * @return Zend_Form_Element 1254 */ 1255 public function setValidators(array $validators) 1256 { 1257 $this->clearValidators(); 1258 return $this->addValidators($validators); 1259 } 1260 1261 /** 1262 * Retrieve a single validator by name 1263 * 1264 * @param string $name 1265 * @return Zend_Validate_Interface|false False if not found, validator otherwise 1266 */ 1267 public function getValidator($name) 1268 { 1269 if (!isset($this->_validators[$name])) { 1270 $len = strlen($name); 1271 foreach ($this->_validators as $localName => $validator) { 1272 if ($len > strlen($localName)) { 1273 continue; 1274 } 1275 if (0 === substr_compare($localName, $name, -$len, $len, true)) { 1276 if (is_array($validator)) { 1277 return $this->_loadValidator($validator); 1278 } 1279 return $validator; 1280 } 1281 } 1282 return false; 1283 } 1284 1285 if (is_array($this->_validators[$name])) { 1286 return $this->_loadValidator($this->_validators[$name]); 1287 } 1288 1289 return $this->_validators[$name]; 1290 } 1291 1292 /** 1293 * Retrieve all validators 1294 * 1295 * @return array 1296 */ 1297 public function getValidators() 1298 { 1299 $validators = array(); 1300 foreach ($this->_validators as $key => $value) { 1301 if ($value instanceof Zend_Validate_Interface) { 1302 $validators[$key] = $value; 1303 continue; 1304 } 1305 $validator = $this->_loadValidator($value); 1306 $validators[get_class($validator)] = $validator; 1307 } 1308 return $validators; 1309 } 1310 1311 /** 1312 * Remove a single validator by name 1313 * 1314 * @param string $name 1315 * @return bool 1316 */ 1317 public function removeValidator($name) 1318 { 1319 if (isset($this->_validators[$name])) { 1320 unset($this->_validators[$name]); 1321 } else { 1322 $len = strlen($name); 1323 foreach (array_keys($this->_validators) as $validator) { 1324 if ($len > strlen($validator)) { 1325 continue; 1326 } 1327 if (0 === substr_compare($validator, $name, -$len, $len, true)) { 1328 unset($this->_validators[$validator]); 1329 break; 1330 } 1331 } 1332 } 1333 1334 return $this; 1335 } 1336 1337 /** 1338 * Clear all validators 1339 * 1340 * @return Zend_Form_Element 1341 */ 1342 public function clearValidators() 1343 { 1344 $this->_validators = array(); 1345 return $this; 1346 } 1347 1348 /** 1349 * Validate element value 1350 * 1351 * If a translation adapter is registered, any error messages will be 1352 * translated according to the current locale, using the given error code; 1353 * if no matching translation is found, the original message will be 1354 * utilized. 1355 * 1356 * Note: The *filtered* value is validated. 1357 * 1358 * @param mixed $value 1359 * @param mixed $context 1360 * @return boolean 1361 */ 1362 public function isValid($value, $context = null) 1363 { 1364 $this->setValue($value); 1365 $value = $this->getValue(); 1366 1367 if ((('' === $value) || (null === $value)) 1368 && !$this->isRequired() 1369 && $this->getAllowEmpty() 1370 ) { 1371 return true; 1372 } 1373 1374 if ($this->isRequired() 1375 && $this->autoInsertNotEmptyValidator() 1376 && !$this->getValidator('NotEmpty')) 1377 { 1378 $validators = $this->getValidators(); 1379 $notEmpty = array('validator' => 'NotEmpty', 'breakChainOnFailure' => true); 1380 array_unshift($validators, $notEmpty); 1381 $this->setValidators($validators); 1382 } 1383 1384 // Find the correct translator. Zend_Validate_Abstract::getDefaultTranslator() 1385 // will get either the static translator attached to Zend_Validate_Abstract 1386 // or the 'Zend_Translate' from Zend_Registry. 1387 if (Zend_Validate_Abstract::hasDefaultTranslator() && 1388 !Zend_Form::hasDefaultTranslator()) 1389 { 1390 $translator = Zend_Validate_Abstract::getDefaultTranslator(); 1391 if ($this->hasTranslator()) { 1392 // only pick up this element's translator if it was attached directly. 1393 $translator = $this->getTranslator(); 1394 } 1395 } else { 1396 $translator = $this->getTranslator(); 1397 } 1398 1399 $this->_messages = array(); 1400 $this->_errors = array(); 1401 $result = true; 1402 $isArray = $this->isArray(); 1403 foreach ($this->getValidators() as $key => $validator) { 1404 if (method_exists($validator, 'setTranslator')) { 1405 if (method_exists($validator, 'hasTranslator')) { 1406 if (!$validator->hasTranslator()) { 1407 $validator->setTranslator($translator); 1408 } 1409 } else { 1410 $validator->setTranslator($translator); 1411 } 1412 } 1413 1414 if (method_exists($validator, 'setDisableTranslator')) { 1415 $validator->setDisableTranslator($this->translatorIsDisabled()); 1416 } 1417 1418 if ($isArray && is_array($value)) { 1419 $messages = array(); 1420 $errors = array(); 1421 if (empty($value)) { 1422 if ($this->isRequired() 1423 || (!$this->isRequired() && !$this->getAllowEmpty()) 1424 ) { 1425 $value = ''; 1426 } 1427 } 1428 foreach ((array)$value as $val) { 1429 if (!$validator->isValid($val, $context)) { 1430 $result = false; 1431 if ($this->_hasErrorMessages()) { 1432 $messages = $this->_getErrorMessages(); 1433 $errors = $messages; 1434 } else { 1435 $messages = array_merge($messages, $validator->getMessages()); 1436 $errors = array_merge($errors, $validator->getErrors()); 1437 } 1438 } 1439 } 1440 if ($result) { 1441 continue; 1442 } 1443 } elseif ($validator->isValid($value, $context)) { 1444 continue; 1445 } else { 1446 $result = false; 1447 if ($this->_hasErrorMessages()) { 1448 $messages = $this->_getErrorMessages(); 1449 $errors = $messages; 1450 } else { 1451 $messages = $validator->getMessages(); 1452 $errors = array_keys($messages); 1453 } 1454 } 1455 1456 $result = false; 1457 $this->_messages = array_merge($this->_messages, $messages); 1458 $this->_errors = array_merge($this->_errors, $errors); 1459 1460 if ($validator->zfBreakChainOnFailure) { 1461 break; 1462 } 1463 } 1464 1465 // If element manually flagged as invalid, return false 1466 if ($this->_isErrorForced) { 1467 return false; 1468 } 1469 1470 return $result; 1471 } 1472 1473 /** 1474 * Add a custom error message to return in the event of failed validation 1475 * 1476 * @param string $message 1477 * @return Zend_Form_Element 1478 */ 1479 public function addErrorMessage($message) 1480 { 1481 $this->_errorMessages[] = (string) $message; 1482 return $this; 1483 } 1484 1485 /** 1486 * Add multiple custom error messages to return in the event of failed validation 1487 * 1488 * @param array $messages 1489 * @return Zend_Form_Element 1490 */ 1491 public function addErrorMessages(array $messages) 1492 { 1493 foreach ($messages as $message) { 1494 $this->addErrorMessage($message); 1495 } 1496 return $this; 1497 } 1498 1499 /** 1500 * Same as addErrorMessages(), but clears custom error message stack first 1501 * 1502 * @param array $messages 1503 * @return Zend_Form_Element 1504 */ 1505 public function setErrorMessages(array $messages) 1506 { 1507 $this->clearErrorMessages(); 1508 return $this->addErrorMessages($messages); 1509 } 1510 1511 /** 1512 * Retrieve custom error messages 1513 * 1514 * @return array 1515 */ 1516 public function getErrorMessages() 1517 { 1518 return $this->_errorMessages; 1519 } 1520 1521 /** 1522 * Clear custom error messages stack 1523 * 1524 * @return Zend_Form_Element 1525 */ 1526 public function clearErrorMessages() 1527 { 1528 $this->_errorMessages = array(); 1529 return $this; 1530 } 1531 1532 /** 1533 * Get errorMessageSeparator 1534 * 1535 * @return string 1536 */ 1537 public function getErrorMessageSeparator() 1538 { 1539 return $this->_errorMessageSeparator; 1540 } 1541 1542 /** 1543 * Set errorMessageSeparator 1544 * 1545 * @param string $separator 1546 * @return Zend_Form_Element 1547 */ 1548 public function setErrorMessageSeparator($separator) 1549 { 1550 $this->_errorMessageSeparator = $separator; 1551 return $this; 1552 } 1553 1554 /** 1555 * Mark the element as being in a failed validation state 1556 * 1557 * @return Zend_Form_Element 1558 */ 1559 public function markAsError() 1560 { 1561 $messages = $this->getMessages(); 1562 $customMessages = $this->_getErrorMessages(); 1563 $messages = $messages + $customMessages; 1564 if (empty($messages)) { 1565 $this->_isError = true; 1566 } else { 1567 $this->_messages = $messages; 1568 } 1569 $this->_isErrorForced = true; 1570 return $this; 1571 } 1572 1573 /** 1574 * Add an error message and mark element as failed validation 1575 * 1576 * @param string $message 1577 * @return Zend_Form_Element 1578 */ 1579 public function addError($message) 1580 { 1581 $this->addErrorMessage($message); 1582 $this->markAsError(); 1583 return $this; 1584 } 1585 1586 /** 1587 * Add multiple error messages and flag element as failed validation 1588 * 1589 * @param array $messages 1590 * @return Zend_Form_Element 1591 */ 1592 public function addErrors(array $messages) 1593 { 1594 foreach ($messages as $message) { 1595 $this->addError($message); 1596 } 1597 return $this; 1598 } 1599 1600 /** 1601 * Overwrite any previously set error messages and flag as failed validation 1602 * 1603 * @param array $messages 1604 * @return Zend_Form_Element 1605 */ 1606 public function setErrors(array $messages) 1607 { 1608 $this->clearErrorMessages(); 1609 return $this->addErrors($messages); 1610 } 1611 1612 /** 1613 * Are there errors registered? 1614 * 1615 * @return bool 1616 */ 1617 public function hasErrors() 1618 { 1619 return (!empty($this->_messages) || $this->_isError); 1620 } 1621 1622 /** 1623 * Retrieve validator chain errors 1624 * 1625 * @return array 1626 */ 1627 public function getErrors() 1628 { 1629 return $this->_errors; 1630 } 1631 1632 /** 1633 * Retrieve error messages 1634 * 1635 * @return array 1636 */ 1637 public function getMessages() 1638 { 1639 return $this->_messages; 1640 } 1641 1642 1643 // Filtering 1644 1645 /** 1646 * Add a filter to the element 1647 * 1648 * @param string|Zend_Filter_Interface $filter 1649 * @return Zend_Form_Element 1650 */ 1651 public function addFilter($filter, $options = array()) 1652 { 1653 if ($filter instanceof Zend_Filter_Interface) { 1654 $name = get_class($filter); 1655 } elseif (is_string($filter)) { 1656 $name = $filter; 1657 $filter = array( 1658 'filter' => $filter, 1659 'options' => $options, 1660 ); 1661 $this->_filters[$name] = $filter; 1662 } else { 1663 // require_once 'Zend/Form/Exception.php'; 1664 throw new Zend_Form_Exception('Invalid filter provided to addFilter; must be string or Zend_Filter_Interface'); 1665 } 1666 1667 $this->_filters[$name] = $filter; 1668 1669 return $this; 1670 } 1671 1672 /** 1673 * Add filters to element 1674 * 1675 * @param array $filters 1676 * @return Zend_Form_Element 1677 */ 1678 public function addFilters(array $filters) 1679 { 1680 foreach ($filters as $filterInfo) { 1681 if (is_string($filterInfo)) { 1682 $this->addFilter($filterInfo); 1683 } elseif ($filterInfo instanceof Zend_Filter_Interface) { 1684 $this->addFilter($filterInfo); 1685 } elseif (is_array($filterInfo)) { 1686 $argc = count($filterInfo); 1687 $options = array(); 1688 if (isset($filterInfo['filter'])) { 1689 $filter = $filterInfo['filter']; 1690 if (isset($filterInfo['options'])) { 1691 $options = $filterInfo['options']; 1692 } 1693 $this->addFilter($filter, $options); 1694 } else { 1695 switch (true) { 1696 case (0 == $argc): 1697 break; 1698 case (1 <= $argc): 1699 $filter = array_shift($filterInfo); 1700 case (2 <= $argc): 1701 $options = array_shift($filterInfo); 1702 default: 1703 $this->addFilter($filter, $options); 1704 break; 1705 } 1706 } 1707 } else { 1708 // require_once 'Zend/Form/Exception.php'; 1709 throw new Zend_Form_Exception('Invalid filter passed to addFilters()'); 1710 } 1711 } 1712 1713 return $this; 1714 } 1715 1716 /** 1717 * Add filters to element, overwriting any already existing 1718 * 1719 * @param array $filters 1720 * @return Zend_Form_Element 1721 */ 1722 public function setFilters(array $filters) 1723 { 1724 $this->clearFilters(); 1725 return $this->addFilters($filters); 1726 } 1727 1728 /** 1729 * Retrieve a single filter by name 1730 * 1731 * @param string $name 1732 * @return Zend_Filter_Interface 1733 */ 1734 public function getFilter($name) 1735 { 1736 if (!isset($this->_filters[$name])) { 1737 $len = strlen($name); 1738 foreach ($this->_filters as $localName => $filter) { 1739 if ($len > strlen($localName)) { 1740 continue; 1741 } 1742 1743 if (0 === substr_compare($localName, $name, -$len, $len, true)) { 1744 if (is_array($filter)) { 1745 return $this->_loadFilter($filter); 1746 } 1747 return $filter; 1748 } 1749 } 1750 return false; 1751 } 1752 1753 if (is_array($this->_filters[$name])) { 1754 return $this->_loadFilter($this->_filters[$name]); 1755 } 1756 1757 return $this->_filters[$name]; 1758 } 1759 1760 /** 1761 * Get all filters 1762 * 1763 * @return array 1764 */ 1765 public function getFilters() 1766 { 1767 $filters = array(); 1768 foreach ($this->_filters as $key => $value) { 1769 if ($value instanceof Zend_Filter_Interface) { 1770 $filters[$key] = $value; 1771 continue; 1772 } 1773 $filter = $this->_loadFilter($value); 1774 $filters[get_class($filter)] = $filter; 1775 } 1776 return $filters; 1777 } 1778 1779 /** 1780 * Remove a filter by name 1781 * 1782 * @param string $name 1783 * @return Zend_Form_Element 1784 */ 1785 public function removeFilter($name) 1786 { 1787 if (isset($this->_filters[$name])) { 1788 unset($this->_filters[$name]); 1789 } else { 1790 $len = strlen($name); 1791 foreach (array_keys($this->_filters) as $filter) { 1792 if ($len > strlen($filter)) { 1793 continue; 1794 } 1795 if (0 === substr_compare($filter, $name, -$len, $len, true)) { 1796 unset($this->_filters[$filter]); 1797 break; 1798 } 1799 } 1800 } 1801 1802 return $this; 1803 } 1804 1805 /** 1806 * Clear all filters 1807 * 1808 * @return Zend_Form_Element 1809 */ 1810 public function clearFilters() 1811 { 1812 $this->_filters = array(); 1813 return $this; 1814 } 1815 1816 // Rendering 1817 1818 /** 1819 * Set view object 1820 * 1821 * @param Zend_View_Interface $view 1822 * @return Zend_Form_Element 1823 */ 1824 public function setView(Zend_View_Interface $view = null) 1825 { 1826 $this->_view = $view; 1827 return $this; 1828 } 1829 1830 /** 1831 * Retrieve view object 1832 * 1833 * Retrieves from ViewRenderer if none previously set. 1834 * 1835 * @return null|Zend_View_Interface 1836 */ 1837 public function getView() 1838 { 1839 if (null === $this->_view) { 1840 // require_once 'Zend/Controller/Action/HelperBroker.php'; 1841 $viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer'); 1842 $this->setView($viewRenderer->view); 1843 } 1844 return $this->_view; 1845 } 1846 1847 /** 1848 * Instantiate a decorator based on class name or class name fragment 1849 * 1850 * @param string $name 1851 * @param null|array $options 1852 * @return Zend_Form_Decorator_Interface 1853 */ 1854 protected function _getDecorator($name, $options) 1855 { 1856 $class = $this->getPluginLoader(self::DECORATOR)->load($name); 1857 if (null === $options) { 1858 $decorator = new $class; 1859 } else { 1860 $decorator = new $class($options); 1861 } 1862 1863 return $decorator; 1864 } 1865 1866 /** 1867 * Add a decorator for rendering the element 1868 * 1869 * @param string|Zend_Form_Decorator_Interface $decorator 1870 * @param array|Zend_Config $options Options with which to initialize decorator 1871 * @return Zend_Form_Element 1872 */ 1873 public function addDecorator($decorator, $options = null) 1874 { 1875 if ($decorator instanceof Zend_Form_Decorator_Interface) { 1876 $name = get_class($decorator); 1877 } elseif (is_string($decorator)) { 1878 $name = $decorator; 1879 $decorator = array( 1880 'decorator' => $name, 1881 'options' => $options, 1882 ); 1883 } elseif (is_array($decorator)) { 1884 foreach ($decorator as $name => $spec) { 1885 break; 1886 } 1887 if (is_numeric($name)) { 1888 // require_once 'Zend/Form/Exception.php'; 1889 throw new Zend_Form_Exception('Invalid alias provided to addDecorator; must be alphanumeric string'); 1890 } 1891 if (is_string($spec)) { 1892 $decorator = array( 1893 'decorator' => $spec, 1894 'options' => $options, 1895 ); 1896 } elseif ($spec instanceof Zend_Form_Decorator_Interface) { 1897 $decorator = $spec; 1898 } 1899 } else { 1900 // require_once 'Zend/Form/Exception.php'; 1901 throw new Zend_Form_Exception('Invalid decorator provided to addDecorator; must be string or Zend_Form_Decorator_Interface'); 1902 } 1903 1904 $this->_decorators[$name] = $decorator; 1905 1906 return $this; 1907 } 1908 1909 /** 1910 * Add many decorators at once 1911 * 1912 * @param array $decorators 1913 * @return Zend_Form_Element 1914 */ 1915 public function addDecorators(array $decorators) 1916 { 1917 foreach ($decorators as $decoratorName => $decoratorInfo) { 1918 if (is_string($decoratorInfo) || 1919 $decoratorInfo instanceof Zend_Form_Decorator_Interface) { 1920 if (!is_numeric($decoratorName)) { 1921 $this->addDecorator(array($decoratorName => $decoratorInfo)); 1922 } else { 1923 $this->addDecorator($decoratorInfo); 1924 } 1925 } elseif (is_array($decoratorInfo)) { 1926 $argc = count($decoratorInfo); 1927 $options = array(); 1928 if (isset($decoratorInfo['decorator'])) { 1929 $decorator = $decoratorInfo['decorator']; 1930 if (isset($decoratorInfo['options'])) { 1931 $options = $decoratorInfo['options']; 1932 } 1933 $this->addDecorator($decorator, $options); 1934 } else { 1935 switch (true) { 1936 case (0 == $argc): 1937 break; 1938 case (1 <= $argc): 1939 $decorator = array_shift($decoratorInfo); 1940 case (2 <= $argc): 1941 $options = array_shift($decoratorInfo); 1942 default: 1943 $this->addDecorator($decorator, $options); 1944 break; 1945 } 1946 } 1947 } else { 1948 // require_once 'Zend/Form/Exception.php'; 1949 throw new Zend_Form_Exception('Invalid decorator passed to addDecorators()'); 1950 } 1951 } 1952 1953 return $this; 1954 } 1955 1956 /** 1957 * Overwrite all decorators 1958 * 1959 * @param array $decorators 1960 * @return Zend_Form_Element 1961 */ 1962 public function setDecorators(array $decorators) 1963 { 1964 $this->clearDecorators(); 1965 return $this->addDecorators($decorators); 1966 } 1967 1968 /** 1969 * Retrieve a registered decorator 1970 * 1971 * @param string $name 1972 * @return false|Zend_Form_Decorator_Abstract 1973 */ 1974 public function getDecorator($name) 1975 { 1976 if (!isset($this->_decorators[$name])) { 1977 $len = strlen($name); 1978 foreach ($this->_decorators as $localName => $decorator) { 1979 if ($len > strlen($localName)) { 1980 continue; 1981 } 1982 1983 if (0 === substr_compare($localName, $name, -$len, $len, true)) { 1984 if (is_array($decorator)) { 1985 return $this->_loadDecorator($decorator, $localName); 1986 } 1987 return $decorator; 1988 } 1989 } 1990 return false; 1991 } 1992 1993 if (is_array($this->_decorators[$name])) { 1994 return $this->_loadDecorator($this->_decorators[$name], $name); 1995 } 1996 1997 return $this->_decorators[$name]; 1998 } 1999 2000 /** 2001 * Retrieve all decorators 2002 * 2003 * @return array 2004 */ 2005 public function getDecorators() 2006 { 2007 foreach ($this->_decorators as $key => $value) { 2008 if (is_array($value)) { 2009 $this->_loadDecorator($value, $key); 2010 } 2011 } 2012 return $this->_decorators; 2013 } 2014 2015 /** 2016 * Remove a single decorator 2017 * 2018 * @param string $name 2019 * @return Zend_Form_Element 2020 */ 2021 public function removeDecorator($name) 2022 { 2023 if (isset($this->_decorators[$name])) { 2024 unset($this->_decorators[$name]); 2025 } else { 2026 $len = strlen($name); 2027 foreach (array_keys($this->_decorators) as $decorator) { 2028 if ($len > strlen($decorator)) { 2029 continue; 2030 } 2031 if (0 === substr_compare($decorator, $name, -$len, $len, true)) { 2032 unset($this->_decorators[$decorator]); 2033 break; 2034 } 2035 } 2036 } 2037 2038 return $this; 2039 } 2040 2041 /** 2042 * Clear all decorators 2043 * 2044 * @return Zend_Form_Element 2045 */ 2046 public function clearDecorators() 2047 { 2048 $this->_decorators = array(); 2049 return $this; 2050 } 2051 2052 /** 2053 * Render form element 2054 * 2055 * @param Zend_View_Interface $view 2056 * @return string 2057 */ 2058 public function render(Zend_View_Interface $view = null) 2059 { 2060 if ($this->_isPartialRendering) { 2061 return ''; 2062 } 2063 2064 if (null !== $view) { 2065 $this->setView($view); 2066 } 2067 2068 $content = ''; 2069 foreach ($this->getDecorators() as $decorator) { 2070 $decorator->setElement($this); 2071 $content = $decorator->render($content); 2072 } 2073 return $content; 2074 } 2075 2076 /** 2077 * String representation of form element 2078 * 2079 * Proxies to {@link render()}. 2080 * 2081 * @return string 2082 */ 2083 public function __toString() 2084 { 2085 try { 2086 $return = $this->render(); 2087 return $return; 2088 } catch (Exception $e) { 2089 trigger_error($e->getMessage(), E_USER_WARNING); 2090 return ''; 2091 } 2092 } 2093 2094 /** 2095 * Lazy-load a filter 2096 * 2097 * @param array $filter 2098 * @return Zend_Filter_Interface 2099 */ 2100 protected function _loadFilter(array $filter) 2101 { 2102 $origName = $filter['filter']; 2103 $name = $this->getPluginLoader(self::FILTER)->load($filter['filter']); 2104 2105 if (array_key_exists($name, $this->_filters)) { 2106 // require_once 'Zend/Form/Exception.php'; 2107 throw new Zend_Form_Exception(sprintf('Filter instance already exists for filter "%s"', $origName)); 2108 } 2109 2110 if (empty($filter['options'])) { 2111 $instance = new $name; 2112 } else { 2113 $r = new ReflectionClass($name); 2114 if ($r->hasMethod('__construct')) { 2115 $instance = $r->newInstanceArgs((array) $filter['options']); 2116 } else { 2117 $instance = $r->newInstance(); 2118 } 2119 } 2120 2121 if ($origName != $name) { 2122 $filterNames = array_keys($this->_filters); 2123 $order = array_flip($filterNames); 2124 $order[$name] = $order[$origName]; 2125 $filtersExchange = array(); 2126 unset($order[$origName]); 2127 asort($order); 2128 foreach ($order as $key => $index) { 2129 if ($key == $name) { 2130 $filtersExchange[$key] = $instance; 2131 continue; 2132 } 2133 $filtersExchange[$key] = $this->_filters[$key]; 2134 } 2135 $this->_filters = $filtersExchange; 2136 } else { 2137 $this->_filters[$name] = $instance; 2138 } 2139 2140 return $instance; 2141 } 2142 2143 /** 2144 * Lazy-load a validator 2145 * 2146 * @param array $validator Validator definition 2147 * @return Zend_Validate_Interface 2148 */ 2149 protected function _loadValidator(array $validator) 2150 { 2151 $origName = $validator['validator']; 2152 $name = $this->getPluginLoader(self::VALIDATE)->load($validator['validator']); 2153 2154 if (array_key_exists($name, $this->_validators)) { 2155 // require_once 'Zend/Form/Exception.php'; 2156 throw new Zend_Form_Exception(sprintf('Validator instance already exists for validator "%s"', $origName)); 2157 } 2158 2159 $messages = false; 2160 if (isset($validator['options']) && array_key_exists('messages', (array)$validator['options'])) { 2161 $messages = $validator['options']['messages']; 2162 unset($validator['options']['messages']); 2163 } 2164 2165 if (empty($validator['options'])) { 2166 $instance = new $name; 2167 } else { 2168 $r = new ReflectionClass($name); 2169 if ($r->hasMethod('__construct')) { 2170 $numeric = false; 2171 if (is_array($validator['options'])) { 2172 $keys = array_keys($validator['options']); 2173 foreach($keys as $key) { 2174 if (is_numeric($key)) { 2175 $numeric = true; 2176 break; 2177 } 2178 } 2179 } 2180 2181 if ($numeric) { 2182 $instance = $r->newInstanceArgs((array) $validator['options']); 2183 } else { 2184 $instance = $r->newInstance($validator['options']); 2185 } 2186 } else { 2187 $instance = $r->newInstance(); 2188 } 2189 } 2190 2191 if ($messages) { 2192 if (is_array($messages)) { 2193 $instance->setMessages($messages); 2194 } elseif (is_string($messages)) { 2195 $instance->setMessage($messages); 2196 } 2197 } 2198 $instance->zfBreakChainOnFailure = $validator['breakChainOnFailure']; 2199 2200 if ($origName != $name) { 2201 $validatorNames = array_keys($this->_validators); 2202 $order = array_flip($validatorNames); 2203 $order[$name] = $order[$origName]; 2204 $validatorsExchange = array(); 2205 unset($order[$origName]); 2206 asort($order); 2207 foreach ($order as $key => $index) { 2208 if ($key == $name) { 2209 $validatorsExchange[$key] = $instance; 2210 continue; 2211 } 2212 $validatorsExchange[$key] = $this->_validators[$key]; 2213 } 2214 $this->_validators = $validatorsExchange; 2215 } else { 2216 $this->_validators[$name] = $instance; 2217 } 2218 2219 return $instance; 2220 } 2221 2222 /** 2223 * Lazy-load a decorator 2224 * 2225 * @param array $decorator Decorator type and options 2226 * @param mixed $name Decorator name or alias 2227 * @return Zend_Form_Decorator_Interface 2228 */ 2229 protected function _loadDecorator(array $decorator, $name) 2230 { 2231 $sameName = false; 2232 if ($name == $decorator['decorator']) { 2233 $sameName = true; 2234 } 2235 2236 $instance = $this->_getDecorator($decorator['decorator'], $decorator['options']); 2237 if ($sameName) { 2238 $newName = get_class($instance); 2239 $decoratorNames = array_keys($this->_decorators); 2240 $order = array_flip($decoratorNames); 2241 $order[$newName] = $order[$name]; 2242 $decoratorsExchange = array(); 2243 unset($order[$name]); 2244 asort($order); 2245 foreach ($order as $key => $index) { 2246 if ($key == $newName) { 2247 $decoratorsExchange[$key] = $instance; 2248 continue; 2249 } 2250 $decoratorsExchange[$key] = $this->_decorators[$key]; 2251 } 2252 $this->_decorators = $decoratorsExchange; 2253 } else { 2254 $this->_decorators[$name] = $instance; 2255 } 2256 2257 return $instance; 2258 } 2259 2260 /** 2261 * Retrieve error messages and perform translation and value substitution 2262 * 2263 * @return array 2264 */ 2265 protected function _getErrorMessages() 2266 { 2267 $translator = $this->getTranslator(); 2268 $messages = $this->getErrorMessages(); 2269 $value = $this->getValue(); 2270 foreach ($messages as $key => $message) { 2271 if (null !== $translator) { 2272 $message = $translator->translate($message); 2273 } 2274 if ($this->isArray() || is_array($value)) { 2275 $aggregateMessages = array(); 2276 foreach ($value as $val) { 2277 $aggregateMessages[] = str_replace('%value%', $val, $message); 2278 } 2279 if (count($aggregateMessages)) { 2280 if ($this->_concatJustValuesInErrorMessage) { 2281 $values = implode($this->getErrorMessageSeparator(), $value); 2282 $messages[$key] = str_replace('%value%', $values, $message); 2283 } else { 2284 $messages[$key] = implode($this->getErrorMessageSeparator(), $aggregateMessages); 2285 } 2286 } 2287 } else { 2288 $messages[$key] = str_replace('%value%', $value, $message); 2289 } 2290 } 2291 return $messages; 2292 } 2293 2294 /** 2295 * Are there custom error messages registered? 2296 * 2297 * @return bool 2298 */ 2299 protected function _hasErrorMessages() 2300 { 2301 return !empty($this->_errorMessages); 2302 } 2303 }