Element.php 59 KB

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