PageRenderTime 50ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/library/Zend/Form/Element.php

http://digitalus-cms.googlecode.com/
PHP | 2243 lines | 1245 code | 220 blank | 778 comment | 196 complexity | 4f105e042163df7bd8bd74d98fc97e6e MD5 | raw file
Possible License(s): GPL-3.0, BSD-3-Clause, LGPL-2.1
  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://framework.zend.com/license/new-bsd
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_Form
  17. * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
  18. * @license http://framework.zend.com/license/new-bsd New BSD License
  19. */
  20. /** @see Zend_Filter */
  21. require_once 'Zend/Filter.php';
  22. /** @see Zend_Form */
  23. require_once 'Zend/Form.php';
  24. /** @see Zend_Validate_Interface */
  25. require_once 'Zend/Validate/Interface.php';
  26. /** @see Zend_Validate_Abstract */
  27. require_once 'Zend/Validate/Abstract.php';
  28. /**
  29. * Zend_Form_Element
  30. *
  31. * @category Zend
  32. * @package Zend_Form
  33. * @subpackage Element
  34. * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
  35. * @license http://framework.zend.com/license/new-bsd New BSD License
  36. * @version $Id: Element.php 21894 2010-04-16 19:41:12Z matthew $
  37. */
  38. class Zend_Form_Element implements Zend_Validate_Interface
  39. {
  40. /**
  41. * Element Constants
  42. */
  43. const DECORATOR = 'DECORATOR';
  44. const FILTER = 'FILTER';
  45. const VALIDATE = 'VALIDATE';
  46. /**
  47. * Default view helper to use
  48. * @var string
  49. */
  50. public $helper = 'formText';
  51. /**
  52. * 'Allow empty' flag
  53. * @var bool
  54. */
  55. protected $_allowEmpty = true;
  56. /**
  57. * Flag indicating whether or not to insert NotEmpty validator when element is required
  58. * @var bool
  59. */
  60. protected $_autoInsertNotEmptyValidator = true;
  61. /**
  62. * Array to which element belongs
  63. * @var string
  64. */
  65. protected $_belongsTo;
  66. /**
  67. * Element decorators
  68. * @var array
  69. */
  70. protected $_decorators = array();
  71. /**
  72. * Element description
  73. * @var string
  74. */
  75. protected $_description;
  76. /**
  77. * Should we disable loading the default decorators?
  78. * @var bool
  79. */
  80. protected $_disableLoadDefaultDecorators = false;
  81. /**
  82. * Custom error messages
  83. * @var array
  84. */
  85. protected $_errorMessages = array();
  86. /**
  87. * Validation errors
  88. * @var array
  89. */
  90. protected $_errors = array();
  91. /**
  92. * Separator to use when concatenating aggregate error messages (for
  93. * elements having array values)
  94. * @var string
  95. */
  96. protected $_errorMessageSeparator = '; ';
  97. /**
  98. * Element filters
  99. * @var array
  100. */
  101. protected $_filters = array();
  102. /**
  103. * Ignore flag (used when retrieving values at form level)
  104. * @var bool
  105. */
  106. protected $_ignore = false;
  107. /**
  108. * Does the element represent an array?
  109. * @var bool
  110. */
  111. protected $_isArray = false;
  112. /**
  113. * Is the error marked as in an invalid state?
  114. * @var bool
  115. */
  116. protected $_isError = false;
  117. /**
  118. * Has the element been manually marked as invalid?
  119. * @var bool
  120. */
  121. protected $_isErrorForced = false;
  122. /**
  123. * Element label
  124. * @var string
  125. */
  126. protected $_label;
  127. /**
  128. * Plugin loaders for filter and validator chains
  129. * @var array
  130. */
  131. protected $_loaders = array();
  132. /**
  133. * Formatted validation error messages
  134. * @var array
  135. */
  136. protected $_messages = array();
  137. /**
  138. * Element name
  139. * @var string
  140. */
  141. protected $_name;
  142. /**
  143. * Order of element
  144. * @var int
  145. */
  146. protected $_order;
  147. /**
  148. * Required flag
  149. * @var bool
  150. */
  151. protected $_required = false;
  152. /**
  153. * @var Zend_Translate
  154. */
  155. protected $_translator;
  156. /**
  157. * Is translation disabled?
  158. * @var bool
  159. */
  160. protected $_translatorDisabled = false;
  161. /**
  162. * Element type
  163. * @var string
  164. */
  165. protected $_type;
  166. /**
  167. * Array of initialized validators
  168. * @var array Validators
  169. */
  170. protected $_validators = array();
  171. /**
  172. * Array of un-initialized validators
  173. * @var array
  174. */
  175. protected $_validatorRules = array();
  176. /**
  177. * Element value
  178. * @var mixed
  179. */
  180. protected $_value;
  181. /**
  182. * @var Zend_View_Interface
  183. */
  184. protected $_view;
  185. /**
  186. * Is a specific decorator being rendered via the magic renderDecorator()?
  187. *
  188. * This is to allow execution of logic inside the render() methods of child
  189. * elements during the magic call while skipping the parent render() method.
  190. *
  191. * @var bool
  192. */
  193. protected $_isPartialRendering = false;
  194. /**
  195. * Constructor
  196. *
  197. * $spec may be:
  198. * - string: name of element
  199. * - array: options with which to configure element
  200. * - Zend_Config: Zend_Config with options for configuring element
  201. *
  202. * @param string|array|Zend_Config $spec
  203. * @param array|Zend_Config $options
  204. * @return void
  205. * @throws Zend_Form_Exception if no element name after initialization
  206. */
  207. public function __construct($spec, $options = null)
  208. {
  209. if (is_string($spec)) {
  210. $this->setName($spec);
  211. } elseif (is_array($spec)) {
  212. $this->setOptions($spec);
  213. } elseif ($spec instanceof Zend_Config) {
  214. $this->setConfig($spec);
  215. }
  216. if (is_string($spec) && is_array($options)) {
  217. $this->setOptions($options);
  218. } elseif (is_string($spec) && ($options instanceof Zend_Config)) {
  219. $this->setConfig($options);
  220. }
  221. if (null === $this->getName()) {
  222. require_once 'Zend/Form/Exception.php';
  223. throw new Zend_Form_Exception('Zend_Form_Element requires each element to have a name');
  224. }
  225. /**
  226. * Extensions
  227. */
  228. $this->init();
  229. /**
  230. * Register ViewHelper decorator by default
  231. */
  232. $this->loadDefaultDecorators();
  233. }
  234. /**
  235. * Initialize object; used by extending classes
  236. *
  237. * @return void
  238. */
  239. public function init()
  240. {
  241. }
  242. /**
  243. * Set flag to disable loading default decorators
  244. *
  245. * @param bool $flag
  246. * @return Zend_Form_Element
  247. */
  248. public function setDisableLoadDefaultDecorators($flag)
  249. {
  250. $this->_disableLoadDefaultDecorators = (bool) $flag;
  251. return $this;
  252. }
  253. /**
  254. * Should we load the default decorators?
  255. *
  256. * @return bool
  257. */
  258. public function loadDefaultDecoratorsIsDisabled()
  259. {
  260. return $this->_disableLoadDefaultDecorators;
  261. }
  262. /**
  263. * Load default decorators
  264. *
  265. * @return void
  266. */
  267. public function loadDefaultDecorators()
  268. {
  269. if ($this->loadDefaultDecoratorsIsDisabled()) {
  270. return;
  271. }
  272. $decorators = $this->getDecorators();
  273. if (empty($decorators)) {
  274. $this->addDecorator('ViewHelper')
  275. ->addDecorator('Errors')
  276. ->addDecorator('Description', array('tag' => 'p', 'class' => 'description'))
  277. ->addDecorator('HtmlTag', array('tag' => 'dd',
  278. 'id' => $this->getName() . '-element'))
  279. ->addDecorator('Label', array('tag' => 'dt'));
  280. }
  281. }
  282. /**
  283. * Set object state from options array
  284. *
  285. * @param array $options
  286. * @return Zend_Form_Element
  287. */
  288. public function setOptions(array $options)
  289. {
  290. if (isset($options['prefixPath'])) {
  291. $this->addPrefixPaths($options['prefixPath']);
  292. unset($options['prefixPath']);
  293. }
  294. if (isset($options['disableTranslator'])) {
  295. $this->setDisableTranslator($options['disableTranslator']);
  296. unset($options['disableTranslator']);
  297. }
  298. unset($options['options']);
  299. unset($options['config']);
  300. foreach ($options as $key => $value) {
  301. $method = 'set' . ucfirst($key);
  302. if (in_array($method, array('setTranslator', 'setPluginLoader', 'setView'))) {
  303. if (!is_object($value)) {
  304. continue;
  305. }
  306. }
  307. if (method_exists($this, $method)) {
  308. // Setter exists; use it
  309. $this->$method($value);
  310. } else {
  311. // Assume it's metadata
  312. $this->setAttrib($key, $value);
  313. }
  314. }
  315. return $this;
  316. }
  317. /**
  318. * Set object state from Zend_Config object
  319. *
  320. * @param Zend_Config $config
  321. * @return Zend_Form_Element
  322. */
  323. public function setConfig(Zend_Config $config)
  324. {
  325. return $this->setOptions($config->toArray());
  326. }
  327. // Localization:
  328. /**
  329. * Set translator object for localization
  330. *
  331. * @param Zend_Translate|null $translator
  332. * @return Zend_Form_Element
  333. */
  334. public function setTranslator($translator = null)
  335. {
  336. if (null === $translator) {
  337. $this->_translator = null;
  338. } elseif ($translator instanceof Zend_Translate_Adapter) {
  339. $this->_translator = $translator;
  340. } elseif ($translator instanceof Zend_Translate) {
  341. $this->_translator = $translator->getAdapter();
  342. } else {
  343. require_once 'Zend/Form/Exception.php';
  344. throw new Zend_Form_Exception('Invalid translator specified');
  345. }
  346. return $this;
  347. }
  348. /**
  349. * Retrieve localization translator object
  350. *
  351. * @return Zend_Translate_Adapter|null
  352. */
  353. public function getTranslator()
  354. {
  355. if ($this->translatorIsDisabled()) {
  356. return null;
  357. }
  358. if (null === $this->_translator) {
  359. return Zend_Form::getDefaultTranslator();
  360. }
  361. return $this->_translator;
  362. }
  363. /**
  364. * Does this element have its own specific translator?
  365. *
  366. * @return bool
  367. */
  368. public function hasTranslator()
  369. {
  370. return (bool)$this->_translator;
  371. }
  372. /**
  373. * Indicate whether or not translation should be disabled
  374. *
  375. * @param bool $flag
  376. * @return Zend_Form_Element
  377. */
  378. public function setDisableTranslator($flag)
  379. {
  380. $this->_translatorDisabled = (bool) $flag;
  381. return $this;
  382. }
  383. /**
  384. * Is translation disabled?
  385. *
  386. * @return bool
  387. */
  388. public function translatorIsDisabled()
  389. {
  390. return $this->_translatorDisabled;
  391. }
  392. // Metadata
  393. /**
  394. * Filter a name to only allow valid variable characters
  395. *
  396. * @param string $value
  397. * @param bool $allowBrackets
  398. * @return string
  399. */
  400. public function filterName($value, $allowBrackets = false)
  401. {
  402. $charset = '^a-zA-Z0-9_\x7f-\xff';
  403. if ($allowBrackets) {
  404. $charset .= '\[\]';
  405. }
  406. return preg_replace('/[' . $charset . ']/', '', (string) $value);
  407. }
  408. /**
  409. * Set element name
  410. *
  411. * @param string $name
  412. * @return Zend_Form_Element
  413. */
  414. public function setName($name)
  415. {
  416. $name = $this->filterName($name);
  417. if ('' === $name) {
  418. require_once 'Zend/Form/Exception.php';
  419. throw new Zend_Form_Exception('Invalid name provided; must contain only valid variable characters and be non-empty');
  420. }
  421. $this->_name = $name;
  422. return $this;
  423. }
  424. /**
  425. * Return element name
  426. *
  427. * @return string
  428. */
  429. public function getName()
  430. {
  431. return $this->_name;
  432. }
  433. /**
  434. * Get fully qualified name
  435. *
  436. * Places name as subitem of array and/or appends brackets.
  437. *
  438. * @return string
  439. */
  440. public function getFullyQualifiedName()
  441. {
  442. $name = $this->getName();
  443. if (null !== ($belongsTo = $this->getBelongsTo())) {
  444. $name = $belongsTo . '[' . $name . ']';
  445. }
  446. if ($this->isArray()) {
  447. $name .= '[]';
  448. }
  449. return $name;
  450. }
  451. /**
  452. * Get element id
  453. *
  454. * @return string
  455. */
  456. public function getId()
  457. {
  458. if (isset($this->id)) {
  459. return $this->id;
  460. }
  461. $id = $this->getFullyQualifiedName();
  462. // Bail early if no array notation detected
  463. if (!strstr($id, '[')) {
  464. return $id;
  465. }
  466. // Strip array notation
  467. if ('[]' == substr($id, -2)) {
  468. $id = substr($id, 0, strlen($id) - 2);
  469. }
  470. $id = str_replace('][', '-', $id);
  471. $id = str_replace(array(']', '['), '-', $id);
  472. $id = trim($id, '-');
  473. return $id;
  474. }
  475. /**
  476. * Set element value
  477. *
  478. * @param mixed $value
  479. * @return Zend_Form_Element
  480. */
  481. public function setValue($value)
  482. {
  483. $this->_value = $value;
  484. return $this;
  485. }
  486. /**
  487. * Filter a value
  488. *
  489. * @param string $value
  490. * @param string $key
  491. * @return void
  492. */
  493. protected function _filterValue(&$value, &$key)
  494. {
  495. foreach ($this->getFilters() as $filter) {
  496. $value = $filter->filter($value);
  497. }
  498. }
  499. /**
  500. * Retrieve filtered element value
  501. *
  502. * @return mixed
  503. */
  504. public function getValue()
  505. {
  506. $valueFiltered = $this->_value;
  507. if ($this->isArray() && is_array($valueFiltered)) {
  508. array_walk_recursive($valueFiltered, array($this, '_filterValue'));
  509. } else {
  510. $this->_filterValue($valueFiltered, $valueFiltered);
  511. }
  512. return $valueFiltered;
  513. }
  514. /**
  515. * Retrieve unfiltered element value
  516. *
  517. * @return mixed
  518. */
  519. public function getUnfilteredValue()
  520. {
  521. return $this->_value;
  522. }
  523. /**
  524. * Set element label
  525. *
  526. * @param string $label
  527. * @return Zend_Form_Element
  528. */
  529. public function setLabel($label)
  530. {
  531. $this->_label = (string) $label;
  532. return $this;
  533. }
  534. /**
  535. * Retrieve element label
  536. *
  537. * @return string
  538. */
  539. public function getLabel()
  540. {
  541. $translator = $this->getTranslator();
  542. if (null !== $translator) {
  543. return $translator->translate($this->_label);
  544. }
  545. return $this->_label;
  546. }
  547. /**
  548. * Set element order
  549. *
  550. * @param int $order
  551. * @return Zend_Form_Element
  552. */
  553. public function setOrder($order)
  554. {
  555. $this->_order = (int) $order;
  556. return $this;
  557. }
  558. /**
  559. * Retrieve element order
  560. *
  561. * @return int
  562. */
  563. public function getOrder()
  564. {
  565. return $this->_order;
  566. }
  567. /**
  568. * Set required flag
  569. *
  570. * @param bool $flag Default value is true
  571. * @return Zend_Form_Element
  572. */
  573. public function setRequired($flag = true)
  574. {
  575. $this->_required = (bool) $flag;
  576. return $this;
  577. }
  578. /**
  579. * Is the element required?
  580. *
  581. * @return bool
  582. */
  583. public function isRequired()
  584. {
  585. return $this->_required;
  586. }
  587. /**
  588. * Set flag indicating whether a NotEmpty validator should be inserted when element is required
  589. *
  590. * @param bool $flag
  591. * @return Zend_Form_Element
  592. */
  593. public function setAutoInsertNotEmptyValidator($flag)
  594. {
  595. $this->_autoInsertNotEmptyValidator = (bool) $flag;
  596. return $this;
  597. }
  598. /**
  599. * Get flag indicating whether a NotEmpty validator should be inserted when element is required
  600. *
  601. * @return bool
  602. */
  603. public function autoInsertNotEmptyValidator()
  604. {
  605. return $this->_autoInsertNotEmptyValidator;
  606. }
  607. /**
  608. * Set element description
  609. *
  610. * @param string $description
  611. * @return Zend_Form_Element
  612. */
  613. public function setDescription($description)
  614. {
  615. $this->_description = (string) $description;
  616. return $this;
  617. }
  618. /**
  619. * Retrieve element description
  620. *
  621. * @return string
  622. */
  623. public function getDescription()
  624. {
  625. return $this->_description;
  626. }
  627. /**
  628. * Set 'allow empty' flag
  629. *
  630. * When the allow empty flag is enabled and the required flag is false, the
  631. * element will validate with empty values.
  632. *
  633. * @param bool $flag
  634. * @return Zend_Form_Element
  635. */
  636. public function setAllowEmpty($flag)
  637. {
  638. $this->_allowEmpty = (bool) $flag;
  639. return $this;
  640. }
  641. /**
  642. * Get 'allow empty' flag
  643. *
  644. * @return bool
  645. */
  646. public function getAllowEmpty()
  647. {
  648. return $this->_allowEmpty;
  649. }
  650. /**
  651. * Set ignore flag (used when retrieving values at form level)
  652. *
  653. * @param bool $flag
  654. * @return Zend_Form_Element
  655. */
  656. public function setIgnore($flag)
  657. {
  658. $this->_ignore = (bool) $flag;
  659. return $this;
  660. }
  661. /**
  662. * Get ignore flag (used when retrieving values at form level)
  663. *
  664. * @return bool
  665. */
  666. public function getIgnore()
  667. {
  668. return $this->_ignore;
  669. }
  670. /**
  671. * Set flag indicating if element represents an array
  672. *
  673. * @param bool $flag
  674. * @return Zend_Form_Element
  675. */
  676. public function setIsArray($flag)
  677. {
  678. $this->_isArray = (bool) $flag;
  679. return $this;
  680. }
  681. /**
  682. * Is the element representing an array?
  683. *
  684. * @return bool
  685. */
  686. public function isArray()
  687. {
  688. return $this->_isArray;
  689. }
  690. /**
  691. * Set array to which element belongs
  692. *
  693. * @param string $array
  694. * @return Zend_Form_Element
  695. */
  696. public function setBelongsTo($array)
  697. {
  698. $array = $this->filterName($array, true);
  699. if (!empty($array)) {
  700. $this->_belongsTo = $array;
  701. }
  702. return $this;
  703. }
  704. /**
  705. * Return array name to which element belongs
  706. *
  707. * @return string
  708. */
  709. public function getBelongsTo()
  710. {
  711. return $this->_belongsTo;
  712. }
  713. /**
  714. * Return element type
  715. *
  716. * @return string
  717. */
  718. public function getType()
  719. {
  720. if (null === $this->_type) {
  721. $this->_type = get_class($this);
  722. }
  723. return $this->_type;
  724. }
  725. /**
  726. * Set element attribute
  727. *
  728. * @param string $name
  729. * @param mixed $value
  730. * @return Zend_Form_Element
  731. * @throws Zend_Form_Exception for invalid $name values
  732. */
  733. public function setAttrib($name, $value)
  734. {
  735. $name = (string) $name;
  736. if ('_' == $name[0]) {
  737. require_once 'Zend/Form/Exception.php';
  738. throw new Zend_Form_Exception(sprintf('Invalid attribute "%s"; must not contain a leading underscore', $name));
  739. }
  740. if (null === $value) {
  741. unset($this->$name);
  742. } else {
  743. $this->$name = $value;
  744. }
  745. return $this;
  746. }
  747. /**
  748. * Set multiple attributes at once
  749. *
  750. * @param array $attribs
  751. * @return Zend_Form_Element
  752. */
  753. public function setAttribs(array $attribs)
  754. {
  755. foreach ($attribs as $key => $value) {
  756. $this->setAttrib($key, $value);
  757. }
  758. return $this;
  759. }
  760. /**
  761. * Retrieve element attribute
  762. *
  763. * @param string $name
  764. * @return string
  765. */
  766. public function getAttrib($name)
  767. {
  768. $name = (string) $name;
  769. if (isset($this->$name)) {
  770. return $this->$name;
  771. }
  772. return null;
  773. }
  774. /**
  775. * Return all attributes
  776. *
  777. * @return array
  778. */
  779. public function getAttribs()
  780. {
  781. $attribs = get_object_vars($this);
  782. foreach ($attribs as $key => $value) {
  783. if ('_' == substr($key, 0, 1)) {
  784. unset($attribs[$key]);
  785. }
  786. }
  787. return $attribs;
  788. }
  789. /**
  790. * Overloading: retrieve object property
  791. *
  792. * Prevents access to properties beginning with '_'.
  793. *
  794. * @param string $key
  795. * @return mixed
  796. */
  797. public function __get($key)
  798. {
  799. if ('_' == $key[0]) {
  800. require_once 'Zend/Form/Exception.php';
  801. throw new Zend_Form_Exception(sprintf('Cannot retrieve value for protected/private property "%s"', $key));
  802. }
  803. if (!isset($this->$key)) {
  804. return null;
  805. }
  806. return $this->$key;
  807. }
  808. /**
  809. * Overloading: set object property
  810. *
  811. * @param string $key
  812. * @param mixed $value
  813. * @return voide
  814. */
  815. public function __set($key, $value)
  816. {
  817. $this->setAttrib($key, $value);
  818. }
  819. /**
  820. * Overloading: allow rendering specific decorators
  821. *
  822. * Call renderDecoratorName() to render a specific decorator.
  823. *
  824. * @param string $method
  825. * @param array $args
  826. * @return string
  827. * @throws Zend_Form_Exception for invalid decorator or invalid method call
  828. */
  829. public function __call($method, $args)
  830. {
  831. if ('render' == substr($method, 0, 6)) {
  832. $this->_isPartialRendering = true;
  833. $this->render();
  834. $this->_isPartialRendering = false;
  835. $decoratorName = substr($method, 6);
  836. if (false !== ($decorator = $this->getDecorator($decoratorName))) {
  837. $decorator->setElement($this);
  838. $seed = '';
  839. if (0 < count($args)) {
  840. $seed = array_shift($args);
  841. }
  842. return $decorator->render($seed);
  843. }
  844. require_once 'Zend/Form/Element/Exception.php';
  845. throw new Zend_Form_Element_Exception(sprintf('Decorator by name %s does not exist', $decoratorName));
  846. }
  847. require_once 'Zend/Form/Element/Exception.php';
  848. throw new Zend_Form_Element_Exception(sprintf('Method %s does not exist', $method));
  849. }
  850. // Loaders
  851. /**
  852. * Set plugin loader to use for validator or filter chain
  853. *
  854. * @param Zend_Loader_PluginLoader_Interface $loader
  855. * @param string $type 'decorator', 'filter', or 'validate'
  856. * @return Zend_Form_Element
  857. * @throws Zend_Form_Exception on invalid type
  858. */
  859. public function setPluginLoader(Zend_Loader_PluginLoader_Interface $loader, $type)
  860. {
  861. $type = strtoupper($type);
  862. switch ($type) {
  863. case self::DECORATOR:
  864. case self::FILTER:
  865. case self::VALIDATE:
  866. $this->_loaders[$type] = $loader;
  867. return $this;
  868. default:
  869. require_once 'Zend/Form/Exception.php';
  870. throw new Zend_Form_Exception(sprintf('Invalid type "%s" provided to setPluginLoader()', $type));
  871. }
  872. }
  873. /**
  874. * Retrieve plugin loader for validator or filter chain
  875. *
  876. * Instantiates with default rules if none available for that type. Use
  877. * 'decorator', 'filter', or 'validate' for $type.
  878. *
  879. * @param string $type
  880. * @return Zend_Loader_PluginLoader
  881. * @throws Zend_Loader_Exception on invalid type.
  882. */
  883. public function getPluginLoader($type)
  884. {
  885. $type = strtoupper($type);
  886. switch ($type) {
  887. case self::FILTER:
  888. case self::VALIDATE:
  889. $prefixSegment = ucfirst(strtolower($type));
  890. $pathSegment = $prefixSegment;
  891. case self::DECORATOR:
  892. if (!isset($prefixSegment)) {
  893. $prefixSegment = 'Form_Decorator';
  894. $pathSegment = 'Form/Decorator';
  895. }
  896. if (!isset($this->_loaders[$type])) {
  897. require_once 'Zend/Loader/PluginLoader.php';
  898. $this->_loaders[$type] = new Zend_Loader_PluginLoader(
  899. array('Zend_' . $prefixSegment . '_' => 'Zend/' . $pathSegment . '/')
  900. );
  901. }
  902. return $this->_loaders[$type];
  903. default:
  904. require_once 'Zend/Form/Exception.php';
  905. throw new Zend_Form_Exception(sprintf('Invalid type "%s" provided to getPluginLoader()', $type));
  906. }
  907. }
  908. /**
  909. * Add prefix path for plugin loader
  910. *
  911. * If no $type specified, assumes it is a base path for both filters and
  912. * validators, and sets each according to the following rules:
  913. * - decorators: $prefix = $prefix . '_Decorator'
  914. * - filters: $prefix = $prefix . '_Filter'
  915. * - validators: $prefix = $prefix . '_Validate'
  916. *
  917. * Otherwise, the path prefix is set on the appropriate plugin loader.
  918. *
  919. * @param string $prefix
  920. * @param string $path
  921. * @param string $type
  922. * @return Zend_Form_Element
  923. * @throws Zend_Form_Exception for invalid type
  924. */
  925. public function addPrefixPath($prefix, $path, $type = null)
  926. {
  927. $type = strtoupper($type);
  928. switch ($type) {
  929. case self::DECORATOR:
  930. case self::FILTER:
  931. case self::VALIDATE:
  932. $loader = $this->getPluginLoader($type);
  933. $loader->addPrefixPath($prefix, $path);
  934. return $this;
  935. case null:
  936. $prefix = rtrim($prefix, '_');
  937. $path = rtrim($path, DIRECTORY_SEPARATOR);
  938. foreach (array(self::DECORATOR, self::FILTER, self::VALIDATE) as $type) {
  939. $cType = ucfirst(strtolower($type));
  940. $pluginPath = $path . DIRECTORY_SEPARATOR . $cType . DIRECTORY_SEPARATOR;
  941. $pluginPrefix = $prefix . '_' . $cType;
  942. $loader = $this->getPluginLoader($type);
  943. $loader->addPrefixPath($pluginPrefix, $pluginPath);
  944. }
  945. return $this;
  946. default:
  947. require_once 'Zend/Form/Exception.php';
  948. throw new Zend_Form_Exception(sprintf('Invalid type "%s" provided to getPluginLoader()', $type));
  949. }
  950. }
  951. /**
  952. * Add many prefix paths at once
  953. *
  954. * @param array $spec
  955. * @return Zend_Form_Element
  956. */
  957. public function addPrefixPaths(array $spec)
  958. {
  959. if (isset($spec['prefix']) && isset($spec['path'])) {
  960. return $this->addPrefixPath($spec['prefix'], $spec['path']);
  961. }
  962. foreach ($spec as $type => $paths) {
  963. if (is_numeric($type) && is_array($paths)) {
  964. $type = null;
  965. if (isset($paths['prefix']) && isset($paths['path'])) {
  966. if (isset($paths['type'])) {
  967. $type = $paths['type'];
  968. }
  969. $this->addPrefixPath($paths['prefix'], $paths['path'], $type);
  970. }
  971. } elseif (!is_numeric($type)) {
  972. if (!isset($paths['prefix']) || !isset($paths['path'])) {
  973. foreach ($paths as $prefix => $spec) {
  974. if (is_array($spec)) {
  975. foreach ($spec as $path) {
  976. if (!is_string($path)) {
  977. continue;
  978. }
  979. $this->addPrefixPath($prefix, $path, $type);
  980. }
  981. } elseif (is_string($spec)) {
  982. $this->addPrefixPath($prefix, $spec, $type);
  983. }
  984. }
  985. } else {
  986. $this->addPrefixPath($paths['prefix'], $paths['path'], $type);
  987. }
  988. }
  989. }
  990. return $this;
  991. }
  992. // Validation
  993. /**
  994. * Add validator to validation chain
  995. *
  996. * Note: will overwrite existing validators if they are of the same class.
  997. *
  998. * @param string|Zend_Validate_Interface $validator
  999. * @param bool $breakChainOnFailure
  1000. * @param array $options
  1001. * @return Zend_Form_Element
  1002. * @throws Zend_Form_Exception if invalid validator type
  1003. */
  1004. public function addValidator($validator, $breakChainOnFailure = false, $options = array())
  1005. {
  1006. if ($validator instanceof Zend_Validate_Interface) {
  1007. $name = get_class($validator);
  1008. if (!isset($validator->zfBreakChainOnFailure)) {
  1009. $validator->zfBreakChainOnFailure = $breakChainOnFailure;
  1010. }
  1011. } elseif (is_string($validator)) {
  1012. $name = $validator;
  1013. $validator = array(
  1014. 'validator' => $validator,
  1015. 'breakChainOnFailure' => $breakChainOnFailure,
  1016. 'options' => $options,
  1017. );
  1018. } else {
  1019. require_once 'Zend/Form/Exception.php';
  1020. throw new Zend_Form_Exception('Invalid validator provided to addValidator; must be string or Zend_Validate_Interface');
  1021. }
  1022. $this->_validators[$name] = $validator;
  1023. return $this;
  1024. }
  1025. /**
  1026. * Add multiple validators
  1027. *
  1028. * @param array $validators
  1029. * @return Zend_Form_Element
  1030. */
  1031. public function addValidators(array $validators)
  1032. {
  1033. foreach ($validators as $validatorInfo) {
  1034. if (is_string($validatorInfo)) {
  1035. $this->addValidator($validatorInfo);
  1036. } elseif ($validatorInfo instanceof Zend_Validate_Interface) {
  1037. $this->addValidator($validatorInfo);
  1038. } elseif (is_array($validatorInfo)) {
  1039. $argc = count($validatorInfo);
  1040. $breakChainOnFailure = false;
  1041. $options = array();
  1042. if (isset($validatorInfo['validator'])) {
  1043. $validator = $validatorInfo['validator'];
  1044. if (isset($validatorInfo['breakChainOnFailure'])) {
  1045. $breakChainOnFailure = $validatorInfo['breakChainOnFailure'];
  1046. }
  1047. if (isset($validatorInfo['options'])) {
  1048. $options = $validatorInfo['options'];
  1049. }
  1050. $this->addValidator($validator, $breakChainOnFailure, $options);
  1051. } else {
  1052. switch (true) {
  1053. case (0 == $argc):
  1054. break;
  1055. case (1 <= $argc):
  1056. $validator = array_shift($validatorInfo);
  1057. case (2 <= $argc):
  1058. $breakChainOnFailure = array_shift($validatorInfo);
  1059. case (3 <= $argc):
  1060. $options = array_shift($validatorInfo);
  1061. default:
  1062. $this->addValidator($validator, $breakChainOnFailure, $options);
  1063. break;
  1064. }
  1065. }
  1066. } else {
  1067. require_once 'Zend/Form/Exception.php';
  1068. throw new Zend_Form_Exception('Invalid validator passed to addValidators()');
  1069. }
  1070. }
  1071. return $this;
  1072. }
  1073. /**
  1074. * Set multiple validators, overwriting previous validators
  1075. *
  1076. * @param array $validators
  1077. * @return Zend_Form_Element
  1078. */
  1079. public function setValidators(array $validators)
  1080. {
  1081. $this->clearValidators();
  1082. return $this->addValidators($validators);
  1083. }
  1084. /**
  1085. * Retrieve a single validator by name
  1086. *
  1087. * @param string $name
  1088. * @return Zend_Validate_Interface|false False if not found, validator otherwise
  1089. */
  1090. public function getValidator($name)
  1091. {
  1092. if (!isset($this->_validators[$name])) {
  1093. $len = strlen($name);
  1094. foreach ($this->_validators as $localName => $validator) {
  1095. if ($len > strlen($localName)) {
  1096. continue;
  1097. }
  1098. if (0 === substr_compare($localName, $name, -$len, $len, true)) {
  1099. if (is_array($validator)) {
  1100. return $this->_loadValidator($validator);
  1101. }
  1102. return $validator;
  1103. }
  1104. }
  1105. return false;
  1106. }
  1107. if (is_array($this->_validators[$name])) {
  1108. return $this->_loadValidator($this->_validators[$name]);
  1109. }
  1110. return $this->_validators[$name];
  1111. }
  1112. /**
  1113. * Retrieve all validators
  1114. *
  1115. * @return array
  1116. */
  1117. public function getValidators()
  1118. {
  1119. $validators = array();
  1120. foreach ($this->_validators as $key => $value) {
  1121. if ($value instanceof Zend_Validate_Interface) {
  1122. $validators[$key] = $value;
  1123. continue;
  1124. }
  1125. $validator = $this->_loadValidator($value);
  1126. $validators[get_class($validator)] = $validator;
  1127. }
  1128. return $validators;
  1129. }
  1130. /**
  1131. * Remove a single validator by name
  1132. *
  1133. * @param string $name
  1134. * @return bool
  1135. */
  1136. public function removeValidator($name)
  1137. {
  1138. if (isset($this->_validators[$name])) {
  1139. unset($this->_validators[$name]);
  1140. } else {
  1141. $len = strlen($name);
  1142. foreach (array_keys($this->_validators) as $validator) {
  1143. if ($len > strlen($validator)) {
  1144. continue;
  1145. }
  1146. if (0 === substr_compare($validator, $name, -$len, $len, true)) {
  1147. unset($this->_validators[$validator]);
  1148. break;
  1149. }
  1150. }
  1151. }
  1152. return $this;
  1153. }
  1154. /**
  1155. * Clear all validators
  1156. *
  1157. * @return Zend_Form_Element
  1158. */
  1159. public function clearValidators()
  1160. {
  1161. $this->_validators = array();
  1162. return $this;
  1163. }
  1164. /**
  1165. * Validate element value
  1166. *
  1167. * If a translation adapter is registered, any error messages will be
  1168. * translated according to the current locale, using the given error code;
  1169. * if no matching translation is found, the original message will be
  1170. * utilized.
  1171. *
  1172. * Note: The *filtered* value is validated.
  1173. *
  1174. * @param mixed $value
  1175. * @param mixed $context
  1176. * @return boolean
  1177. */
  1178. public function isValid($value, $context = null)
  1179. {
  1180. $this->setValue($value);
  1181. $value = $this->getValue();
  1182. if ((('' === $value) || (null === $value))
  1183. && !$this->isRequired()
  1184. && $this->getAllowEmpty()
  1185. ) {
  1186. return true;
  1187. }
  1188. if ($this->isRequired()
  1189. && $this->autoInsertNotEmptyValidator()
  1190. && !$this->getValidator('NotEmpty'))
  1191. {
  1192. $validators = $this->getValidators();
  1193. $notEmpty = array('validator' => 'NotEmpty', 'breakChainOnFailure' => true);
  1194. array_unshift($validators, $notEmpty);
  1195. $this->setValidators($validators);
  1196. }
  1197. // Find the correct translator. Zend_Validate_Abstract::getDefaultTranslator()
  1198. // will get either the static translator attached to Zend_Validate_Abstract
  1199. // or the 'Zend_Translate' from Zend_Registry.
  1200. if (Zend_Validate_Abstract::hasDefaultTranslator() &&
  1201. !Zend_Form::hasDefaultTranslator())
  1202. {
  1203. $translator = Zend_Validate_Abstract::getDefaultTranslator();
  1204. if ($this->hasTranslator()) {
  1205. // only pick up this element's translator if it was attached directly.
  1206. $translator = $this->getTranslator();
  1207. }
  1208. } else {
  1209. $translator = $this->getTranslator();
  1210. }
  1211. $this->_messages = array();
  1212. $this->_errors = array();
  1213. $result = true;
  1214. $isArray = $this->isArray();
  1215. foreach ($this->getValidators() as $key => $validator) {
  1216. if (method_exists($validator, 'setTranslator')) {
  1217. if (method_exists($validator, 'hasTranslator')) {
  1218. if (!$validator->hasTranslator()) {
  1219. $validator->setTranslator($translator);
  1220. }
  1221. } else {
  1222. $validator->setTranslator($translator);
  1223. }
  1224. }
  1225. if (method_exists($validator, 'setDisableTranslator')) {
  1226. $validator->setDisableTranslator($this->translatorIsDisabled());
  1227. }
  1228. if ($isArray && is_array($value)) {
  1229. $messages = array();
  1230. $errors = array();
  1231. foreach ($value as $val) {
  1232. if (!$validator->isValid($val, $context)) {
  1233. $result = false;
  1234. if ($this->_hasErrorMessages()) {
  1235. $messages = $this->_getErrorMessages();
  1236. $errors = $messages;
  1237. } else {
  1238. $messages = array_merge($messages, $validator->getMessages());
  1239. $errors = array_merge($errors, $validator->getErrors());
  1240. }
  1241. }
  1242. }
  1243. if ($result) {
  1244. continue;
  1245. }
  1246. } elseif ($validator->isValid($value, $context)) {
  1247. continue;
  1248. } else {
  1249. $result = false;
  1250. if ($this->_hasErrorMessages()) {
  1251. $messages = $this->_getErrorMessages();
  1252. $errors = $messages;
  1253. } else {
  1254. $messages = $validator->getMessages();
  1255. $errors = array_keys($messages);
  1256. }
  1257. }
  1258. $result = false;
  1259. $this->_messages = array_merge($this->_messages, $messages);
  1260. $this->_errors = array_merge($this->_errors, $errors);
  1261. if ($validator->zfBreakChainOnFailure) {
  1262. break;
  1263. }
  1264. }
  1265. // If element manually flagged as invalid, return false
  1266. if ($this->_isErrorForced) {
  1267. return false;
  1268. }
  1269. return $result;
  1270. }
  1271. /**
  1272. * Add a custom error message to return in the event of failed validation
  1273. *
  1274. * @param string $message
  1275. * @return Zend_Form_Element
  1276. */
  1277. public function addErrorMessage($message)
  1278. {
  1279. $this->_errorMessages[] = (string) $message;
  1280. return $this;
  1281. }
  1282. /**
  1283. * Add multiple custom error messages to return in the event of failed validation
  1284. *
  1285. * @param array $messages
  1286. * @return Zend_Form_Element
  1287. */
  1288. public function addErrorMessages(array $messages)
  1289. {
  1290. foreach ($messages as $message) {
  1291. $this->addErrorMessage($message);
  1292. }
  1293. return $this;
  1294. }
  1295. /**
  1296. * Same as addErrorMessages(), but clears custom error message stack first
  1297. *
  1298. * @param array $messages
  1299. * @return Zend_Form_Element
  1300. */
  1301. public function setErrorMessages(array $messages)
  1302. {
  1303. $this->clearErrorMessages();
  1304. return $this->addErrorMessages($messages);
  1305. }
  1306. /**
  1307. * Retrieve custom error messages
  1308. *
  1309. * @return array
  1310. */
  1311. public function getErrorMessages()
  1312. {
  1313. return $this->_errorMessages;
  1314. }
  1315. /**
  1316. * Clear custom error messages stack
  1317. *
  1318. * @return Zend_Form_Element
  1319. */
  1320. public function clearErrorMessages()
  1321. {
  1322. $this->_errorMessages = array();
  1323. return $this;
  1324. }
  1325. /**
  1326. * Get errorMessageSeparator
  1327. *
  1328. * @return string
  1329. */
  1330. public function getErrorMessageSeparator()
  1331. {
  1332. return $this->_errorMessageSeparator;
  1333. }
  1334. /**
  1335. * Set errorMessageSeparator
  1336. *
  1337. * @param string $separator
  1338. * @return Zend_Form_Element
  1339. */
  1340. public function setErrorMessageSeparator($separator)
  1341. {
  1342. $this->_errorMessageSeparator = $separator;
  1343. return $this;
  1344. }
  1345. /**
  1346. * Mark the element as being in a failed validation state
  1347. *
  1348. * @return Zend_Form_Element
  1349. */
  1350. public function markAsError()
  1351. {
  1352. $messages = $this->getMessages();
  1353. $customMessages = $this->_getErrorMessages();
  1354. $messages = $messages + $customMessages;
  1355. if (empty($messages)) {
  1356. $this->_isError = true;
  1357. } else {
  1358. $this->_messages = $messages;
  1359. }
  1360. $this->_isErrorForced = true;
  1361. return $this;
  1362. }
  1363. /**
  1364. * Add an error message and mark element as failed validation
  1365. *
  1366. * @param string $message
  1367. * @return Zend_Form_Element
  1368. */
  1369. public function addError($message)
  1370. {
  1371. $this->addErrorMessage($message);
  1372. $this->markAsError();
  1373. return $this;
  1374. }
  1375. /**
  1376. * Add multiple error messages and flag element as failed validation
  1377. *
  1378. * @param array $messages
  1379. * @return Zend_Form_Element
  1380. */
  1381. public function addErrors(array $messages)
  1382. {
  1383. foreach ($messages as $message) {
  1384. $this->addError($message);
  1385. }
  1386. return $this;
  1387. }
  1388. /**
  1389. * Overwrite any previously set error messages and flag as failed validation
  1390. *
  1391. * @param array $messages
  1392. * @return Zend_Form_Element
  1393. */
  1394. public function setErrors(array $messages)
  1395. {
  1396. $this->clearErrorMessages();
  1397. return $this->addErrors($messages);
  1398. }
  1399. /**
  1400. * Are there errors registered?
  1401. *
  1402. * @return bool
  1403. */
  1404. public function hasErrors()
  1405. {
  1406. return (!empty($this->_messages) || $this->_isError);
  1407. }
  1408. /**
  1409. * Retrieve validator chain errors
  1410. *
  1411. * @return array
  1412. */
  1413. public function getErrors()
  1414. {
  1415. return $this->_errors;
  1416. }
  1417. /**
  1418. * Retrieve error messages
  1419. *
  1420. * @return array
  1421. */
  1422. public function getMessages()
  1423. {
  1424. return $this->_messages;
  1425. }
  1426. // Filtering
  1427. /**
  1428. * Add a filter to the element
  1429. *
  1430. * @param string|Zend_Filter_Interface $filter
  1431. * @return Zend_Form_Element
  1432. */
  1433. public function addFilter($filter, $options = array())
  1434. {
  1435. if ($filter instanceof Zend_Filter_Interface) {
  1436. $name = get_class($filter);
  1437. } elseif (is_string($filter)) {
  1438. $name = $filter;
  1439. $filter = array(
  1440. 'filter' => $filter,
  1441. 'options' => $options,
  1442. );
  1443. $this->_filters[$name] = $filter;
  1444. } else {
  1445. require_once 'Zend/Form/Exception.php';
  1446. throw new Zend_Form_Exception('Invalid filter provided to addFilter; must be string or Zend_Filter_Interface');
  1447. }
  1448. $this->_filters[$name] = $filter;
  1449. return $this;
  1450. }
  1451. /**
  1452. * Add filters to element
  1453. *
  1454. * @param array $filters
  1455. * @return Zend_Form_Element
  1456. */
  1457. public function addFilters(array $filters)
  1458. {
  1459. foreach ($filters as $filterInfo) {
  1460. if (is_string($filterInfo)) {
  1461. $this->addFilter($filterInfo);
  1462. } elseif ($filterInfo instanceof Zend_Filter_Interface) {
  1463. $this->addFilter($filterInfo);
  1464. } elseif (is_array($filterInfo)) {
  1465. $argc = count($filterInfo);
  1466. $options = array();
  1467. if (isset($filterInfo['filter'])) {
  1468. $filter = $filterInfo['filter'];
  1469. if (isset($filterInfo['options'])) {
  1470. $options = $filterInfo['options'];
  1471. }
  1472. $this->addFilter($filter, $options);
  1473. } else {
  1474. switch (true) {
  1475. case (0 == $argc):
  1476. break;
  1477. case (1 <= $argc):
  1478. $filter = array_shift($filterInfo);
  1479. case (2 <= $argc):
  1480. $options = array_shift($filterInfo);
  1481. default:
  1482. $this->addFilter($filter, $options);
  1483. break;
  1484. }
  1485. }
  1486. } else {
  1487. require_once 'Zend/Form/Exception.php';
  1488. throw new Zend_Form_Exception('Invalid filter passed to addFilters()');
  1489. }
  1490. }
  1491. return $this;
  1492. }
  1493. /**
  1494. * Add filters to element, overwriting any already existing
  1495. *
  1496. * @param array $filters
  1497. * @return Zend_Form_Element
  1498. */
  1499. public function setFilters(array $filters)
  1500. {
  1501. $this->clearFilters();
  1502. return $this->addFilters($filters);
  1503. }
  1504. /**
  1505. * Retrieve a single filter by name
  1506. *
  1507. * @param string $name
  1508. * @return Zend_Filter_Interface
  1509. */
  1510. public function getFilter($name)
  1511. {
  1512. if (!isset($this->_filters[$name])) {
  1513. $len = strlen($name);
  1514. foreach ($this->_filters as $localName => $filter) {
  1515. if ($len > strlen($localName)) {
  1516. continue;
  1517. }
  1518. if (0 === substr_compare($localName, $name, -$len, $len, true)) {
  1519. if (is_array($filter)) {
  1520. return $this->_loadFilter($filter);
  1521. }
  1522. return $filter;
  1523. }
  1524. }
  1525. return false;
  1526. }
  1527. if (is_array($this->_filters[$name])) {
  1528. return $this->_loadFilter($this->_filters[$name]);
  1529. }
  1530. return $this->_filters[$name];
  1531. }
  1532. /**
  1533. * Get all filters
  1534. *
  1535. * @return array
  1536. */
  1537. public function getFilters()
  1538. {
  1539. $filters = array();
  1540. foreach ($this->_filters as $key => $value) {
  1541. if ($value instanceof Zend_Filter_Interface) {
  1542. $filters[$key] = $value;
  1543. continue;
  1544. }
  1545. $filter = $this->_loadFilter($value);
  1546. $filters[get_class($filter)] = $filter;
  1547. }
  1548. return $filters;
  1549. }
  1550. /**
  1551. * Remove a filter by name
  1552. *
  1553. * @param string $name
  1554. * @return Zend_Form_Element
  1555. */
  1556. public function removeFilter($name)
  1557. {
  1558. if (isset($this->_filters[$name])) {
  1559. unset($this->_filters[$name]);
  1560. } else {
  1561. $len = strlen($name);
  1562. foreach (array_keys($this->_filters) as $filter) {
  1563. if ($len > strlen($filter)) {
  1564. continue;
  1565. }
  1566. if (0 === substr_compare($filter, $name, -$len, $len, true)) {
  1567. unset($this->_filters[$filter]);
  1568. break;
  1569. }
  1570. }
  1571. }
  1572. return $this;
  1573. }
  1574. /**
  1575. * Clear all filters
  1576. *
  1577. * @return Zend_Form_Element
  1578. */
  1579. public function clearFilters()
  1580. {
  1581. $this->_filters = array();
  1582. return $this;
  1583. }
  1584. // Rendering
  1585. /**
  1586. * Set view object
  1587. *
  1588. * @param Zend_View_Interface $view
  1589. * @return Zend_Form_Element
  1590. */
  1591. public function setView(Zend_View_Interface $view = null)
  1592. {
  1593. $this->_view = $view;
  1594. return $this;
  1595. }
  1596. /**
  1597. * Retrieve view object
  1598. *
  1599. * Retrieves from ViewRenderer if none previously set.
  1600. *
  1601. * @return null|Zend_View_Interface
  1602. */
  1603. public function getView()
  1604. {
  1605. if (null === $this->_view) {
  1606. require_once 'Zend/Controller/Action/HelperBroker.php';
  1607. $viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
  1608. $this->setView($viewRenderer->view);
  1609. }
  1610. return $this->_view;
  1611. }
  1612. /**
  1613. * Instantiate a decorator based on class name or class name fragment
  1614. *
  1615. * @param string $name
  1616. * @param null|array $options
  1617. * @return Zend_Form_Decorator_Interface
  1618. */
  1619. protected function _getDecorator($name, $options)
  1620. {
  1621. $class = $this->getPluginLoader(self::DECORATOR)->load($name);
  1622. if (null === $options) {
  1623. $decorator = new $class;
  1624. } else {
  1625. $decorator = new $class($options);
  1626. }
  1627. return $decorator;
  1628. }
  1629. /**
  1630. * Add a decorator for rendering the element
  1631. *
  1632. * @param string|Zend_Form_Decorator_Interface $decorator
  1633. * @param array|Zend_Config $options Options with which to initialize decorator
  1634. * @return Zend_Form_Element
  1635. */
  1636. public function addDecorator($decorator, $options = null)
  1637. {
  1638. if ($decorator instanceof Zend_Form_Decorator_Interface) {
  1639. $name = get_class($decorator);
  1640. } elseif (is_string($decorator)) {
  1641. $name = $decorator;
  1642. $decorator = array(
  1643. 'decorator' => $name,
  1644. 'options' => $options,
  1645. );
  1646. } elseif (is_array($decorator)) {
  1647. foreach ($decorator as $name => $spec) {
  1648. break;
  1649. }
  1650. if (is_numeric($name)) {
  1651. require_once 'Zend/Form/Exception.php';
  1652. throw new Zend_Form_Exception('Invalid alias provided to addDecorator; must be alphanumeric string');
  1653. }
  1654. if (is_string($spec)) {
  1655. $decorator = array(
  1656. 'decorator' => $spec,
  1657. 'options' => $options,
  1658. );
  1659. } elseif ($spec instanceof Zend_Form_Decorator_Interface) {
  1660. $decorator = $spec;
  1661. }
  1662. } else {
  1663. require_once 'Zend/Form/Exception.php';
  1664. throw new Zend_Form_Exception('Invalid decorator provided to addDecorator; must be string or Zend_Form_Decorator_Interface');
  1665. }
  1666. $this->_decorators[$name] = $decorator;
  1667. return $this;
  1668. }
  1669. /**
  1670. * Add many decorators at once
  1671. *
  1672. * @param array $decorators
  1673. * @return Zend_Form_Element
  1674. */
  1675. public function addDecorators(array $decorators)
  1676. {
  1677. foreach ($decorators as $decoratorInfo) {
  1678. if (is_string($decoratorInfo)) {
  1679. $this->addDecorator($decoratorInfo);
  1680. } elseif ($decoratorInfo instanceof Zend_Form_Decorator_Interface) {
  1681. $this->addDecorator($decoratorInfo);
  1682. } elseif (is_array($decoratorInfo)) {
  1683. $argc = count($decoratorInfo);
  1684. $options = array();
  1685. if (isset($decoratorInfo['decorator'])) {
  1686. $decorator = $decoratorInfo['decorator'];
  1687. if (isset($decoratorInfo['options'])) {
  1688. $options = $decoratorInfo['options'];
  1689. }
  1690. $this->addDecorator($decorator, $options);
  1691. } else {
  1692. switch (true) {
  1693. case (0 == $argc):
  1694. break;
  1695. case (1 <= $argc):
  1696. $decorator = array_shift($decoratorInfo);
  1697. case (2 <= $argc):
  1698. $options = array_shift($decoratorInfo);
  1699. default:
  1700. $this->addDecorator($decorator, $options);
  1701. break;
  1702. }
  1703. }
  1704. } else {
  1705. require_once 'Zend/Form/Exception.php';
  1706. throw new Zend_Form_Exception('Invalid decorator passed to addDecorators()');
  1707. }
  1708. }
  1709. return $this;
  1710. }
  1711. /**
  1712. * Overwrite all decorators
  1713. *
  1714. * @param array $decorators
  1715. * @return Zend_Form_Element
  1716. */
  1717. public function setDecorators(array $decorators)
  1718. {
  1719. $this->clearDecorators();
  1720. return $this->addDecorators($decorators);
  1721. }
  1722. /**
  1723. * Retrieve a registered decorator
  1724. *
  1725. * @param string $name
  1726. * @return false|Zend_Form_Decorator_Abstract
  1727. */
  1728. public function getDecorator($name)
  1729. {
  1730. if (!isset($this->_decorators[$name])) {
  1731. $len = strlen($name);
  1732. foreach ($this->_decorators as $localName => $decorator) {
  1733. if ($len > strlen($localName)) {
  1734. continue;
  1735. }
  1736. if (0 === substr_compare($localName, $name, -$len, $len, true)) {
  1737. if (is_array($decorator)) {
  1738. return $this->_loadDecorator($decorator, $localName);
  1739. }
  1740. return $decorator;
  1741. }
  1742. }
  1743. return false;
  1744. }
  1745. if (is_array($this->_decorators[$name])) {
  1746. return $this->_loadDecorator($this->_decorators[$name], $name);
  1747. }
  1748. return $this->_decorators[$name];
  1749. }
  1750. /**
  1751. * Retrieve all decorators
  1752. *
  1753. * @return array
  1754. */
  1755. public function getDecorators()
  1756. {
  1757. foreach ($this->_decorators as $key => $value) {
  1758. if (is_array($value)) {
  1759. $this->_loadDecorator($value, $key);
  1760. }
  1761. }
  1762. return $this->_decorators;
  1763. }
  1764. /**
  1765. * Remove a single decorator
  1766. *
  1767. * @param string $name
  1768. * @return Zend_Form_Element
  1769. */
  1770. public function removeDecorator($name)
  1771. {
  1772. if (isset($this->_decorators[$name])) {
  1773. unset($this->_decorators[$name]);
  1774. } else {
  1775. $len = strlen($name);
  1776. foreach (array_keys($this->_decorators) as $decorator) {
  1777. if ($len > strlen($decorator)) {
  1778. continue;
  1779. }
  1780. if (0 === substr_compare($decorator, $name, -$len, $len, true)) {
  1781. unset($this->_decorators[$decorator]);
  1782. break;
  1783. }
  1784. }
  1785. }
  1786. return $this;
  1787. }
  1788. /**
  1789. * Clear all decorators
  1790. *
  1791. * @return Zend_Form_Element
  1792. */
  1793. public function clearDecorators()
  1794. {
  1795. $this->_decorators = array();
  1796. return $this;
  1797. }
  1798. /**
  1799. * Render form element
  1800. *
  1801. * @param Zend_View_Interface $view
  1802. * @return string
  1803. */
  1804. public function render(Zend_View_Interface $view = null)
  1805. {
  1806. if ($this->_isPartialRendering) {
  1807. return '';
  1808. }
  1809. if (null !== $view) {
  1810. $this->setView($view);
  1811. }
  1812. $content = '';
  1813. foreach ($this->getDecorators() as $decorator) {
  1814. $decorator->setElement($this);
  1815. $content = $decorator->render($content);
  1816. }
  1817. return $content;
  1818. }
  1819. /**
  1820. * String representation of form element
  1821. *
  1822. * Proxies to {@link render()}.
  1823. *
  1824. * @return string
  1825. */
  1826. public function __toString()
  1827. {
  1828. try {
  1829. $return = $this->render();
  1830. return $return;
  1831. } catch (Exception $e) {
  1832. trigger_error($e->getMessage(), E_USER_WARNING);
  1833. return '';
  1834. }
  1835. }
  1836. /**
  1837. * Lazy-load a filter
  1838. *
  1839. * @param array $filter
  1840. * @return Zend_Filter_Interface
  1841. */
  1842. protected function _loadFilter(array $filter)
  1843. {
  1844. $origName = $filter['filter'];
  1845. $name = $this->getPluginLoader(self::FILTER)->load($filter['filter']);
  1846. if (array_key_exists($name, $this->_filters)) {
  1847. require_once 'Zend/Form/Exception.php';
  1848. throw new Zend_Form_Exception(sprintf('Filter instance already exists for filter "%s"', $origName));
  1849. }
  1850. if (empty($filter['options'])) {
  1851. $instance = new $name;
  1852. } else {
  1853. $r = new ReflectionClass($name);
  1854. if ($r->hasMethod('__construct')) {
  1855. $instance = $r->newInstanceArgs((array) $filter['options']);
  1856. } else {
  1857. $instance = $r->newInstance();
  1858. }
  1859. }
  1860. if ($origName != $name) {
  1861. $filterNames = array_keys($this->_filters);
  1862. $order = array_flip($filterNames);
  1863. $order[$name] = $order[$origName];
  1864. $filtersExchange = array();
  1865. unset($order[$origName]);
  1866. asort($order);
  1867. foreach ($order as $key => $index) {
  1868. if ($key == $name) {
  1869. $filtersExchange[$key] = $instance;
  1870. continue;
  1871. }
  1872. $filtersExchange[$key] = $this->_filters[$key];
  1873. }
  1874. $this->_filters = $filtersExchange;
  1875. } else {
  1876. $this->_filters[$name] = $instance;
  1877. }
  1878. return $instance;
  1879. }
  1880. /**
  1881. * Lazy-load a validator
  1882. *
  1883. * @param array $validator Validator definition
  1884. * @return Zend_Validate_Interface
  1885. */
  1886. protected function _loadValidator(array $validator)
  1887. {
  1888. $origName = $validator['validator'];
  1889. $name = $this->getPluginLoader(self::VALIDATE)->load($validator['validator']);
  1890. if (array_key_exists($name, $this->_validators)) {
  1891. require_once 'Zend/Form/Exception.php';
  1892. throw new Zend_Form_Exception(sprintf('Validator instance already exists for validator "%s"', $origName));
  1893. }
  1894. $messages = false;
  1895. if (isset($validator['options']) && array_key_exists('messages', (array)$validator['options'])) {
  1896. $messages = $validator['options']['messages'];
  1897. unset($validator['options']['messages']);
  1898. }
  1899. if (empty($validator['options'])) {
  1900. $instance = new $name;
  1901. } else {
  1902. $r = new ReflectionClass($name);
  1903. if ($r->hasMethod('__construct')) {
  1904. $numeric = false;
  1905. if (is_array($validator['options'])) {
  1906. $keys = array_keys($validator['options']);
  1907. foreach($keys as $key) {
  1908. if (is_numeric($key)) {
  1909. $numeric = true;
  1910. break;
  1911. }
  1912. }
  1913. }
  1914. if ($numeric) {
  1915. $instance = $r->newInstanceArgs((array) $validator['options']);
  1916. } else {
  1917. $instance = $r->newInstance($validator['options']);
  1918. }
  1919. } else {
  1920. $instance = $r->newInstance();
  1921. }
  1922. }
  1923. if ($messages) {
  1924. if (is_array($messages)) {
  1925. $instance->setMessages($messages);
  1926. } elseif (is_string($messages)) {
  1927. $instance->setMessage($messages);
  1928. }
  1929. }
  1930. $instance->zfBreakChainOnFailure = $validator['breakChainOnFailure'];
  1931. if ($origName != $name) {
  1932. $validatorNames = array_keys($this->_validators);
  1933. $order = array_flip($validatorNames);
  1934. $order[$name] = $order[$origName];
  1935. $validatorsExchange = array();
  1936. unset($order[$origName]);
  1937. asort($order);
  1938. foreach ($order as $key => $index) {
  1939. if ($key == $name) {
  1940. $validatorsExchange[$key] = $instance;
  1941. continue;
  1942. }
  1943. $validatorsExchange[$key] = $this->_validators[$key];
  1944. }
  1945. $this->_validators = $validatorsExchange;
  1946. } else {
  1947. $this->_validators[$name] = $instance;
  1948. }
  1949. return $instance;
  1950. }
  1951. /**
  1952. * Lazy-load a decorator
  1953. *
  1954. * @param array $decorator Decorator type and options
  1955. * @param mixed $name Decorator name or alias
  1956. * @return Zend_Form_Decorator_Interface
  1957. */
  1958. protected function _loadDecorator(array $decorator, $name)
  1959. {
  1960. $sameName = false;
  1961. if ($name == $decorator['decorator']) {
  1962. $sameName = true;
  1963. }
  1964. $instance = $this->_getDecorator($decorator['decorator'], $decorator['options']);
  1965. if ($sameName) {
  1966. $newName = get_class($instance);
  1967. $decoratorNames = array_keys($this->_decorators);
  1968. $order = array_flip($decoratorNames);
  1969. $order[$newName] = $order[$name];
  1970. $decoratorsExchange = array();
  1971. unset($order[$name]);
  1972. asort($order);
  1973. foreach ($order as $key => $index) {
  1974. if ($key == $newName) {
  1975. $decoratorsExchange[$key] = $instance;
  1976. continue;
  1977. }
  1978. $decoratorsExchange[$key] = $this->_decorators[$key];
  1979. }
  1980. $this->_decorators = $decoratorsExchange;
  1981. } else {
  1982. $this->_decorators[$name] = $instance;
  1983. }
  1984. return $instance;
  1985. }
  1986. /**
  1987. * Retrieve error messages and perform translation and value substitution
  1988. *
  1989. * @return array
  1990. */
  1991. protected function _getErrorMessages()
  1992. {
  1993. $translator = $this->getTranslator();
  1994. $messages = $this->getErrorMessages();
  1995. $value = $this->getValue();
  1996. foreach ($messages as $key => $message) {
  1997. if (null !== $translator) {
  1998. $message = $translator->translate($message);
  1999. }
  2000. if (($this->isArray() || is_array($value))
  2001. && !empty($value)
  2002. ) {
  2003. $aggregateMessages = array();
  2004. foreach ($value as $val) {
  2005. $aggregateMessages[] = str_replace('%value%', $val, $message);
  2006. }
  2007. $messages[$key] = implode($this->getErrorMessageSeparator(), $aggregateMessages);
  2008. } else {
  2009. $messages[$key] = str_replace('%value%', $value, $message);
  2010. }
  2011. }
  2012. return $messages;
  2013. }
  2014. /**
  2015. * Are there custom error messages registered?
  2016. *
  2017. * @return bool
  2018. */
  2019. protected function _hasErrorMessages()
  2020. {
  2021. return !empty($this->_errorMessages);
  2022. }
  2023. }