1<?php
2/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
4/**
5 * A static renderer for HTML_QuickForm compatible
6 * with HTML_Template_IT and HTML_Template_Sigma.
7 *
8 * PHP versions 4 and 5
9 *
10 * LICENSE: This source file is subject to version 3.01 of the PHP license
11 * that is available through the world-wide-web at the following URI:
12 * http://www.php.net/license/3_01.txt If you did not receive a copy of
13 * the PHP License and are unable to obtain it through the web, please
14 * send a note to license@php.net so we can mail you a copy immediately.
15 *
16 * @category    HTML
17 * @package     HTML_QuickForm
18 * @author      Bertrand Mansion <bmansion@mamasam.com>
19 * @copyright   2001-2011 The PHP Group
20 * @license     http://www.php.net/license/3_01.txt PHP License 3.01
21 * @version     CVS: $Id$
22 * @link        http://pear.php.net/package/HTML_QuickForm
23 */
24
25/**
26 * An abstract base class for QuickForm renderers
27 */
28require_once 'HTML/QuickForm/Renderer.php';
29
30/**
31 * A static renderer for HTML_QuickForm compatible
32 * with HTML_Template_IT and HTML_Template_Sigma.
33 *
34 * As opposed to the dynamic renderer, this renderer needs
35 * every elements and labels in the form to be specified by
36 * placeholders at the position you want them to be displayed.
37 *
38 * @category    HTML
39 * @package     HTML_QuickForm
40 * @author      Bertrand Mansion <bmansion@mamasam.com>
41 * @version     Release: 3.2.16
42 * @since       3.0
43 */
44class HTML_QuickForm_Renderer_ITStatic extends HTML_QuickForm_Renderer
45{
46   /**#@+
47    * @access private
48    */
49   /**
50    * An HTML_Template_IT or some other API compatible Template instance
51    * @var object
52    */
53    var $_tpl = null;
54
55   /**
56    * Rendered form name
57    * @var string
58    */
59    var $_formName = 'form';
60
61   /**
62    * The errors that were not shown near concrete fields go here
63    * @var array
64    */
65    var $_errors = array();
66
67   /**
68    * Show the block with required note?
69    * @var bool
70    */
71    var $_showRequired = false;
72
73   /**
74    * Which group are we currently parsing ?
75    * @var string
76    */
77    var $_inGroup;
78
79   /**
80    * Index of the element in its group
81    * @var int
82    */
83    var $_elementIndex = 0;
84
85   /**
86    * If elements have been added with the same name
87    * @var array
88    */
89    var $_duplicateElements = array();
90
91   /**
92    * How to handle the required tag for required fields
93    * @var string
94    */
95    var $_required = '{label}<font size="1" color="red">*</font>';
96
97   /**
98    * How to handle error messages in form validation
99    * @var string
100    */
101    var $_error = '<font color="red">{error}</font><br />{html}';
102
103   /**
104    * Collected HTML for hidden elements, if needed
105    * @var string
106    */
107    var $_hidden = '';
108   /**#@-*/
109
110   /**
111    * Constructor
112    *
113    * @param HTML_Template_IT|HTML_Template_Sigma   Template object to use
114    */
115    function HTML_QuickForm_Renderer_ITStatic(&$tpl)
116    {
117        $this->HTML_QuickForm_Renderer();
118        $this->_tpl =& $tpl;
119    } // end constructor
120
121   /**
122    * Called when visiting a form, before processing any form elements
123    *
124    * @param    HTML_QuickForm  form object being visited
125    * @access   public
126    * @return   void
127    */
128    function startForm(&$form)
129    {
130        $this->_formName = $form->getAttribute('id');
131
132        if (count($form->_duplicateIndex) > 0) {
133            // Take care of duplicate elements
134            foreach ($form->_duplicateIndex as $elementName => $indexes) {
135                $this->_duplicateElements[$elementName] = 0;
136            }
137        }
138    } // end func startForm
139
140   /**
141    * Called when visiting a form, after processing all form elements
142    *
143    * @param    HTML_QuickForm  form object being visited
144    * @access   public
145    * @return   void
146    */
147    function finishForm(&$form)
148    {
149        // display errors above form
150        if (!empty($this->_errors) && $this->_tpl->blockExists($this->_formName.'_error_loop')) {
151            foreach ($this->_errors as $error) {
152                $this->_tpl->setVariable($this->_formName.'_error', $error);
153                $this->_tpl->parse($this->_formName.'_error_loop');
154            }
155        }
156        // show required note
157        if ($this->_showRequired) {
158            $this->_tpl->setVariable($this->_formName.'_required_note', $form->getRequiredNote());
159        }
160        // add hidden elements, if collected
161        if (!empty($this->_hidden)) {
162            $this->_tpl->setVariable($this->_formName . '_hidden', $this->_hidden);
163        }
164        // assign form attributes
165        $this->_tpl->setVariable($this->_formName.'_attributes', $form->getAttributes(true));
166        // assign javascript validation rules
167        $this->_tpl->setVariable($this->_formName.'_javascript', $form->getValidationScript());
168    } // end func finishForm
169
170   /**
171    * Called when visiting a header element
172    *
173    * @param    HTML_QuickForm_header   header element being visited
174    * @access   public
175    * @return   void
176    */
177    function renderHeader(&$header)
178    {
179        $name = $header->getName();
180        $varName = $this->_formName.'_header';
181
182        // Find placeHolder
183        if (!empty($name) && $this->_tpl->placeHolderExists($this->_formName.'_header_'.$name)) {
184            $varName = $this->_formName.'_header_'.$name;
185        }
186        $this->_tpl->setVariable($varName, $header->toHtml());
187    } // end func renderHeader
188
189   /**
190    * Called when visiting an element
191    *
192    * @param    HTML_QuickForm_element  form element being visited
193    * @param    bool                    Whether an element is required
194    * @param    string                  An error message associated with an element
195    * @access   public
196    * @return   void
197    */
198    function renderElement(&$element, $required, $error)
199    {
200        $name = $element->getName();
201
202        // are we inside a group?
203        if (!empty($this->_inGroup)) {
204            $varName = $this->_formName.'_'.str_replace(array('[', ']'), '_', $name);
205            if (substr($varName, -2) == '__') {
206                // element name is of type : group[]
207                $varName = $this->_inGroup.'_'.$this->_elementIndex.'_';
208                $this->_elementIndex++;
209            }
210            if ($varName != $this->_inGroup) {
211                $varName .= '_' == substr($varName, -1)? '': '_';
212                // element name is of type : group[name]
213                $label = $element->getLabel();
214                $html = $element->toHtml();
215
216                if ($required && !$element->isFrozen()) {
217                    $this->_renderRequired($label, $html);
218                    $this->_showRequired = true;
219                }
220                if (!empty($label)) {
221                    if (is_array($label)) {
222                        foreach ($label as $key => $value) {
223                            $this->_tpl->setVariable($varName.'label_'.$key, $value);
224                        }
225                    } else {
226                        $this->_tpl->setVariable($varName.'label', $label);
227                    }
228                }
229                $this->_tpl->setVariable($varName.'html', $html);
230            }
231
232        } else {
233
234            $name = str_replace(array('[', ']'), array('_', ''), $name);
235
236            if (isset($this->_duplicateElements[$name])) {
237                // Element is a duplicate
238                $varName = $this->_formName.'_'.$name.'_'.$this->_duplicateElements[$name];
239                $this->_duplicateElements[$name]++;
240            } else {
241                $varName = $this->_formName.'_'.$name;
242            }
243
244            $label = $element->getLabel();
245            $html = $element->toHtml();
246
247            if ($required) {
248                $this->_showRequired = true;
249                $this->_renderRequired($label, $html);
250            }
251            if (!empty($error)) {
252                $this->_renderError($label, $html, $error);
253            }
254            if (is_array($label)) {
255                foreach ($label as $key => $value) {
256                    $this->_tpl->setVariable($varName.'_label_'.$key, $value);
257                }
258            } else {
259                $this->_tpl->setVariable($varName.'_label', $label);
260            }
261            $this->_tpl->setVariable($varName.'_html', $html);
262        }
263    } // end func renderElement
264
265   /**
266    * Called when visiting a hidden element
267    *
268    * @param    HTML_QuickForm_element  hidden element being visited
269    * @access   public
270    * @return   void
271    */
272    function renderHidden(&$element)
273    {
274        if ($this->_tpl->placeholderExists($this->_formName . '_hidden')) {
275            $this->_hidden .= $element->toHtml();
276        } else {
277            $name = $element->getName();
278            $name = str_replace(array('[', ']'), array('_', ''), $name);
279            $this->_tpl->setVariable($this->_formName.'_'.$name.'_html', $element->toHtml());
280        }
281    } // end func renderHidden
282
283   /**
284    * Called when visiting a group, before processing any group elements
285    *
286    * @param    HTML_QuickForm_group    group being visited
287    * @param    bool                    Whether a group is required
288    * @param    string                  An error message associated with a group
289    * @access   public
290    * @return   void
291    */
292    function startGroup(&$group, $required, $error)
293    {
294        $name = $group->getName();
295        $varName = $this->_formName.'_'.$name;
296
297        $this->_elementIndex = 0;
298
299        $html = $this->_tpl->placeholderExists($varName.'_html') ? $group->toHtml() : '';
300        $label = $group->getLabel();
301
302        if ($required) {
303            $this->_renderRequired($label, $html);
304        }
305        if (!empty($error)) {
306            $this->_renderError($label, $html, $error);
307        }
308        if (!empty($html)) {
309            $this->_tpl->setVariable($varName.'_html', $html);
310        } else {
311            // Uses error blocks to set the special groups layout error
312            // <!-- BEGIN form_group_error -->{form_group_error}<!-- END form_group_error -->
313            if (!empty($error)) {
314                if ($this->_tpl->placeholderExists($varName.'_error')) {
315                    if ($this->_tpl->blockExists($this->_formName . '_error_block')) {
316                        $this->_tpl->setVariable($this->_formName . '_error', $error);
317                        $error = $this->_getTplBlock($this->_formName . '_error_block');
318                    } elseif (strpos($this->_error, '{html}') !== false || strpos($this->_error, '{label}') !== false) {
319                        $error = str_replace('{error}', $error, $this->_error);
320                    }
321                }
322                $this->_tpl->setVariable($varName . '_error', $error);
323                array_pop($this->_errors);
324            }
325        }
326        if (is_array($label)) {
327            foreach ($label as $key => $value) {
328                $this->_tpl->setVariable($varName.'_label_'.$key, $value);
329            }
330        } else {
331            $this->_tpl->setVariable($varName.'_label', $label);
332        }
333        $this->_inGroup = $varName;
334    } // end func startGroup
335
336   /**
337    * Called when visiting a group, after processing all group elements
338    *
339    * @param    HTML_QuickForm_group    group being visited
340    * @access   public
341    * @return   void
342    */
343    function finishGroup(&$group)
344    {
345        $this->_inGroup = '';
346    } // end func finishGroup
347
348   /**
349    * Sets the way required elements are rendered
350    *
351    * You can use {label} or {html} placeholders to let the renderer know where
352    * where the element label or the element html are positionned according to the
353    * required tag. They will be replaced accordingly with the right value.
354    * For example:
355    * <font color="red">*</font>{label}
356    * will put a red star in front of the label if the element is required.
357    *
358    * @param    string      The required element template
359    * @access   public
360    * @return   void
361    */
362    function setRequiredTemplate($template)
363    {
364        $this->_required = $template;
365    } // end func setRequiredTemplate
366
367   /**
368    * Sets the way elements with validation errors are rendered
369    *
370    * You can use {label} or {html} placeholders to let the renderer know where
371    * where the element label or the element html are positionned according to the
372    * error message. They will be replaced accordingly with the right value.
373    * The error message will replace the {error} place holder.
374    * For example:
375    * <font color="red">{error}</font><br />{html}
376    * will put the error message in red on top of the element html.
377    *
378    * If you want all error messages to be output in the main error block, do not specify
379    * {html} nor {label}.
380    *
381    * Groups can have special layouts. With this kind of groups, the renderer will need
382    * to know where to place the error message. In this case, use error blocks like:
383    * <!-- BEGIN form_group_error -->{form_group_error}<!-- END form_group_error -->
384    * where you want the error message to appear in the form.
385    *
386    * @param    string      The element error template
387    * @access   public
388    * @return   void
389    */
390    function setErrorTemplate($template)
391    {
392        $this->_error = $template;
393    } // end func setErrorTemplate
394
395   /**
396    * Called when an element is required
397    *
398    * This method will add the required tag to the element label and/or the element html
399    * such as defined with the method setRequiredTemplate
400    *
401    * @param    string      The element label
402    * @param    string      The element html rendering
403    * @see      setRequiredTemplate()
404    * @access   private
405    * @return   void
406    */
407    function _renderRequired(&$label, &$html)
408    {
409        if ($this->_tpl->blockExists($tplBlock = $this->_formName . '_required_block')) {
410            if (!empty($label) && $this->_tpl->placeholderExists($this->_formName . '_label', $tplBlock)) {
411                $this->_tpl->setVariable($this->_formName . '_label', is_array($label)? $label[0]: $label);
412                if (is_array($label)) {
413                    $label[0] = $this->_getTplBlock($tplBlock);
414                } else {
415                    $label    = $this->_getTplBlock($tplBlock);
416                }
417            }
418            if (!empty($html) && $this->_tpl->placeholderExists($this->_formName . '_html', $tplBlock)) {
419                $this->_tpl->setVariable($this->_formName . '_html', $html);
420                $html = $this->_getTplBlock($tplBlock);
421            }
422        } else {
423            if (!empty($label) && strpos($this->_required, '{label}') !== false) {
424                if (is_array($label)) {
425                    $label[0] = str_replace('{label}', $label[0], $this->_required);
426                } else {
427                    $label = str_replace('{label}', $label, $this->_required);
428                }
429            }
430            if (!empty($html) && strpos($this->_required, '{html}') !== false) {
431                $html = str_replace('{html}', $html, $this->_required);
432            }
433        }
434    } // end func _renderRequired
435
436   /**
437    * Called when an element has a validation error
438    *
439    * This method will add the error message to the element label or the element html
440    * such as defined with the method setErrorTemplate. If the error placeholder is not found
441    * in the template, the error will be displayed in the form error block.
442    *
443    * @param    string      The element label
444    * @param    string      The element html rendering
445    * @param    string      The element error
446    * @see      setErrorTemplate()
447    * @access   private
448    * @return   void
449    */
450    function _renderError(&$label, &$html, $error)
451    {
452        if ($this->_tpl->blockExists($tplBlock = $this->_formName . '_error_block')) {
453            $this->_tpl->setVariable($this->_formName . '_error', $error);
454            if (!empty($label) && $this->_tpl->placeholderExists($this->_formName . '_label', $tplBlock)) {
455                $this->_tpl->setVariable($this->_formName . '_label', is_array($label)? $label[0]: $label);
456                if (is_array($label)) {
457                    $label[0] = $this->_getTplBlock($tplBlock);
458                } else {
459                    $label    = $this->_getTplBlock($tplBlock);
460                }
461            } elseif (!empty($html) && $this->_tpl->placeholderExists($this->_formName . '_html', $tplBlock)) {
462                $this->_tpl->setVariable($this->_formName . '_html', $html);
463                $html = $this->_getTplBlock($tplBlock);
464            }
465            // clean up after ourselves
466            $this->_tpl->setVariable($this->_formName . '_error', null);
467        } elseif (!empty($label) && strpos($this->_error, '{label}') !== false) {
468            if (is_array($label)) {
469                $label[0] = str_replace(array('{label}', '{error}'), array($label[0], $error), $this->_error);
470            } else {
471                $label = str_replace(array('{label}', '{error}'), array($label, $error), $this->_error);
472            }
473        } elseif (!empty($html) && strpos($this->_error, '{html}') !== false) {
474            $html = str_replace(array('{html}', '{error}'), array($html, $error), $this->_error);
475        } else {
476            $this->_errors[] = $error;
477        }
478    }// end func _renderError
479
480
481   /**
482    * Returns the block's contents
483    *
484    * The method is needed because ITX and Sigma implement clearing
485    * the block contents on get() a bit differently
486    *
487    * @param    string  Block name
488    * @return   string  Block contents
489    */
490    function _getTplBlock($block)
491    {
492        $this->_tpl->parse($block);
493        if (is_a($this->_tpl, 'html_template_sigma')) {
494            $ret = $this->_tpl->get($block, true);
495        } else {
496            $oldClear = $this->_tpl->clearCache;
497            $this->_tpl->clearCache = true;
498            $ret = $this->_tpl->get($block);
499            $this->_tpl->clearCache = $oldClear;
500        }
501        return $ret;
502    }
503} // end class HTML_QuickForm_Renderer_ITStatic
504?>