PageRenderTime 61ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/solar/source/solar/Solar/View/Helper/Form.php

https://bitbucket.org/Sanakan/noise
PHP | 2080 lines | 837 code | 217 blank | 1026 comment | 99 complexity | 99a6a2f37944227d709d81e6f05a5e2e MD5 | raw file
Possible License(s): MIT

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /**
  3. *
  4. * Helper for building CSS-based forms.
  5. *
  6. * This is a fluent class; all method calls except fetch() return
  7. * $this, which means you can chain method calls for easier readability.
  8. *
  9. * @category Solar
  10. *
  11. * @package Solar_View_Helper_Form Helpers for generating form output.
  12. *
  13. * @author Paul M. Jones <pmjones@solarphp.com>
  14. *
  15. * @license http://opensource.org/licenses/bsd-license.php BSD
  16. *
  17. * @version $Id: Form.php 4704 2010-09-30 20:56:49Z pmjones $
  18. *
  19. */
  20. class Solar_View_Helper_Form extends Solar_View_Helper
  21. {
  22. /**
  23. *
  24. * Default configuration values.
  25. *
  26. * @config array attribs Default attributes to use in the <form> tag.
  27. *
  28. * @config array request A Solar_Request dependency injection.
  29. *
  30. * @config string descr_part Where to place descriptions (in the 'label'
  31. * or the 'value').
  32. *
  33. * @config array decorator_tags Use these decorator tags around form
  34. * parts.
  35. *
  36. * @config array decorator_attribs Use these attributes for decorator
  37. * tags.
  38. *
  39. * @config array css_classes Use these CSS classes for form elements.
  40. *
  41. * @config string label_suffix Attach this suffix to all labels.
  42. *
  43. * @var array
  44. *
  45. * @see setDecorators()
  46. *
  47. * @see setDecoratorAttribs()
  48. *
  49. * @see setCssClasses()
  50. *
  51. * @see setDescrPart()
  52. *
  53. * @see setLabelSuffix()
  54. *
  55. */
  56. protected $_Solar_View_Helper_Form = array(
  57. 'attribs' => array(),
  58. 'request' => 'request',
  59. 'descr_part' => 'value',
  60. 'decorator_tags' => array(),
  61. 'decorator_attribs' => array(),
  62. 'css_classes' => array(),
  63. 'label_suffix' => null,
  64. );
  65. /**
  66. *
  67. * Attributes for the form tag set via the auto() method.
  68. *
  69. * @var array
  70. *
  71. */
  72. protected $_attribs_auto = array();
  73. /**
  74. *
  75. * Attributes for the form tag set from the view-helper level.
  76. *
  77. * @var array
  78. *
  79. */
  80. protected $_attribs_view = array();
  81. /**
  82. *
  83. * All form attributes from all sources merged into one array.
  84. *
  85. * @var array
  86. *
  87. */
  88. protected $_attribs_form = array();
  89. /**
  90. *
  91. * Collection of form-level feedback messages.
  92. *
  93. * @var array
  94. *
  95. */
  96. protected $_feedback = array();
  97. /**
  98. *
  99. * Collection of hidden elements.
  100. *
  101. * @var array
  102. *
  103. */
  104. protected $_hidden = array();
  105. /**
  106. *
  107. * Stack of element and layout pieces for the form.
  108. *
  109. * @var array
  110. *
  111. */
  112. protected $_stack = array();
  113. /**
  114. *
  115. * Tracks element IDs so we can have unique IDs for each element.
  116. *
  117. * @var array
  118. *
  119. */
  120. protected $_id_count = array();
  121. /**
  122. *
  123. * CSS classes to use for element and feedback types.
  124. *
  125. * Array format is type => css-class.
  126. *
  127. * @var array
  128. *
  129. */
  130. protected $_css_class = array(
  131. 'button' => 'input-button',
  132. 'checkbox' => 'input-checkbox',
  133. 'date' => 'input-date',
  134. 'file' => 'input-file',
  135. 'hidden' => 'input-hidden',
  136. 'options' => 'input-option',
  137. 'password' => 'input-password',
  138. 'radio' => 'input-radio',
  139. 'reset' => 'input-reset',
  140. 'select' => 'input-select',
  141. 'submit' => 'input-submit',
  142. 'text' => 'input-text',
  143. 'textarea' => 'input-textarea',
  144. 'time' => 'input-time',
  145. 'timestamp' => 'input-timestamp',
  146. 'failure' => 'failure',
  147. 'success' => 'success',
  148. 'require' => 'require',
  149. 'invalid' => 'invalid',
  150. 'descr' => 'descr',
  151. );
  152. /**
  153. *
  154. * The current failure/success status.
  155. *
  156. * @var bool
  157. *
  158. */
  159. protected $_status = null;
  160. /**
  161. *
  162. * Default form tag attributes.
  163. *
  164. * @var array
  165. *
  166. */
  167. protected $_default_attribs = array(
  168. 'action' => null,
  169. 'method' => 'post',
  170. 'enctype' => 'multipart/form-data',
  171. );
  172. /**
  173. *
  174. * Default info for each element.
  175. *
  176. * @var array
  177. *
  178. */
  179. protected $_default_info = array(
  180. 'type' => '',
  181. 'name' => '',
  182. 'value' => '',
  183. 'label' => '',
  184. 'descr' => '',
  185. 'status' => null,
  186. 'attribs' => array(),
  187. 'options' => array(),
  188. 'disable' => false,
  189. 'require' => false,
  190. 'invalid' => array(),
  191. );
  192. /**
  193. *
  194. * Details about the request environment.
  195. *
  196. * @var Solar_Request
  197. *
  198. */
  199. protected $_request;
  200. /**
  201. *
  202. * When building the form, are we currently in an element list?
  203. *
  204. * @var bool
  205. *
  206. */
  207. protected $_in_elemlist = false;
  208. /**
  209. *
  210. * When building the form, are we currently in a grouping?
  211. *
  212. * @var bool
  213. *
  214. */
  215. protected $_in_group = false;
  216. /**
  217. *
  218. * When building the form, are we currently in a fieldset?
  219. *
  220. * @var bool
  221. *
  222. */
  223. protected $_in_fieldset = false;
  224. /**
  225. *
  226. * When building a group of elements, collect the "invalid" messages here.
  227. *
  228. * @var string
  229. *
  230. */
  231. protected $_group_invalid = null;
  232. /**
  233. *
  234. * Add this suffix to all labels.
  235. *
  236. * @var string
  237. *
  238. */
  239. protected $_label_suffix = null;
  240. /**
  241. *
  242. * Which form part the element description goes in: 'label' or 'value'.
  243. *
  244. * @var string
  245. *
  246. */
  247. protected $_descr_part = 'value';
  248. /**
  249. *
  250. * When building XHTML for each of these parts of the form, decorate it
  251. * with the noted tag.
  252. *
  253. * @var array
  254. *
  255. */
  256. protected $_decorator_tags = array(
  257. 'list' => 'dl',
  258. 'elem' => null,
  259. 'label' => 'dt',
  260. 'value' => 'dd',
  261. 'descr' => 'div',
  262. );
  263. /**
  264. *
  265. * When building XHTML for each of these parts of the form, use these
  266. * attributes in its opening tag.
  267. *
  268. * @var array
  269. *
  270. */
  271. protected $_decorator_attribs = array(
  272. 'list' => array(),
  273. 'elem' => array(),
  274. 'label' => array(),
  275. 'value' => array(),
  276. 'descr' => array(),
  277. );
  278. /**
  279. *
  280. * Cross-site request forgery detector.
  281. *
  282. * @var Solar_Csrf
  283. *
  284. */
  285. protected $_csrf;
  286. /**
  287. *
  288. * Post-construction tasks to complete object construction.
  289. *
  290. * @return void
  291. *
  292. */
  293. public function _postConstruct()
  294. {
  295. parent::_postConstruct();
  296. // get the current request environment
  297. $this->_request = Solar::dependency(
  298. 'Solar_Request',
  299. $this->_config['request']
  300. );
  301. // get csrf object
  302. $this->_csrf = Solar::factory('Solar_Csrf');
  303. // make sure we have a default action
  304. $action = $this->_request->server('REQUEST_URI');
  305. $this->_default_attribs['action'] = $action;
  306. // reset the form propertes
  307. $this->reset();
  308. }
  309. /**
  310. *
  311. * Magic __call() for addElement() using element helpers.
  312. *
  313. * Allows $this->elementName() internally, and
  314. * $this->form()->elementType() externally.
  315. *
  316. * @param string $type The form element type (text, radio, etc).
  317. *
  318. * @param array $args Arguments passed to the method call; only
  319. * the first argument is used, the $info array.
  320. *
  321. * @return string The form element helper output.
  322. *
  323. */
  324. public function __call($type, $args)
  325. {
  326. if (! $args) {
  327. throw $this->_exception('ERR_CALL_ARGS', array(
  328. 'type' => $type,
  329. ));
  330. }
  331. $info = $args[0];
  332. if (! is_array($info)) {
  333. throw $this->_exception('ERR_CALL_INFO', array(
  334. 'type' => $type,
  335. 'info' => $info,
  336. ));
  337. }
  338. $info['type'] = $type;
  339. return $this->addElement($info);
  340. }
  341. /**
  342. *
  343. * Magic __toString() to print out the form automatically.
  344. *
  345. * Note that this calls fetch() and will reset the form afterwards.
  346. *
  347. * @return string The form output.
  348. *
  349. */
  350. public function __toString()
  351. {
  352. return $this->fetch();
  353. }
  354. /**
  355. *
  356. * Main method interface to Solar_View.
  357. *
  358. * @param Solar_Form|array $spec If a Solar_Form object, does a
  359. * full auto build and fetch of a form based on the Solar_Form
  360. * properties. If an array, treated as attribute keys and values
  361. * for the <form> tag.
  362. *
  363. * @return string|Solar_View_Helper_Form
  364. *
  365. */
  366. public function form($spec = null)
  367. {
  368. if ($spec instanceof Solar_Form) {
  369. // auto-build and fetch from a Solar_Form object
  370. $this->auto($spec);
  371. return $this->fetch();
  372. } elseif (is_array($spec)) {
  373. // set attributes from an array
  374. foreach ($spec as $key => $val) {
  375. $this->setAttrib($key, $val);
  376. }
  377. return $this;
  378. } else {
  379. // just return self
  380. return $this;
  381. }
  382. }
  383. /**
  384. *
  385. * Sets a form-tag attribute.
  386. *
  387. * @param string $key The attribute name.
  388. *
  389. * @param string $val The attribute value.
  390. *
  391. * @return Solar_View_Helper_Form
  392. *
  393. */
  394. public function setAttrib($key, $val = null)
  395. {
  396. $this->_attribs_view[$key] = $val;
  397. return $this;
  398. }
  399. /**
  400. *
  401. * Sets multiple form-tag attributes.
  402. *
  403. * @param Solar_Form|array $spec If a Solar_Form object, uses the $attribs
  404. * property. If an array, uses the keys as the attribute names and the
  405. * values as the attribute values.
  406. *
  407. * @return Solar_View_Helper_Form
  408. *
  409. */
  410. public function setAttribs($spec)
  411. {
  412. if ($spec instanceof Solar_Form) {
  413. $attribs = (array) $spec->attribs;
  414. } else {
  415. $attribs = (array) $spec;
  416. }
  417. foreach ($attribs as $key => $val) {
  418. $this->setAttrib($key, $val);
  419. }
  420. return $this;
  421. }
  422. /**
  423. *
  424. * Adds to the form-level feedback message array.
  425. *
  426. * @param string|array $spec The feedback message(s).
  427. *
  428. * @return Solar_View_Helper_Form
  429. *
  430. */
  431. public function addFeedback($spec)
  432. {
  433. $this->_feedback = array_merge($this->_feedback, (array) $spec);
  434. return $this;
  435. }
  436. /**
  437. *
  438. * Adds a single element to the form.
  439. *
  440. * @param array $info The element information.
  441. *
  442. * @return Solar_View_Helper_Form
  443. *
  444. */
  445. public function addElement($info)
  446. {
  447. // make sure we have all the info keys we need
  448. $info = array_merge($this->_default_info, $info);
  449. // fix up certain pieces
  450. $this->_fixElementType($info);
  451. $this->_fixElementName($info);
  452. $this->_fixElementId($info);
  453. $this->_fixElementClass($info);
  454. // place in the normal stack, or as hidden?
  455. if (strtolower($info['type']) == 'hidden') {
  456. // hidden elements are a special case
  457. $this->_hidden[] = $info;
  458. } else {
  459. // non-hidden element
  460. $this->_stack[] = array('element', $info);
  461. }
  462. return $this;
  463. }
  464. /**
  465. *
  466. * Adds multiple elements to the form.
  467. *
  468. * @param Solar_Form|array $spec If a Solar_Form object, uses the
  469. * $elements property as the element source. If an array, it is treated
  470. * as a sequential array of element information arrays.
  471. *
  472. * @param array $list A white-list of element names to add from the $spec.
  473. * If empty, all elements from the $spec are added.
  474. *
  475. * @return Solar_View_Helper_Form
  476. *
  477. */
  478. public function addElements($spec, $list = null)
  479. {
  480. if ($spec instanceof Solar_Form) {
  481. $elements = (array) $spec->elements;
  482. } else {
  483. $elements = (array) $spec;
  484. }
  485. $list = (array) $list;
  486. if ($list) {
  487. // add only listed elements, in the order specified by the list
  488. foreach ($list as $name) {
  489. foreach ($elements as $info) {
  490. if ($info['name'] == $name) {
  491. // it's on the list, add it
  492. $this->addElement($info);
  493. break;
  494. }
  495. }
  496. }
  497. } else {
  498. // add all elements
  499. foreach ($elements as $info) {
  500. $this->addElement($info);
  501. }
  502. }
  503. return $this;
  504. }
  505. /**
  506. *
  507. * Adds a submit button named 'process' to the form, using a translated
  508. * locale key stub as the submit value.
  509. *
  510. * @param string $key The locale key stub. E.g., $key is 'save', the
  511. * submit-button value is the locale translated 'PROCESS_SAVE' string.
  512. *
  513. * @param array $info Additional element info.
  514. *
  515. * @return Solar_View_Helper_Form
  516. *
  517. */
  518. public function addProcess($key, $info = null)
  519. {
  520. $key = 'PROCESS_' . strtoupper($key);
  521. $base = array(
  522. 'type' => 'submit',
  523. 'name' => 'process',
  524. 'value' => $this->_view->getTextRaw($key),
  525. );
  526. $info = array_merge($base, (array) $info);
  527. if (empty($info['attribs']['id'])) {
  528. $id = str_replace('_', '-', strtolower($key));
  529. $info['attribs']['id'] = $id;
  530. }
  531. return $this->addElement($info);
  532. }
  533. /**
  534. *
  535. * Adds a group of process buttons with an optional label.
  536. *
  537. * @param array $list An array of process button names. Normally you would
  538. * pass a sequential array ('save', 'delete', 'cancel'). If you like, you
  539. * can pass the process name as the key, with an associative array value
  540. * of element info for that particular submit button.
  541. *
  542. * @param string $label The label for the group.
  543. *
  544. * @return Solar_View_Helper_Form
  545. *
  546. */
  547. public function addProcessGroup($list, $label = null)
  548. {
  549. $this->beginGroup($label);
  550. foreach ((array) $list as $key => $val) {
  551. if (is_array($val)) {
  552. // $key stays the same
  553. $info = $val;
  554. } else {
  555. // sequential array; the value is the process key.
  556. $key = $val;
  557. // no info
  558. $info = array();
  559. }
  560. // add the process within the group
  561. $this->addProcess($key, $info);
  562. }
  563. $this->endGroup();
  564. return $this;
  565. }
  566. /**
  567. *
  568. * Adds arbitrary raw HTML to the form stack outside the normal element
  569. * structure.
  570. *
  571. * @param string $html The raw HTML to add to the stack; it will not
  572. * be escaped for you at output time.
  573. *
  574. * @return Solar_View_Helper_Form
  575. *
  576. */
  577. public function addHtml($html)
  578. {
  579. $this->_stack[] = array('html', $html);
  580. return $this;
  581. }
  582. /**
  583. *
  584. * Sets the form validation status.
  585. *
  586. * @param bool $flag True if you want to say the form is valid,
  587. * false if you want to say it is not valid, null if you want to
  588. * say that validation has not been attempted.
  589. *
  590. * @return Solar_View_Helper_Form
  591. *
  592. */
  593. public function setStatus($flag)
  594. {
  595. if ($flag === null) {
  596. $this->_status = null;
  597. } else {
  598. $this->_status = (bool) $flag;
  599. }
  600. return $this;
  601. }
  602. /**
  603. *
  604. * Gets the form validation status.
  605. *
  606. * @return bool True if the form is currently valid, false if not,
  607. * null if validation has not been attempted.
  608. *
  609. */
  610. public function getStatus()
  611. {
  612. return $this->_status;
  613. }
  614. /**
  615. *
  616. * Automatically adds multiple pieces to the form.
  617. *
  618. * @param Solar_Form|array $spec If a Solar_Form object, adds attributes,
  619. * elements and feedback, and sets status, from the object properties.
  620. * If an array, treats it as a a collection of element info
  621. * arrays and adds them.
  622. *
  623. * @return Solar_View_Helper_Form
  624. *
  625. */
  626. public function auto($spec)
  627. {
  628. if ($spec instanceof Solar_Form) {
  629. // set status, merge attribs, add feedback
  630. $this->meta($spec);
  631. // add elements
  632. foreach ((array) $spec->elements as $info) {
  633. $this->addElement($info);
  634. }
  635. } elseif (is_array($spec)) {
  636. // add from an array of elements.
  637. foreach ($spec as $info) {
  638. $this->addElement($info);
  639. }
  640. }
  641. // done
  642. return $this;
  643. }
  644. /**
  645. *
  646. * Automatically adds attributes and feedback, and sets status, for the
  647. * form as a whole from a Solar_Form object.
  648. *
  649. * @param Solar_Form $form Add from this form object.
  650. *
  651. * @return Solar_View_Helper_Form
  652. *
  653. */
  654. public function meta(Solar_Form $form)
  655. {
  656. // add from a Solar_Form object.
  657. // set the form status.
  658. $this->setStatus($form->getStatus());
  659. // retain the automatic attribs separately from those
  660. // specified at the view level (i.e. in this object)
  661. $this->_attribs_auto = array_merge(
  662. (array) $this->_attribs_auto,
  663. (array) $form->attribs
  664. );
  665. // add form-level feedback
  666. $this->addFeedback($form->feedback);
  667. // done
  668. return $this;
  669. }
  670. /**
  671. *
  672. * Begins a group of form elements under a single label.
  673. *
  674. * @param string $label The label text.
  675. *
  676. * @return Solar_View_Helper_Form
  677. *
  678. */
  679. public function beginGroup($label = null)
  680. {
  681. $this->_stack[] = array('group', array(true, $label));
  682. return $this;
  683. }
  684. /**
  685. *
  686. * Ends a group of form elements.
  687. *
  688. * @return Solar_View_Helper_Form
  689. *
  690. */
  691. public function endGroup()
  692. {
  693. $this->_stack[] = array('group', array(false, null));
  694. return $this;
  695. }
  696. /**
  697. *
  698. * Begins a <fieldset> block with a legend/caption.
  699. *
  700. * @param string $legend The legend or caption for the fieldset.
  701. *
  702. * @param array $attribs Attributes for the fieldset tag.
  703. *
  704. * @return Solar_View_Helper_Form
  705. *
  706. */
  707. public function beginFieldset($legend, $attribs = null)
  708. {
  709. $this->_stack[] = array('fieldset', array(
  710. 'flag' => true,
  711. 'label' => $legend,
  712. 'attribs' => $attribs,
  713. ));
  714. return $this;
  715. }
  716. /**
  717. *
  718. * Ends a <fieldset> block.
  719. *
  720. * @return Solar_View_Helper_Form
  721. *
  722. */
  723. public function endFieldset()
  724. {
  725. $this->_stack[] = array('fieldset', array(
  726. 'flag' => false,
  727. 'label' => null,
  728. 'attribs' => null,
  729. ));
  730. return $this;
  731. }
  732. /**
  733. *
  734. * If a CSRF element is needed but not present, add it; if present and not
  735. * needed, remove it.
  736. *
  737. * @return void
  738. *
  739. */
  740. protected function _modCsrfElement()
  741. {
  742. // the name of the csrf element
  743. $name = $this->_csrf->getKey();
  744. // if using GET, don't add csrf if not already there ...
  745. $method = strtolower($this->_attribs_form['method']);
  746. if ($method == 'get') {
  747. // ... and remove it if present.
  748. foreach ($this->_hidden as $key => $info) {
  749. if ($info['name'] == $name) {
  750. unset($this->_hidden[$key]);
  751. }
  752. }
  753. // done
  754. return;
  755. }
  756. // if no token, nothing to add
  757. if (! $this->_csrf->hasToken()) {
  758. return;
  759. }
  760. // is a csrf element already present?
  761. foreach ($this->_hidden as $info) {
  762. if ($info['name'] == $name) {
  763. // found it, no need to add it
  764. return;
  765. }
  766. }
  767. // add the token to the hidden elements
  768. $this->addElement(array(
  769. 'name' => $name,
  770. 'type' => 'hidden',
  771. 'value' => $this->_csrf->getToken(),
  772. ));
  773. }
  774. /**
  775. *
  776. * Builds and returns the form output, adding a hidden CSRF element as
  777. * needed.
  778. *
  779. * @param bool $with_form_tag If true (the default) outputs the form with
  780. * <form>...</form> tags. If false, it does not.
  781. *
  782. * @return string
  783. *
  784. */
  785. public function fetch($with_form_tag = true)
  786. {
  787. // merge all form-level attributes
  788. $this->_setAttribsForm();
  789. // add or remove the csrf value as needed
  790. $this->_modCsrfElement();
  791. // stack of output pieces
  792. $html = array();
  793. // the opening form tag?
  794. if ($with_form_tag) {
  795. $this->_buildBegin($html);
  796. }
  797. // all feedback, hidden, element, etc
  798. $this->_buildStack($html);
  799. // the closing form tag?
  800. if ($with_form_tag) {
  801. $this->_buildEnd($html);
  802. }
  803. // reset for the next pass
  804. $this->reset();
  805. // done, return the output pieces!
  806. return implode("\n", $html);
  807. }
  808. /**
  809. *
  810. * Resets the form entirely.
  811. *
  812. * @return Solar_View_Helper_Form
  813. *
  814. */
  815. public function reset()
  816. {
  817. // form-tag attributes at the auto() level
  818. $this->_attribs_auto = array();
  819. // form-tag attributes at the view level
  820. $this->_attribs_view = array();
  821. // merged form-tag attributes from all levels
  822. $this->_attribs_form = array();
  823. // where does the descr go?
  824. $this->setDescrPart($this->_config['descr_part']);
  825. // custom CSS classes
  826. $this->setCssClasses($this->_config['css_classes']);
  827. // default decorator tags ...
  828. $this->decorateAsDlList();
  829. // ... then custom decorator tags ...
  830. $this->setDecorators($this->_config['decorator_tags']);
  831. // ... then custom decorator attribs
  832. $attribs = $this->_config['decorator_attribs'];
  833. if ($attribs) {
  834. foreach ((array) $attribs as $part => $values) {
  835. $this->setDecoratorAttribs($part, $values);
  836. }
  837. }
  838. // label suffix
  839. $this->setLabelSuffix($this->_config['label_suffix']);
  840. // build-tracking properties
  841. $this->_in_elemlist = false;
  842. $this->_in_group = false;
  843. $this->_in_fieldset = false;
  844. // everything else
  845. $this->_feedback = array();
  846. $this->_hidden = array();
  847. $this->_stack = array();
  848. $this->_status = null;
  849. // we *do not* reset $this->_id_count, because the form helper may be
  850. // reused for another form on the same page. need to keep the count
  851. // so that IDs in the second and subsequent forms have unique values.
  852. return $this;
  853. }
  854. /**
  855. *
  856. * Merges the form-tag attributes in this fashion, with the later ones
  857. * overriding the earlier ones:
  858. *
  859. * 1. The $_default_attribs array.
  860. *
  861. * 2. The $_config['attribs'] array.
  862. *
  863. * 3. Any attribs set via the auto() method.
  864. *
  865. * 4. Any attribs set via setAttrib() or setAttribs().
  866. *
  867. * This keeps it so that values set directly in the view object take
  868. * precedence over anything automated via a form object.
  869. *
  870. * @return void
  871. *
  872. */
  873. protected function _setAttribsForm()
  874. {
  875. $this->_attribs_form = array_merge(
  876. (array) $this->_default_attribs,
  877. (array) $this->_config['attribs'],
  878. (array) $this->_attribs_auto,
  879. (array) $this->_attribs_view
  880. );
  881. }
  882. /**
  883. *
  884. * Fixes the element info 'type' value; by default, it just throws an
  885. * exception when the 'type' is empty.
  886. *
  887. * @param array &$info A reference to the element info array.
  888. *
  889. * @return void
  890. *
  891. */
  892. protected function _fixElementType(&$info)
  893. {
  894. if (empty($info['type'])) {
  895. throw $this->_exception('ERR_NO_ELEMENT_TYPE', $info);
  896. }
  897. }
  898. /**
  899. *
  900. * Fixes the element info 'name' value; by default, it just throws an
  901. * exception when the 'name' is empty on non-xhtml element types.
  902. *
  903. * @param array &$info A reference to the element info array.
  904. *
  905. * @return void
  906. *
  907. */
  908. protected function _fixElementName(&$info)
  909. {
  910. if (empty($info['name']) && $info['type'] != 'xhtml') {
  911. throw $this->_exception('ERR_NO_ELEMENT_NAME', $info);
  912. }
  913. }
  914. /**
  915. *
  916. * Fixes the element info 'id' value.
  917. *
  918. * When no ID is present, auto-sets an ID from the element name.
  919. *
  920. * Appends sequential integers to the ID as needed to deconflict matching
  921. * ID values.
  922. *
  923. * @param array &$info A reference to the element info array.
  924. *
  925. * @return void
  926. *
  927. */
  928. protected function _fixElementId(&$info)
  929. {
  930. // auto-set the ID?
  931. if (empty($info['attribs']['id'])) {
  932. // convert name[key][subkey] to name-key-subkey
  933. $info['attribs']['id'] = str_replace(
  934. array('[', ']'),
  935. array('-', ''),
  936. $info['name']
  937. );
  938. }
  939. // convenience variable
  940. $id = $info['attribs']['id'];
  941. // is this id already in use?
  942. if (empty($this->_id_count[$id])) {
  943. // not used yet, start tracking it
  944. $this->_id_count[$id] = 1;
  945. } else {
  946. // already in use, increment the count.
  947. // for example, 'this-id' becomes 'this-id-1',
  948. // next one is 'this-id-2', etc.
  949. $id .= "-" . $this->_id_count[$id] ++;
  950. $info['attribs']['id'] = $id;
  951. }
  952. }
  953. /**
  954. *
  955. * Fixes the element info 'class' value to add classes for the element
  956. * type, ID, require, and validation status -- but only if the class is
  957. * empty to begin with.
  958. *
  959. * @param array &$info A reference to the element info array.
  960. *
  961. * @return void
  962. *
  963. */
  964. protected function _fixElementClass(&$info)
  965. {
  966. // skip is classes are already set
  967. if (! empty($info['attribs']['class'])) {
  968. return;
  969. }
  970. // add a CSS class for the element type
  971. if (! empty($this->_css_class[$info['type']])) {
  972. $info['attribs']['class'] = $this->_css_class[$info['type']];
  973. } else {
  974. $info['attribs']['class'] = '';
  975. }
  976. // also use the element ID for further overrides
  977. $info['attribs']['class'] .= ' ' . $info['attribs']['id'];
  978. // passed validation?
  979. if ($info['status'] === true) {
  980. $info['attribs']['class'] .= ' ' . $this->_css_class['success'];
  981. }
  982. // failed validation?
  983. if ($info['status'] === false) {
  984. $info['attribs']['class'] .= ' ' . $this->_css_class['failure'];
  985. }
  986. // required?
  987. if ($info['require']) {
  988. $info['attribs']['class'] .= ' ' . $this->_css_class['require'];
  989. }
  990. }
  991. /**
  992. *
  993. * Returns text indented to a number of levels, accounting for whether
  994. * or not we are in a fieldset.
  995. *
  996. * @param int $num The number of levels to indent.
  997. *
  998. * @param string $text The text to indent.
  999. *
  1000. * @return string The indented text.
  1001. *
  1002. */
  1003. protected function _indent($num, $text = null)
  1004. {
  1005. if ($this->_in_fieldset) {
  1006. $num += 1;
  1007. }
  1008. return str_pad('', $num * 4) . $text;
  1009. }
  1010. /**
  1011. *
  1012. * Builds the opening <form> tag for output.
  1013. *
  1014. * @param array &$html A reference to the array of HTML lines for output.
  1015. *
  1016. * @return void
  1017. *
  1018. */
  1019. protected function _buildBegin(&$html)
  1020. {
  1021. $html[] = '<form' . $this->_view->attribs($this->_attribs_form) . '>';
  1022. }
  1023. /**
  1024. *
  1025. * Builds the closing </form> tag for output.
  1026. *
  1027. * @param array &$html A reference to the array of HTML lines for output.
  1028. *
  1029. * @return void
  1030. *
  1031. */
  1032. protected function _buildEnd(&$html)
  1033. {
  1034. $html[] = '</form>';
  1035. }
  1036. /**
  1037. *
  1038. * Builds the form-level feedback tag for output.
  1039. *
  1040. * @param array &$html A reference to the array of HTML lines for output.
  1041. *
  1042. * @return void
  1043. *
  1044. */
  1045. protected function _buildFeedback(&$html)
  1046. {
  1047. if (empty($this->_feedback)) {
  1048. return;
  1049. }
  1050. // what status class should we use?
  1051. if ($this->_status === true) {
  1052. $class = $this->_css_class['success'];
  1053. } elseif ($this->_status === false) {
  1054. $class = $this->_css_class['failure'];
  1055. } else {
  1056. $class = null;
  1057. }
  1058. if ($class) {
  1059. $open = '<ul class="' . $this->_view->escape($class) . '">';
  1060. } else {
  1061. $open = '<ul>';
  1062. }
  1063. $html[] = $this->_indent(1, $open);
  1064. foreach ((array) $this->_feedback as $item) {
  1065. $item = '<li>' . $this->_view->escape($item) . '</li>';
  1066. $html[] = $this->_indent(2, $item);
  1067. }
  1068. $html[] = $this->_indent(1, "</ul>");
  1069. }
  1070. /**
  1071. *
  1072. * Builds the stack of hidden elements for output.
  1073. *
  1074. * @param array &$html A reference to the array of HTML lines for output.
  1075. *
  1076. * @return void
  1077. *
  1078. */
  1079. protected function _buildHidden(&$html)
  1080. {
  1081. // wrap in a hidden fieldset for XHTML-Strict compliance
  1082. $html[] = ' <fieldset style="display: none;">';
  1083. foreach ($this->_hidden as $info) {
  1084. $html[] = ' ' . $this->_view->formHidden($info);
  1085. }
  1086. $html[] = ' </fieldset>';
  1087. }
  1088. /**
  1089. *
  1090. * Builds the stack of non-hidden elements for output.
  1091. *
  1092. * @param array &$html A reference to the array of HTML lines for output.
  1093. *
  1094. * @return void
  1095. *
  1096. */
  1097. protected function _buildStack(&$html)
  1098. {
  1099. // form-level feedback
  1100. $this->_buildFeedback($html);
  1101. // the hidden elements
  1102. if ($this->_hidden) {
  1103. $this->_buildHidden($html);
  1104. }
  1105. $this->_in_fieldset = false;
  1106. $this->_in_group = false;
  1107. $this->_in_elemlist = false;
  1108. foreach ($this->_stack as $key => $val) {
  1109. $type = $val[0];
  1110. $info = $val[1];
  1111. if ($type == 'element') {
  1112. $this->_buildElement($html, $info);
  1113. } elseif ($type == 'group') {
  1114. $this->_buildGroup($html, $info);
  1115. } elseif ($type == 'fieldset') {
  1116. $this->_buildFieldset($html, $info);
  1117. } elseif ($type == 'html') {
  1118. $this->_buildHtml($html, $info);
  1119. }
  1120. }
  1121. // close up any loose ends
  1122. $this->_buildGroupEnd($html);
  1123. $this->_buildElementListEnd($html);
  1124. $this->_buildFieldsetEnd($html);
  1125. }
  1126. /**
  1127. *
  1128. * Builds added HTML for output.
  1129. *
  1130. * @param array &$html A reference to the array of HTML lines for output.
  1131. *
  1132. * @param string $info The raw HTML to add to the output.
  1133. *
  1134. * @return void
  1135. *
  1136. */
  1137. protected function _buildHtml(&$html, $info)
  1138. {
  1139. $html[] = $info;
  1140. }
  1141. /**
  1142. *
  1143. * Builds a single element label and value for output.
  1144. *
  1145. * @param array &$html A reference to the array of HTML lines for output.
  1146. *
  1147. * @param array $info The array of element information.
  1148. *
  1149. * @return void
  1150. *
  1151. */
  1152. protected function _buildElement(&$html, $info)
  1153. {
  1154. $this->_buildElementListBegin($html);
  1155. $this->_buildElementBegin($html, $info);
  1156. $this->_buildElementLabel($html, $info);
  1157. $this->_buildElementValue($html, $info);
  1158. $this->_buildElementEnd($html);
  1159. }
  1160. /**
  1161. *
  1162. * Builds the beginning decorator of an element.
  1163. *
  1164. * @param array &$html A reference to the array of HTML lines for output.
  1165. *
  1166. * @param array $info The array of element information.
  1167. *
  1168. * @return void
  1169. *
  1170. */
  1171. protected function _buildElementBegin(&$html, $info = null)
  1172. {
  1173. if ($this->_in_group) {
  1174. return;
  1175. }
  1176. $this->_buildDecoratorBegin($html, 'elem', 2, $info);
  1177. }
  1178. /**
  1179. *
  1180. * Builds the ending decorator of an element.
  1181. *
  1182. * @param array &$html A reference to the array of HTML lines for output.
  1183. *
  1184. * @return void
  1185. *
  1186. */
  1187. protected function _buildElementEnd(&$html)
  1188. {
  1189. if ($this->_in_group) {
  1190. return;
  1191. }
  1192. $this->_buildDecoratorEnd($html, 'elem', 2);
  1193. }
  1194. /**
  1195. *
  1196. * Modifies the element label information before building for output.
  1197. *
  1198. * @param array &$info A reference to the element label information.
  1199. *
  1200. * @return void
  1201. *
  1202. */
  1203. protected function _buildElementLabelInfo(&$info)
  1204. {
  1205. $attribs = array(
  1206. 'for' => null,
  1207. 'class' => array(),
  1208. );
  1209. // does the element have an ID?
  1210. if (! empty($info['attribs']['id'])) {
  1211. $attribs['for'] = $info['attribs']['id'];
  1212. $attribs['class'][] = $info['attribs']['id'];
  1213. }
  1214. // add a class for the element
  1215. // is the element required?
  1216. if ($info['require']) {
  1217. $attribs['class'][] = $this->_css_class['require'];
  1218. }
  1219. // is the element invalid?
  1220. if ($info['invalid']) {
  1221. $attribs['class'][] = $this->_css_class['invalid'];
  1222. }
  1223. // checkbox elements don't get an "extra" label
  1224. if (strtolower($info['type']) == 'checkbox') {
  1225. $info['label'] = null;
  1226. }
  1227. // reset attribs
  1228. $info['attribs'] = $attribs;
  1229. // add the label suffix
  1230. $info['label'] .= $this->_label_suffix;
  1231. }
  1232. /**
  1233. *
  1234. * Builds the label portion of an element for output.
  1235. *
  1236. * @param array &$html A reference to the array of HTML lines for output.
  1237. *
  1238. * @param array $info The array of element information.
  1239. *
  1240. * @return void
  1241. *
  1242. */
  1243. protected function _buildElementLabel(&$html, $info)
  1244. {
  1245. if ($this->_in_group) {
  1246. // no labels while in an element group
  1247. return;
  1248. }
  1249. // open the label decorator
  1250. $this->_buildDecoratorBegin($html, 'label', 3, $info);
  1251. // modify information **just for the label portion**
  1252. $this->_buildElementLabelInfo($info);
  1253. $label = $this->_view->formLabel($info);
  1254. $html[] = $this->_indent(4, $label);
  1255. // do descriptions go in the label part?
  1256. if ($this->_descr_part == 'label') {
  1257. $this->_buildElementDescr($html, $info);
  1258. }
  1259. // close the label decorator
  1260. $this->_buildDecoratorEnd($html, 'label', 3, $info);
  1261. }
  1262. /**
  1263. *
  1264. * Modifies the element value information before building for output.
  1265. *
  1266. * @param array &$info A reference to the element value information.
  1267. *
  1268. * @return void
  1269. *
  1270. */
  1271. protected function _buildElementValueInfo(&$info)
  1272. {
  1273. }
  1274. /**
  1275. *
  1276. * Builds the value portion of an element for output.
  1277. *
  1278. * @param array &$html A reference to the array of HTML lines for output.
  1279. *
  1280. * @param array $info The array of element information.
  1281. *
  1282. * @return void
  1283. *
  1284. */
  1285. protected function _buildElementValue(&$html, $info)
  1286. {
  1287. // modify information **just for the value portion**
  1288. $this->_buildElementValueInfo($info);
  1289. try {
  1290. // look for the requested element helper
  1291. $method = 'form' . ucfirst($info['type']);
  1292. $helper = $this->_view->getHelper($method);
  1293. } catch (Solar_Class_Stack_Exception_ClassNotFound $e) {
  1294. // use 'text' helper as a fallback
  1295. $method = 'formText';
  1296. $helper = $this->_view->getHelper($method);
  1297. }
  1298. // get the element output
  1299. $element = $helper->$method($info);
  1300. // handle differently if we're in a group
  1301. if ($this->_in_group) {
  1302. $html[] = $this->_indent(4, $element);
  1303. $this->_buildGroupInvalid($info);
  1304. return;
  1305. }
  1306. // open the value decorator
  1307. $this->_buildDecoratorBegin($html, 'value', 3, $info);
  1308. // add the element
  1309. $html[] = $this->_indent(4, $element);
  1310. // add invalid messages
  1311. $this->_buildElementInvalid($html, $info);
  1312. // add description
  1313. if ($this->_descr_part == 'value') {
  1314. $this->_buildElementDescr($html, $info);
  1315. }
  1316. // close the decorator
  1317. $this->_buildDecoratorEnd($html, 'value', 3, $info);
  1318. }
  1319. /**
  1320. *
  1321. * Builds the list of "invalid" messages for a single element.
  1322. *
  1323. * @param array &$html A reference to the array of HTML lines for output.
  1324. *
  1325. * @param array $info The array of element information.
  1326. *
  1327. * @return void
  1328. *
  1329. */
  1330. protected function _buildElementInvalid(&$html, $info)
  1331. {
  1332. if (empty($info['invalid'])) {
  1333. return;
  1334. }
  1335. $this->_view->getHelper('formInvalid')->setIndent(4);
  1336. $html[] = $this->_view->formInvalid($info);
  1337. }
  1338. /**
  1339. *
  1340. * Builds the element description for output.
  1341. *
  1342. * @param array &$html A reference to the array of HTML lines for output.
  1343. *
  1344. * @param array $info The array of element information.
  1345. *
  1346. * @return void
  1347. *
  1348. */
  1349. protected function _buildElementDescr(&$html, $info)
  1350. {
  1351. // only build a description if it's non-empty, and isn't a
  1352. // DESCR_* "empty" locale value.
  1353. if (! $info['descr'] || substr($info['descr'], 0, 6) == 'DESCR_') {
  1354. return;
  1355. }
  1356. // open the tag
  1357. $descr = "<" . $this->_view->escape($this->_decorator_tags['descr']);
  1358. // get the attribs for it
  1359. $attribs = $this->_decorator_attribs['descr'];
  1360. // add a CSS class
  1361. if ($this->_css_class['descr']) {
  1362. $attribs['class'][] = $this->_css_class['descr'];
  1363. }
  1364. // add the attribs
  1365. $descr .= $this->_view->attribs($attribs) . '>';
  1366. // add the raw descr XHTML and close the tag.
  1367. $descr .= $info['descr'] . "</{$this->_decorator_tags['descr']}>";
  1368. $html[] = $this->_indent(4, $descr);
  1369. }
  1370. /**
  1371. *
  1372. * Builds the beginning of an element list for output.
  1373. *
  1374. * @param array &$html A reference to the array of HTML lines for output.
  1375. *
  1376. * @return void
  1377. *
  1378. */
  1379. protected function _buildElementListBegin(&$html)
  1380. {
  1381. if ($this->_in_elemlist) {
  1382. // already in a list, don't begin again
  1383. return;
  1384. }
  1385. $this->_buildDecoratorBegin($html, 'list', 1);
  1386. $this->_in_elemlist = true;
  1387. }
  1388. /**
  1389. *
  1390. * Builds the ending of an element list for output.
  1391. *
  1392. * @param array &$html A reference to the array of HTML lines for output.
  1393. *
  1394. * @return void
  1395. *
  1396. */
  1397. protected function _buildElementListEnd(&$html)
  1398. {
  1399. if (! $this->_in_elemlist) {
  1400. // can't end a list if not in one
  1401. return;
  1402. }
  1403. $this->_buildDecoratorEnd($html, 'list', 1);
  1404. $this->_in_elemlist = false;
  1405. }
  1406. /**
  1407. *
  1408. * Builds a group beginning/ending for output.
  1409. *
  1410. * @param array &$html A reference to the array of HTML lines for output.
  1411. *
  1412. * @param array $info The array of element information.
  1413. *
  1414. * @return void
  1415. *
  1416. */
  1417. protected function _buildGroup(&$html, $info)
  1418. {
  1419. $flag = $info[0];
  1420. $label = $info[1];
  1421. if ($flag) {
  1422. $this->_buildGroupEnd($html);
  1423. $this->_buildGroupBegin($html, $label);
  1424. } else {
  1425. $this->_buildGroupEnd($html);
  1426. }
  1427. }
  1428. /**
  1429. *
  1430. * Builds an element group label for output and begins the grouping.
  1431. *
  1432. * @param array &$html A reference to the array of HTML lines for output.
  1433. *
  1434. * @param string $label The group label.
  1435. *
  1436. * @return void
  1437. *
  1438. */
  1439. protected function _buildGroupBegin(&$html, $label)
  1440. {
  1441. if ($this->_in_group) {
  1442. // already in a group, don't start another one
  1443. return;
  1444. }
  1445. $this->_buildElementListBegin($html);
  1446. $this->_buildElementBegin($html);
  1447. $this->_buildDecoratorBegin($html, 'label', 3);
  1448. $label = $this->_view->formLabel(array('label' => $label));
  1449. $html[] = $this->_indent(4, $label);
  1450. $this->_buildDecoratorEnd($html, 'label', 3);
  1451. $this->_buildDecoratorBegin($html, 'value', 3);
  1452. $this->_group_invalid = null;
  1453. $this->_in_group = true;
  1454. }
  1455. /**
  1456. *
  1457. * Builds the end of an element group.
  1458. *
  1459. * @param array &$html A reference to the array of HTML lines for output.
  1460. *
  1461. * @return void
  1462. *
  1463. */
  1464. protected function _buildGroupEnd(&$html)
  1465. {
  1466. if (! $this->_in_group) {
  1467. // not in a group so can't end it
  1468. return;
  1469. }
  1470. if ($this->_group_invalid) {
  1471. $html[] = $this->_indent(4, $this->_group_invalid);
  1472. $this->_group_invalid = null;
  1473. }
  1474. $this->_buildDecoratorEnd($html, 'value', 3);
  1475. $this->_in_group = false;
  1476. $this->_buildElementEnd($html);
  1477. }
  1478. /**
  1479. *
  1480. * Builds the list of "invalid" messages while in an element group.
  1481. *
  1482. * @param array $info The array of element information.
  1483. *
  1484. * @return void
  1485. *
  1486. */
  1487. protected function _buildGroupInvalid($info)
  1488. {
  1489. $html = array();
  1490. $this->_buildElementInvalid($html, $info);
  1491. $this->_group_invalid .= implode("\n", $html);
  1492. }
  1493. /**
  1494. *
  1495. * Builds a fieldset beginning/ending for output.
  1496. *
  1497. * @param array &$html A reference to the array of HTML lines for output.
  1498. *
  1499. * @param array $info The array of element information.
  1500. *
  1501. * @return void
  1502. *
  1503. */
  1504. protected function _buildFieldset(&$html, $info)
  1505. {
  1506. $flag = $info['flag'];
  1507. if ($flag) {
  1508. // end any previous groups, lists, and sets
  1509. $this->_buildGroupEnd($html);
  1510. $this->_buildElementListEnd($html);
  1511. $this->_buildFieldsetEnd($html);
  1512. // start a new set
  1513. $legend = $info['label'];
  1514. $attribs = $info['attribs'];
  1515. $this->_buildFieldsetBegin($html, $legend, $attribs);
  1516. } else {
  1517. // end previous groups, lists, and sets
  1518. $this->_buildGroupEnd($html);
  1519. $this->_buildElementListEnd($html);
  1520. $this->_buildFieldsetEnd($html);
  1521. }
  1522. }
  1523. /**
  1524. *
  1525. * Builds the beginning of a fieldset and its legend.
  1526. *
  1527. * @param array &$html A reference to the array of HTML lines for output.
  1528. *
  1529. * @param string $legend The legend for the fieldset.
  1530. *
  1531. * @param array $attribs Attributes for the fieldset tag.
  1532. *
  1533. * @return void
  1534. *
  1535. */
  1536. protected function _buildFieldsetBegin(&$html, $legend, $attribs)
  1537. {
  1538. if ($this->_in_fieldset) {
  1539. // already in a fieldset, don't start another one
  1540. return;
  1541. }
  1542. $attr = $this->_view->attribs($attribs);
  1543. $html[] = $this->_indent(1, "<fieldset{$attr}>");
  1544. if ($legend) {
  1545. $legend = $this->_view->getText($legend);
  1546. $html[] = $this->_indent(2, "<legend>$legend</legend>");
  1547. }
  1548. $this->_in_fieldset = true;
  1549. }
  1550. /**
  1551. *
  1552. * Builds the end of a fieldset.
  1553. *
  1554. * @param array &$html A reference to the array of HTML lines for output.
  1555. *
  1556. * @return void
  1557. *
  1558. */
  1559. protected function _buildFieldsetEnd(&$html)
  1560. {
  1561. if (! $this->_in_fieldset) {
  1562. // not in a fieldset, so can't end it
  1563. return;
  1564. }
  1565. $this->_in_fieldset = false;
  1566. $html[] = $this->_indent(1, "</fieldset>");
  1567. }
  1568. /**
  1569. *
  1570. * Builds the beginning of a decorator.
  1571. *
  1572. * @param array &$html A reference to the array of HTML lines for output.
  1573. *
  1574. * @param array $type The decorator type to use: 'list', 'elem', 'label',
  1575. * or 'value'.
  1576. *
  1577. * @param int $indent Indent the decorator this many times.
  1578. *
  1579. * @param array $info For 'label' and 'value' decorators, the label or
  1580. * value information array.
  1581. *
  1582. * @return void
  1583. *
  1584. */
  1585. protected function _buildDecoratorBegin(&$html, $type, $indent, $info = null)
  1586. {
  1587. if (! $this->_decorator_tags[$type]) {
  1588. return;
  1589. }
  1590. $attribs = $this->_decorator_attribs[$type];
  1591. if (empty($attribs['class'])) {
  1592. $attribs['class'] = array();
  1593. } else {
  1594. settype($attribs['class'], 'array');
  1595. }
  1596. if (! empty($info['attribs']['id'])) {
  1597. $attribs['class'][] = $info['attribs']['id'];
  1598. }
  1599. if (empty($attribs['class'])) {
  1600. $attribs['class'] = $type;
  1601. }
  1602. if (! empty($info['require'])) {
  1603. $attribs['class'][] = 'require';
  1604. }
  1605. if (! empty($info['invalid'])) {
  1606. $attribs['class'][] = 'invalid';
  1607. }
  1608. $decorator = '<'
  1609. . $this->_decorator_tags[$type]
  1610. . $this->_view->attribs($attribs)
  1611. . '>';
  1612. $html[] = $this->_indent($indent, $decorator);
  1613. }
  1614. /**
  1615. *
  1616. * Builds the end of a decorator.
  1617. *
  1618. * @param array &$html A reference to the array of HTML lines for output.
  1619. *
  1620. * @param array $type The decorator type to use: 'list', 'elem', 'label',
  1621. * or 'value'.
  1622. *
  1623. * @param int $indent Indent the decorator this many times.
  1624. *
  1625. * @param array $info For 'label' and 'value' decorators, the label or
  1626. * value information array.
  1627. *
  1628. * @return void
  1629. *
  1630. */
  1631. protected function _buildDecoratorEnd(&$html, $type, $indent, $info = null)
  1632. {
  1633. if (! $this->_decorator_tags[$type]) {
  1634. return;
  1635. }
  1636. $decorator = "</{$this->_decorator_tags[$type]}>";
  1637. $html[] = $this->_indent($indent, $decorator);
  1638. }
  1639. /**
  1640. *
  1641. * Use this suffix string on all labels; for example, ": ".
  1642. *
  1643. * @param string $suffix The suffix string to use.
  1644. *
  1645. * @return Solar_View_Helper_Form
  1646. *
  1647. */
  1648. public function setLabelSuffix($suffix)
  1649. {
  1650. $this->_label_suffix = $suffix;
  1651. return $this;
  1652. }
  1653. /**
  1654. *
  1655. * When fetching output, render elements as part of an HTML table.
  1656. *
  1657. * @return void
  1658. *
  1659. */
  1660. public function decorateAsTable()
  1661. {
  1662. $this->setDecorators(array(
  1663. 'list' => 'table',
  1664. 'elem' => 'tr',
  1665. 'label' => 'th',
  1666. 'value' => 'td',
  1667. ));
  1668. return $this;
  1669. }
  1670. /**
  1671. *
  1672. * When fetching output, render elements as part of an HTML definition list.
  1673. *
  1674. * @return void
  1675. *
  1676. */
  1677. public function decorateAsDlList()
  1678. {
  1679. $this->setDecorators(array(
  1680. 'list' => 'dl',
  1681. 'elem' => null,
  1682. 'label' => 'dt',
  1683. 'value' => 'dd',
  1684. ));
  1685. return $this;
  1686. }
  1687. /**
  1688. *
  1689. * When fetching output, render the list and elements inside divs.
  1690. *
  1691. * @return void
  1692. *
  1693. */
  1694. public function decorateAsDivs()
  1695. {
  1696. $this->setDecorators(array(
  1697. 'list' => 'div',
  1698. 'elem' => 'div',
  1699. 'label' => null,
  1700. 'value' => null,
  1701. ));
  1702. return $this;
  1703. }
  1704. /**
  1705. *
  1706. * When f…

Large files files are truncated, but you can click here to view the full file