/system/library/PEAR/HTML/QuickForm2/Renderer/Callback.php

https://bitbucket.org/spekkionu/passworddb · PHP · 774 lines · 423 code · 53 blank · 298 comment · 56 complexity · a1a43f76738f2bc496b42dce6e03f4c6 MD5 · raw file

  1. <?php
  2. /**
  3. * Callback renderer for HTML_QuickForm2
  4. *
  5. * PHP version 5
  6. *
  7. * LICENSE:
  8. *
  9. * Copyright (c) 2006-2012, Alexey Borzov <avb@php.net>,
  10. * Bertrand Mansion <golgote@mamasam.com>
  11. * All rights reserved.
  12. *
  13. * Redistribution and use in source and binary forms, with or without
  14. * modification, are permitted provided that the following conditions
  15. * are met:
  16. *
  17. * * Redistributions of source code must retain the above copyright
  18. * notice, this list of conditions and the following disclaimer.
  19. * * Redistributions in binary form must reproduce the above copyright
  20. * notice, this list of conditions and the following disclaimer in the
  21. * documentation and/or other materials provided with the distribution.
  22. * * The names of the authors may not be used to endorse or promote products
  23. * derived from this software without specific prior written permission.
  24. *
  25. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  26. * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  27. * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  28. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  29. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  30. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  31. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  32. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  33. * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  34. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  35. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  36. *
  37. * @category HTML
  38. * @package HTML_QuickForm2
  39. * @author Alexey Borzov <avb@php.net>
  40. * @author Bertrand Mansion <golgote@mamasam.com>
  41. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  42. * @version SVN: $Id: Callback.php 325755 2012-05-19 16:13:21Z mansion $
  43. * @link http://pear.php.net/package/HTML_QuickForm2
  44. */
  45. /**
  46. * Abstract base class for QuickForm2 renderers
  47. */
  48. require_once 'HTML/QuickForm2/Renderer.php';
  49. /**
  50. * Callback renderer for QuickForm2
  51. *
  52. * This renderer uses PHP callbacks to render form elements
  53. *
  54. * While almost everything in this class is defined as public, its properties
  55. * and those methods that are not published (i.e. not in array returned by
  56. * exportMethods()) will be available to renderer plugins only.
  57. *
  58. * The following methods are published:
  59. * - {@link setCallbackForClass()}
  60. * - {@link setCallbackForId()}
  61. * - {@link setErrorGroupCallback()}
  62. * - {@link setElementCallbackForGroupClass()}
  63. * - {@link setElementCallbackForGroupId()}
  64. * - {@link setHiddenGroupCallback()}
  65. * - {@link setRequiredNoteCallback()}
  66. * - {@link setLabelCallback()}
  67. *
  68. * Using a callback to render a Submit button and a Cancel link:
  69. * <code>
  70. * function renderSubmitCancel($renderer, $submit) {
  71. * $data = $submit->getData();
  72. * $url = !empty($data['cancel']) ? $data['cancel'] : '/';
  73. * return '<div>'.$submit.' or <a href="'.$url.'">Cancel</a></div>';
  74. * }
  75. * $renderer = HTML_QuickForm2_Renderer::factory('callback');
  76. * $renderer->setCallbackForId($submit->getId(), 'renderSubmitCancel');
  77. * </code>
  78. *
  79. * @category HTML
  80. * @package HTML_QuickForm2
  81. * @author Alexey Borzov <avb@php.net>
  82. * @author Bertrand Mansion <golgote@mamasam.com>
  83. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  84. * @version Release: 2.0.0
  85. * @link http://pear.php.net/package/HTML_QuickForm2
  86. */
  87. class HTML_QuickForm2_Renderer_Callback extends HTML_QuickForm2_Renderer
  88. {
  89. /**
  90. * Whether the form contains required elements
  91. * @var bool
  92. */
  93. public $hasRequired = false;
  94. /**
  95. * HTML generated for the form
  96. * @var array
  97. */
  98. public $html = array(array());
  99. /**
  100. * HTML for hidden elements if 'group_hiddens' option is on
  101. * @var string
  102. */
  103. public $hiddenHtml = '';
  104. /**
  105. * HTML for hidden elements if 'group_hiddens' option is on
  106. * @var string
  107. */
  108. public $hidden = array();
  109. /**
  110. * Array of validation errors if 'group_errors' option is on
  111. * @var array
  112. */
  113. public $errors = array();
  114. /**
  115. * Callback used to render errors if 'group_errors' is on
  116. * @var mixed
  117. */
  118. public $errorGroupCallback = array('HTML_QuickForm2_Renderer_Callback', '_renderErrorsGroup');
  119. /**
  120. * Callback used to render hidden elements
  121. * @var mixed
  122. */
  123. public $hiddenGroupCallback = array('HTML_QuickForm2_Renderer_Callback', '_renderHiddenGroup');
  124. /**
  125. * Callback used to render required note
  126. * @var mixed
  127. */
  128. public $requiredNoteCallback = array('HTML_QuickForm2_Renderer_Callback', '_renderRequiredNote');
  129. /**
  130. * Callback used to render labels
  131. * @var mixed
  132. */
  133. public $labelCallback = array('HTML_QuickForm2_Renderer_Callback', '_renderLabel');
  134. /**
  135. * Array of callbacks defined using an element or container ID
  136. * @var array
  137. */
  138. public $callbacksForId = array();
  139. /**
  140. * Array of callbacks defined using an element class
  141. * @var array
  142. */
  143. public $callbacksForClass = array(
  144. 'html_quickform2' => array('HTML_QuickForm2_Renderer_Callback', '_renderForm'),
  145. 'html_quickform2_element' => array('HTML_QuickForm2_Renderer_Callback', '_renderElement'),
  146. 'html_quickform2_element_inputhidden' => array('HTML_QuickForm2_Renderer_Callback', '_renderHidden'),
  147. 'html_quickform2_container' => array('HTML_QuickForm2_Renderer_Callback', '_renderContainer'),
  148. 'html_quickform2_container_group' => array('HTML_QuickForm2_Renderer_Callback', '_renderGroup'),
  149. 'html_quickform2_container_fieldset' => array('HTML_QuickForm2_Renderer_Callback', '_renderFieldset'),
  150. 'html_quickform2_container_repeat' => array('HTML_QuickForm2_Renderer_Callback', '_renderRepeat')
  151. );
  152. /**
  153. * Array of callbacks defined using a group ID
  154. * @var array
  155. */
  156. public $elementCallbacksForGroupId = array();
  157. /**
  158. * Array of callbacks defined using a group class
  159. * @var array
  160. */
  161. public $elementCallbacksForGroupClass = array(
  162. 'html_quickform2_container' => array(
  163. 'html_quickform2_element' => array('HTML_QuickForm2_Renderer_Callback', '_renderGroupedElement')
  164. )
  165. );
  166. /**
  167. * Array containing IDs of the groups being rendered
  168. * @var array
  169. */
  170. public $groupId = array();
  171. protected function exportMethods()
  172. {
  173. return array(
  174. 'setCallbackForClass',
  175. 'setCallbackForId',
  176. 'setErrorGroupCallback',
  177. 'setElementCallbackForGroupClass',
  178. 'setElementCallbackForGroupId',
  179. 'setHiddenGroupCallback',
  180. 'setRequiredNoteCallback',
  181. 'setLabelCallback'
  182. );
  183. }
  184. public static function _renderForm(
  185. HTML_QuickForm2_Renderer $renderer, HTML_QuickForm2 $form
  186. ) {
  187. $break = HTML_Common2::getOption('linebreak');
  188. $html[] = '<div class="quickform">' .
  189. call_user_func($renderer->errorGroupCallback, $renderer, $form) .
  190. '<form'.$form->getAttributes(true).'><div>' .
  191. call_user_func($renderer->hiddenGroupCallback, $renderer, $form);
  192. $html[] = implode($break, array_pop($renderer->html));
  193. $html[] = '</div></form>';
  194. $html[] = call_user_func($renderer->requiredNoteCallback, $renderer, $form);
  195. $script = $renderer->getJavascriptBuilder()->getFormJavascript($form->getId());
  196. if (!empty($script)) {
  197. $html[] = $script;
  198. }
  199. $html[] = '</div>';
  200. return implode($break, $html) . $break;
  201. }
  202. public static function _renderElement(
  203. HTML_QuickForm2_Renderer $renderer, HTML_QuickForm2_Element $element
  204. ) {
  205. $html[] = '<div class="row">';
  206. $html[] = $renderer->renderLabel($element);
  207. $error = $element->getError();
  208. if ($error) {
  209. $html[] = '<div class="element error">';
  210. if ($renderer->getOption('group_errors')) {
  211. $renderer->errors[] = $error;
  212. } else {
  213. $html[] = '<span class="error">'.$error.'</span><br />';
  214. }
  215. } else {
  216. $html[] = '<div class="element">';
  217. }
  218. $html[] = $element->__toString();
  219. $html[] = '</div>';
  220. $html[] = '</div>';
  221. return implode("", $html);
  222. }
  223. public static function _renderGroupedElement(
  224. HTML_QuickForm2_Renderer $renderer, HTML_QuickForm2_Element $element
  225. ) {
  226. return $element->__toString();
  227. }
  228. public static function _renderErrorsGroup(
  229. HTML_QuickForm2_Renderer $renderer, HTML_QuickForm2 $form
  230. ) {
  231. $html = array();
  232. if (!empty($renderer->errors)) {
  233. $html[] = '<div class="errors">';
  234. if (($prefix = $renderer->getOption('errors_prefix'))
  235. && !empty($prefix)
  236. ) {
  237. $html[] = '<p>' . $prefix . '</p>';
  238. }
  239. $html[] = '<ul>';
  240. foreach ($renderer->errors as $error) {
  241. $html[] = '<li>' . $error . '</li>';
  242. }
  243. $html[] = '</ul>';
  244. if (($suffix = $renderer->getOption('errors_suffix'))
  245. && !empty($suffix)
  246. ) {
  247. $html[] = '<p>' . $suffix . '</p>';
  248. }
  249. $html[] = '</div>';
  250. }
  251. return implode("", $html);
  252. }
  253. public static function _renderHidden(
  254. HTML_QuickForm2_Renderer $renderer,
  255. HTML_QuickForm2_Element_InputHidden $hidden
  256. ) {
  257. return '<div style="display: none;">'.$hidden->__toString().'</div>';
  258. }
  259. public static function _renderHiddenGroup(
  260. HTML_QuickForm2_Renderer $renderer, HTML_QuickForm2 $form
  261. ) {
  262. if (empty($renderer->hidden)) {
  263. return '';
  264. }
  265. $html = array();
  266. foreach ($renderer->hidden as $hidden) {
  267. $html[] = $hidden->__toString();
  268. }
  269. return '<div style="display: none;">'.implode('', $html).'</div>';
  270. }
  271. public static function _renderRequiredNote(
  272. HTML_QuickForm2_Renderer $renderer, HTML_QuickForm2 $form
  273. ) {
  274. if ($renderer->hasRequired && !$form->toggleFrozen(null)) {
  275. if (($note = $renderer->getOption('required_note')) && !empty($note)) {
  276. return '<div class="reqnote">'.$note.'</div>';
  277. }
  278. }
  279. }
  280. public static function _renderContainer(
  281. HTML_QuickForm2_Renderer $renderer, HTML_QuickForm2_Container $container
  282. ) {
  283. $break = HTML_Common2::getOption('linebreak');
  284. return implode($break, array_pop($renderer->html));
  285. }
  286. public static function _renderGroup(
  287. HTML_QuickForm2_Renderer $renderer, HTML_QuickForm2_Container_Group $group
  288. ) {
  289. $break = HTML_Common2::getOption('linebreak');
  290. $class = $group->getAttribute('class');
  291. $html[] = '<div class="row'.(!empty($class) ? ' '.$class : '').'">';
  292. $html[] = $renderer->renderLabel($group);
  293. $error = $group->getError();
  294. if ($error) {
  295. $html[] = '<div class="element group error" id="'.$group->getId().'">';
  296. if ($renderer->getOption('group_errors')) {
  297. $renderer->errors[] = $error;
  298. } else {
  299. $html[] = '<span class="error">'.$error.'</span><br />';
  300. }
  301. } else {
  302. $html[] = '<div class="element group" id="'.$group->getId().'">';
  303. }
  304. $separator = $group->getSeparator();
  305. $elements = array_pop($renderer->html);
  306. if (!is_array($separator)) {
  307. $content = implode((string)$separator, $elements);
  308. } else {
  309. $content = '';
  310. $cSeparator = count($separator);
  311. for ($i = 0, $count = count($elements); $i < $count; $i++) {
  312. $content .= (0 == $i? '': $separator[($i - 1) % $cSeparator]) .
  313. $elements[$i];
  314. }
  315. }
  316. $html[] = $content;
  317. $html[] = '</div>';
  318. $html[] = '</div>';
  319. return implode($break, $html) . $break;
  320. }
  321. public static function _renderRepeat(
  322. HTML_QuickForm2_Renderer $renderer,
  323. HTML_QuickForm2_Container_Repeat $repeat
  324. ) {
  325. $break = HTML_Common2::getOption('linebreak');
  326. $html[] = '<div class="row repeat" id="'.$repeat->getId().'">';
  327. $label = $repeat->getLabel();
  328. if (!is_array($label)) {
  329. $label = array($label);
  330. }
  331. if (!empty($label[0])) {
  332. $html[] = '<p>'.array_shift($label).'</p>';
  333. }
  334. $elements = array_pop($renderer->html);
  335. $content = implode($break, $elements);
  336. $html[] = $content;
  337. $html[] = '</div>';
  338. return implode($break, $html) . $break;
  339. }
  340. public static function _renderFieldset(
  341. HTML_QuickForm2_Renderer $renderer,
  342. HTML_QuickForm2_Container_Fieldset $fieldset
  343. ) {
  344. $break = HTML_Common2::getOption('linebreak');
  345. $html[] = '<fieldset'.$fieldset->getAttributes(true).'>';
  346. $label = $fieldset->getLabel();
  347. if (!empty($label)) {
  348. $html[] = sprintf(
  349. '<legend id="%s-legend">%s</legend>',
  350. $fieldset->getId(), $label
  351. );
  352. }
  353. $elements = array_pop($renderer->html);
  354. $html[] = implode($break, $elements);
  355. $html[] = '</fieldset>';
  356. return implode($break, $html) . $break;
  357. }
  358. public static function _renderLabel(
  359. HTML_QuickForm2_Renderer $renderer, HTML_QuickForm2_Node $node
  360. ) {
  361. $html = array();
  362. $label = $node->getLabel();
  363. if (!is_array($label)) {
  364. $label = array($label);
  365. }
  366. if ($node->isRequired()) {
  367. $renderer->hasRequired = true;
  368. }
  369. $html[] = '<p class="label">';
  370. if (!empty($label[0])) {
  371. if ($node->isRequired()) {
  372. $html[] = '<span class="required">*</span>';
  373. }
  374. if ($node instanceof HTML_QuickForm2_Container) {
  375. $html[] = '<label>';
  376. } else {
  377. $html[] = '<label for="'.$node->getId().'">';
  378. }
  379. $html[] = array_shift($label);
  380. $html[] = '</label>';
  381. }
  382. $html[] = '</p>';
  383. return implode('', $html);
  384. }
  385. /**
  386. * Renders a generic element
  387. *
  388. * @param HTML_QuickForm2_Node $element Element being rendered
  389. */
  390. public function renderElement(HTML_QuickForm2_Node $element)
  391. {
  392. $default = $this->callbacksForClass['html_quickform2_element'];
  393. $callback = $this->findCallback($element, $default);
  394. $res = call_user_func_array($callback, array($this, $element));
  395. $this->html[count($this->html) - 1][] = $res;
  396. }
  397. /**
  398. * Renders an element label
  399. *
  400. * @param HTML_QuickForm2_Node $element Element being rendered
  401. *
  402. * @return string
  403. */
  404. public function renderLabel(HTML_QuickForm2_Node $element)
  405. {
  406. return call_user_func_array($this->labelCallback, array($this, $element));
  407. }
  408. /**
  409. * Renders a hidden element
  410. *
  411. * @param HTML_QuickForm2_Node $element Hidden element being rendered
  412. */
  413. public function renderHidden(HTML_QuickForm2_Node $element)
  414. {
  415. if ($this->getOption('group_hiddens')) {
  416. $this->hidden[] = $element;
  417. } else {
  418. $default = $this->callbacksForClass['html_quickform2_element_inputhidden'];
  419. $callback = $this->findCallback($element, $default);
  420. $this->html[count($this->html) - 1][] = call_user_func_array(
  421. $callback, array($this, $element)
  422. );
  423. }
  424. }
  425. /**
  426. * Starts rendering a generic container, called before processing contained elements
  427. *
  428. * @param HTML_QuickForm2_Node $container Container being rendered
  429. */
  430. public function startContainer(HTML_QuickForm2_Node $container)
  431. {
  432. $this->html[] = array();
  433. $this->groupId[] = false;
  434. }
  435. /**
  436. * Finishes rendering a generic container, called after processing contained elements
  437. *
  438. * @param HTML_QuickForm2_Node $container Container being rendered
  439. */
  440. public function finishContainer(HTML_QuickForm2_Node $container)
  441. {
  442. array_pop($this->groupId);
  443. $default = $this->callbacksForClass['html_quickform2_container'];
  444. $callback = $this->findCallback($container, $default);
  445. $res = call_user_func_array($callback, array($this, $container));
  446. $this->html[count($this->html) - 1][] = $res;
  447. }
  448. /**
  449. * Starts rendering a group, called before processing grouped elements
  450. *
  451. * @param HTML_QuickForm2_Node $group Group being rendered
  452. */
  453. public function startGroup(HTML_QuickForm2_Node $group)
  454. {
  455. $this->html[] = array();
  456. $this->groupId[] = $group->getId();
  457. }
  458. /**
  459. * Finishes rendering a group, called after processing grouped elements
  460. *
  461. * @param HTML_QuickForm2_Node $group Group being rendered
  462. */
  463. public function finishGroup(HTML_QuickForm2_Node $group)
  464. {
  465. array_pop($this->groupId);
  466. $default = $this->callbacksForClass['html_quickform2_container_group'];
  467. $callback = $this->findCallback($group, $default);
  468. $res = call_user_func_array($callback, array($this, $group));
  469. $this->html[count($this->html) - 1][] = $res;
  470. }
  471. /**
  472. * Starts rendering a form, called before processing contained elements
  473. *
  474. * @param HTML_QuickForm2_Node $form Form being rendered
  475. */
  476. public function startForm(HTML_QuickForm2_Node $form)
  477. {
  478. $this->reset();
  479. }
  480. /**
  481. * Finishes rendering a form, called after processing contained elements
  482. *
  483. * @param HTML_QuickForm2_Node $form Form being rendered
  484. */
  485. public function finishForm(HTML_QuickForm2_Node $form)
  486. {
  487. $default = $this->callbacksForClass['html_quickform2'];
  488. $callback = $this->findCallback($form, $default);
  489. $this->html[0] = array(
  490. call_user_func_array($callback, array($this, $form))
  491. );
  492. }
  493. private function _validateCallback($callback)
  494. {
  495. if (is_callable($callback) || is_null($callback)) {
  496. return true;
  497. }
  498. throw new HTML_QuickForm2_InvalidArgumentException(
  499. "Renderer callback is invalid"
  500. );
  501. }
  502. /**
  503. * Sets callback for rendering labels
  504. *
  505. * @param callback|null $callback PHP callback
  506. *
  507. * @return HTML_QuickForm2_Renderer_Callback
  508. */
  509. public function setLabelCallback($callback)
  510. {
  511. if ($this->_validateCallback($callback)) {
  512. $this->labelCallback = $callback;
  513. }
  514. return $this;
  515. }
  516. /**
  517. * Sets callback for rendering hidden elements if option group_hiddens is true
  518. *
  519. * @param callback|null $callback PHP callback
  520. *
  521. * @return HTML_QuickForm2_Renderer_Callback
  522. */
  523. public function setHiddenGroupCallback($callback)
  524. {
  525. if ($this->_validateCallback($callback)) {
  526. $this->hiddenGroupCallback = $callback;
  527. }
  528. return $this;
  529. }
  530. /**
  531. * Sets callback for rendering required note
  532. *
  533. * @param callback|null $callback PHP callback
  534. *
  535. * @return HTML_QuickForm2_Renderer_Callback
  536. */
  537. public function setRequiredNoteCallback($callback)
  538. {
  539. if ($this->_validateCallback($callback)) {
  540. $this->requiredNoteCallback = $callback;
  541. }
  542. return $this;
  543. }
  544. /**
  545. * Sets callback for form elements that are instances of the given class
  546. *
  547. * When searching for a callback to use, renderer will check for callbacks
  548. * set for element's class and its parent classes, until found. Thus a more
  549. * specific callbacks will override a more generic one.
  550. *
  551. * @param string $className Class name
  552. * @param callback|null $callback Callback to use for elements of that class
  553. *
  554. * @return HTML_QuickForm2_Renderer_Callback
  555. */
  556. public function setCallbackForClass($className, $callback)
  557. {
  558. if ($this->_validateCallback($callback)) {
  559. $this->callbacksForClass[strtolower($className)] = $callback;
  560. }
  561. return $this;
  562. }
  563. /**
  564. * Sets callback for form element with the given id
  565. *
  566. * If a callback is set for an element via this method, it will be used.
  567. * In the other case a generic callback set by {@link setCallbackForClass()}
  568. * or {@link setElementCallbackForGroupClass()} will be used.
  569. *
  570. * @param string $id Element's id
  571. * @param callback|null $callback Callback to use for rendering of that element
  572. *
  573. * @return HTML_QuickForm2_Renderer_Callback
  574. */
  575. public function setCallbackForId($id, $callback)
  576. {
  577. if ($this->_validateCallback($callback)) {
  578. $this->callbacksForId[$id] = $callback;
  579. }
  580. return $this;
  581. }
  582. /**
  583. * Sets callback for rendering validation errors
  584. *
  585. * This callback will be used if 'group_errors' option is set to true.
  586. *
  587. * @param callback|null $callback Callback for validation errors
  588. *
  589. * @return HTML_QuickForm2_Renderer_Callback
  590. */
  591. public function setErrorGroupCallback($callback)
  592. {
  593. if ($this->_validateCallback($callback)) {
  594. $this->errorGroupCallback = $callback;
  595. }
  596. return $this;
  597. }
  598. /**
  599. * Sets grouped elements callbacks using group class
  600. *
  601. * Callbacks set via {@link setCallbackForClass()} will not be used for
  602. * grouped form elements. When searching for a callback to use, the renderer
  603. * will first consider callback set for a specific group id, then the
  604. * group callback set by group class.
  605. *
  606. * @param string $groupClass Group class name
  607. * @param string $elementClass Element class name
  608. * @param callback|null $callback Callback
  609. *
  610. * @return HTML_QuickForm2_Renderer_Callback
  611. */
  612. public function setElementCallbackForGroupClass($groupClass, $elementClass, $callback)
  613. {
  614. if ($this->_validateCallback($callback)) {
  615. $this->elementCallbacksForGroupClass[strtolower($groupClass)][strtolower($elementClass)] = $callback;
  616. }
  617. return $this;
  618. }
  619. /**
  620. * Sets grouped elements callback using group id
  621. *
  622. * Callbacks set via {@link setCallbackForClass()} will not be used for
  623. * grouped form elements. When searching for a callback to use, the renderer
  624. * will first consider callback set for a specific group id, then the
  625. * group callbacks set by group class.
  626. *
  627. * @param string $groupId Group id
  628. * @param string $elementClass Element class name
  629. * @param callback|null $callback Callback
  630. *
  631. * @return HTML_QuickForm2_Renderer_Callback
  632. */
  633. public function setElementCallbackForGroupId($groupId, $elementClass, $callback)
  634. {
  635. if ($this->_validateCallback($callback)) {
  636. $this->elementCallbacksForGroupId[$groupId][strtolower($elementClass)] = $callback;
  637. }
  638. return $this;
  639. }
  640. /**
  641. * Resets the accumulated data
  642. *
  643. * This method is called automatically by startForm() method, but should
  644. * be called manually before calling other rendering methods separately.
  645. *
  646. * @return HTML_QuickForm2_Renderer_Callback
  647. */
  648. public function reset()
  649. {
  650. $this->html = array(array());
  651. $this->hiddenHtml = '';
  652. $this->errors = array();
  653. $this->hidden = array();
  654. $this->hasRequired = false;
  655. $this->groupId = array();
  656. return $this;
  657. }
  658. /**
  659. * Returns generated HTML
  660. *
  661. * @return string
  662. */
  663. public function __toString()
  664. {
  665. return (isset($this->html[0][0])? $this->html[0][0]: '');
  666. }
  667. /**
  668. * Finds a proper callback for the element
  669. *
  670. * Callbacks are scanned in a predefined order. First, if a callback was
  671. * set for a specific element by id, it is returned, no matter if the
  672. * element belongs to a group. If the element does not belong to a group,
  673. * we try to match a callback using the element class.
  674. * But, if the element belongs to a group, callbacks are first looked up
  675. * using the containing group id, then using the containing group class.
  676. * When no callback is found, the provided default callback is returned.
  677. *
  678. * @param HTML_QuickForm2_Node $element Element being rendered
  679. * @param callback|null $default Default callback to use if not found
  680. *
  681. * @return callback|null
  682. */
  683. public function findCallback(HTML_QuickForm2_Node $element, $default = null)
  684. {
  685. if (!empty($this->callbacksForId[$element->getId()])) {
  686. return $this->callbacksForId[$element->getId()];
  687. }
  688. $class = strtolower(get_class($element));
  689. $groupId = end($this->groupId);
  690. $elementClasses = array();
  691. do {
  692. if (empty($groupId) && !empty($this->callbacksForClass[$class])) {
  693. return $this->callbacksForClass[$class];
  694. }
  695. $elementClasses[$class] = true;
  696. } while ($class = strtolower(get_parent_class($class)));
  697. if (!empty($groupId)) {
  698. if (!empty($this->elementCallbacksForGroupId[$groupId])) {
  699. while (list($elClass) = each($elementClasses)) {
  700. if (!empty($this->elementCallbacksForGroupId[$groupId][$elClass])) {
  701. return $this->elementCallbacksForGroupId[$groupId][$elClass];
  702. }
  703. }
  704. }
  705. $group = $element->getContainer();
  706. $grClass = strtolower(get_class($group));
  707. do {
  708. if (!empty($this->elementCallbacksForGroupClass[$grClass])) {
  709. reset($elementClasses);
  710. while (list($elClass) = each($elementClasses)) {
  711. if (!empty($this->elementCallbacksForGroupClass[$grClass][$elClass])) {
  712. return $this->elementCallbacksForGroupClass[$grClass][$elClass];
  713. }
  714. }
  715. }
  716. } while ($grClass = strtolower(get_parent_class($grClass)));
  717. }
  718. return $default;
  719. }
  720. }
  721. ?>