Element.php 62 KB

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