Configure the dmca form site on ridley
[chef.git] / cookbooks / dmca / files / default / html / HTML / QuickForm / Renderer / ArraySmarty.php
1 <?php
2 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
4 /**
5  * A static renderer for HTML_QuickForm, makes an array of form content
6  * useful for a Smarty template
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      Alexey Borzov <avb@php.net>
19  * @author      Bertrand Mansion <bmansion@mamasam.com>
20  * @author      Thomas Schulz <ths@4bconsult.de>
21  * @copyright   2001-2011 The PHP Group
22  * @license     http://www.php.net/license/3_01.txt PHP License 3.01
23  * @version     CVS: $Id$
24  * @link        http://pear.php.net/package/HTML_QuickForm
25  */
26
27 /**
28  * A concrete renderer for HTML_QuickForm, makes an array of form contents
29  */ 
30 require_once 'HTML/QuickForm/Renderer/Array.php';
31
32 /**
33  * A static renderer for HTML_QuickForm, makes an array of form content
34  * useful for a Smarty template
35  *
36  * Based on old HTML_QuickForm::toArray() code and ITStatic renderer.
37  *
38  * The form array structure is the following:
39  * <pre>
40  * Array (
41  *  [frozen]       => whether the complete form is frozen'
42  *  [javascript]   => javascript for client-side validation
43  *  [attributes]   => attributes for <form> tag
44  *  [hidden]       => html of all hidden elements
45  *  [requirednote] => note about the required elements
46  *  [errors] => Array
47  *      (
48  *          [1st_element_name] => Error for the 1st element
49  *          ...
50  *          [nth_element_name] => Error for the nth element
51  *      )
52  *
53  *  [header] => Array
54  *      (
55  *          [1st_header_name] => Header text for the 1st header
56  *          ...
57  *          [nth_header_name] => Header text for the nth header
58  *      )
59  *
60  *  [1st_element_name] => Array for the 1st element
61  *  ...
62  *  [nth_element_name] => Array for the nth element
63  * </pre>
64  *
65  * where an element array has the form:
66  * <pre>
67  *      (
68  *          [name]      => element name
69  *          [value]     => element value,
70  *          [type]      => type of the element
71  *          [frozen]    => whether element is frozen
72  *          [label]     => label for the element
73  *          [required]  => whether element is required
74  * // if element is not a group:
75  *          [html]      => HTML for the element
76  * // if element is a group:
77  *          [separator] => separator for group elements
78  *          [1st_gitem_name] => Array for the 1st element in group
79  *          ...
80  *          [nth_gitem_name] => Array for the nth element in group
81  *      )
82  * )
83  * </pre>
84  *
85  * @category    HTML
86  * @package     HTML_QuickForm
87  * @author      Alexey Borzov <avb@php.net>
88  * @author      Bertrand Mansion <bmansion@mamasam.com>
89  * @author      Thomas Schulz <ths@4bconsult.de>
90  * @version     Release: 3.2.16
91  * @since       3.0
92  */
93 class HTML_QuickForm_Renderer_ArraySmarty extends HTML_QuickForm_Renderer_Array
94 {
95    /**#@+
96     * @access private
97     */
98    /**
99     * The Smarty template engine instance
100     * @var object
101     */
102     var $_tpl = null;
103
104    /**
105     * Current element index
106     * @var integer
107     */
108     var $_elementIdx = 0;
109
110     /**
111     * The current element index inside a group
112     * @var integer
113     */
114     var $_groupElementIdx = 0;
115
116    /**
117     * How to handle the required tag for required fields
118     * @var string
119     * @see      setRequiredTemplate()
120     */
121     var $_required = '';
122
123    /**
124     * How to handle error messages in form validation
125     * @var string
126     * @see      setErrorTemplate()
127     */
128     var $_error = '';
129    /**#@-*/
130
131    /**
132     * Constructor
133     *
134     * @param  Smarty  reference to the Smarty template engine instance
135     * @param  bool    true: render an array of labels to many labels, $key 0 to 'label' and the oterh to "label_$key"
136     * @param  bool    true: collect all hidden elements into string; false: process them as usual form elements
137     * @access public
138     */
139     function HTML_QuickForm_Renderer_ArraySmarty(&$tpl, $staticLabels = false, $collectHidden = true)
140     {
141         $this->HTML_QuickForm_Renderer_Array($collectHidden, $staticLabels);
142         $this->_tpl =& $tpl;
143     } // end constructor
144
145    /**
146     * Called when visiting a header element
147     *
148     * @param    HTML_QuickForm_header   header element being visited
149     * @access   public
150     * @return   void
151     */
152     function renderHeader(&$header)
153     {
154         if ($name = $header->getName()) {
155             $this->_ary['header'][$name] = $header->toHtml();
156         } else {
157             $this->_ary['header'][$this->_sectionCount] = $header->toHtml();
158         }
159         $this->_currentSection = $this->_sectionCount++;
160     } // end func renderHeader
161
162    /**
163     * Called when visiting a group, before processing any group elements
164     *
165     * @param    HTML_QuickForm_group    group being visited
166     * @param    bool                    Whether a group is required
167     * @param    string                  An error message associated with a group
168     * @access   public
169     * @return   void
170     */
171     function startGroup(&$group, $required, $error)
172     {
173         parent::startGroup($group, $required, $error);
174         $this->_groupElementIdx = 1;
175     } // end func startGroup
176
177    /**
178     * Creates an array representing an element containing
179     * the key for storing this
180     *
181     * @access private
182     * @param  HTML_QuickForm_element    form element being visited
183     * @param  bool                      Whether an element is required
184     * @param  string                    Error associated with the element
185     * @return array
186     */
187     function _elementToArray(&$element, $required, $error)
188     {
189         $ret = parent::_elementToArray($element, $required, $error);
190
191         if ('group' == $ret['type']) {
192             $ret['html'] = $element->toHtml();
193             // we don't need the elements, see the array structure
194             unset($ret['elements']);
195         }
196         if (($required || $error) && !empty($this->_required)){
197             $this->_renderRequired($ret['label'], $ret['html'], $required, $error);
198         }
199         if ($error && !empty($this->_error)) {
200             $this->_renderError($ret['label'], $ret['html'], $error);
201             $ret['error'] = $error;
202         }
203         // create keys for elements grouped by native group or name
204         if (strstr($ret['name'], '[') or $this->_currentGroup) {
205             // Fix for bug #8123: escape backslashes and quotes to prevent errors 
206             // in eval(). The code below seems to handle the case where element
207             // name has unbalanced square brackets. Dunno whether we really
208             // need this after the fix for #8123, but I'm wary of making big
209             // changes to this code.  
210             preg_match('/([^]]*)\\[([^]]*)\\]/', $ret['name'], $matches);
211             if (isset($matches[1])) {
212                 $sKeysSub = substr_replace($ret['name'], '', 0, strlen($matches[1]));
213                 $sKeysSub = str_replace(
214                     array('\\',   '\'',   '['  ,   ']', '[\'\']'),
215                     array('\\\\', '\\\'', '[\'', '\']', '[]'    ),
216                     $sKeysSub
217                 );
218                 $sKeys = '[\'' . str_replace(array('\\', '\''), array('\\\\', '\\\''), $matches[1]) . '\']' . $sKeysSub;
219             } else {
220                 $sKeys = '[\'' . str_replace(array('\\', '\''), array('\\\\', '\\\''), $ret['name']) . '\']';
221             }
222             // special handling for elements in native groups
223             if ($this->_currentGroup) {
224                 // skip unnamed group items unless radios: no name -> no static access
225                 // identification: have the same key string as the parent group
226                 if ($this->_currentGroup['keys'] == $sKeys and 'radio' != $ret['type']) {
227                     return false;
228                 }
229                 // reduce string of keys by remove leading group keys
230                 if (0 === strpos($sKeys, $this->_currentGroup['keys'])) {
231                     $sKeys = substr_replace($sKeys, '', 0, strlen($this->_currentGroup['keys']));
232                 }
233             }
234         // element without a name
235         } elseif ($ret['name'] == '') {
236             $sKeys = '[\'element_' . $this->_elementIdx . '\']';
237         // other elements
238         } else {
239             $sKeys = '[\'' . str_replace(array('\\', '\''), array('\\\\', '\\\''), $ret['name']) . '\']';
240         }
241         // for radios: add extra key from value
242         if ('radio' == $ret['type'] and substr($sKeys, -2) != '[]') {
243             $sKeys .= '[\'' . str_replace(array('\\', '\''), array('\\\\', '\\\''), $ret['value']) . '\']';
244         }
245         $this->_elementIdx++;
246         $ret['keys'] = $sKeys;
247         return $ret;
248     } // end func _elementToArray
249
250    /**
251     * Stores an array representation of an element in the form array
252     *
253     * @access private
254     * @param array  Array representation of an element
255     * @return void
256     */
257     function _storeArray($elAry)
258     {
259         if ($elAry) {
260             $sKeys = $elAry['keys'];
261             unset($elAry['keys']);
262             // where should we put this element...
263             if (is_array($this->_currentGroup) && ('group' != $elAry['type'])) {
264                 $toEval = '$this->_currentGroup' . $sKeys . ' = $elAry;';
265             } else {
266                 $toEval = '$this->_ary' . $sKeys . ' = $elAry;';
267             }
268             eval($toEval);
269         }
270         return;
271     }
272
273    /**
274     * Called when an element is required
275     *
276     * This method will add the required tag to the element label and/or the element html
277     * such as defined with the method setRequiredTemplate.
278     *
279     * @param    string      The element label
280     * @param    string      The element html rendering
281     * @param    boolean     The element required
282     * @param    string      The element error
283     * @see      setRequiredTemplate()
284     * @access   private
285     * @return   void
286     */
287     function _renderRequired(&$label, &$html, &$required, &$error)
288     {
289         $this->_tpl->assign(array(
290             'label'    => $label,
291             'html'     => $html,
292             'required' => $required,
293             'error'    => $error
294         ));
295         if (!empty($label) && strpos($this->_required, $this->_tpl->left_delimiter . '$label') !== false) {
296             $label = $this->_tplFetch($this->_required);
297         }
298         if (!empty($html) && strpos($this->_required, $this->_tpl->left_delimiter . '$html') !== false) {
299             $html = $this->_tplFetch($this->_required);
300         }
301         $this->_tpl->clear_assign(array('label', 'html', 'required'));
302     } // end func _renderRequired
303
304    /**
305     * Called when an element has a validation error
306     *
307     * This method will add the error message to the element label or the element html
308     * such as defined with the method setErrorTemplate. If the error placeholder is not found
309     * in the template, the error will be displayed in the form error block.
310     *
311     * @param    string      The element label
312     * @param    string      The element html rendering
313     * @param    string      The element error
314     * @see      setErrorTemplate()
315     * @access   private
316     * @return   void
317     */
318     function _renderError(&$label, &$html, &$error)
319     {
320         $this->_tpl->assign(array('label' => '', 'html' => '', 'error' => $error));
321         $error = $this->_tplFetch($this->_error);
322         $this->_tpl->assign(array('label' => $label, 'html'  => $html));
323
324         if (!empty($label) && strpos($this->_error, $this->_tpl->left_delimiter . '$label') !== false) {
325             $label = $this->_tplFetch($this->_error);
326         } elseif (!empty($html) && strpos($this->_error, $this->_tpl->left_delimiter . '$html') !== false) {
327             $html = $this->_tplFetch($this->_error);
328         }
329         $this->_tpl->clear_assign(array('label', 'html', 'error'));
330     } // end func _renderError
331
332    /**
333     * Process an template sourced in a string with Smarty
334     *
335     * Smarty has no core function to render     a template given as a string.
336     * So we use the smarty eval plugin function to do this.
337     *
338     * @param    string      The template source
339     * @access   private
340     * @return   void
341     */
342     function _tplFetch($tplSource)
343     {
344         if (!function_exists('smarty_function_eval')) {
345             require SMARTY_DIR . '/plugins/function.eval.php';
346         }
347         return smarty_function_eval(array('var' => $tplSource), $this->_tpl);
348     }// end func _tplFetch
349
350    /**
351     * Sets the way required elements are rendered
352     *
353     * You can use {$label} or {$html} placeholders to let the renderer know where
354     * where the element label or the element html are positionned according to the
355     * required tag. They will be replaced accordingly with the right value.     You
356     * can use the full smarty syntax here, especially a custom modifier for I18N.
357     * For example:
358     * {if $required}<span style="color: red;">*</span>{/if}{$label|translate}
359     * will put a red star in front of the label if the element is required and
360     * translate the label.
361     *
362     *
363     * @param    string      The required element template
364     * @access   public
365     * @return   void
366     */
367     function setRequiredTemplate($template)
368     {
369         $this->_required = $template;
370     } // end func setRequiredTemplate
371
372    /**
373     * Sets the way elements with validation errors are rendered
374     *
375     * You can use {$label} or {$html} placeholders to let the renderer know where
376     * where the element label or the element html are positionned according to the
377     * error message. They will be replaced accordingly with the right value.
378     * The error message will replace the {$error} placeholder.
379     * For example:
380     * {if $error}<span style="color: red;">{$error}</span>{/if}<br />{$html}
381     * will put the error message in red on top of the element html.
382     *
383     * If you want all error messages to be output in the main error block, use
384     * the {$form.errors} part of the rendered array that collects all raw error
385     * messages.
386     *
387     * If you want to place all error messages manually, do not specify {$html}
388     * nor {$label}.
389     *
390     * Groups can have special layouts. With this kind of groups, you have to
391     * place the formated error message manually. In this case, use {$form.group.error}
392     * where you want the formated error message to appear in the form.
393     *
394     * @param    string      The element error template
395     * @access   public
396     * @return   void
397     */
398     function setErrorTemplate($template)
399     {
400         $this->_error = $template;
401     } // end func setErrorTemplate
402 }
403 ?>