Element.php 61 KB

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