Completed
Push — 1.10.x ( 3d9ba2...d7355d )
by
unknown
52:02
created

HTML_QuickForm_Renderer_Default::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
4
/**
5
 * A concrete renderer for HTML_QuickForm, based on QuickForm 2.x built-in one
6
 *
7
 * PHP versions 4 and 5
8
 *
9
 * LICENSE: This source file is subject to version 3.01 of the PHP license
10
 * that is available through the world-wide-web at the following URI:
11
 * http://www.php.net/license/3_01.txt If you did not receive a copy of
12
 * the PHP License and are unable to obtain it through the web, please
13
 * send a note to [email protected] so we can mail you a copy immediately.
14
 *
15
 * @category    HTML
16
 * @package     HTML_QuickForm
17
 * @author      Alexey Borzov <[email protected]>
18
 * @author      Adam Daniel <[email protected]>
19
 * @author      Bertrand Mansion <[email protected]>
20
 * @copyright   2001-2009 The PHP Group
21
 * @license     http://www.php.net/license/3_01.txt PHP License 3.01
22
 * @version     CVS: $Id$
23
 * @link        http://pear.php.net/package/HTML_QuickForm
24
 */
25
26
/**
27
 * A concrete renderer for HTML_QuickForm, based on QuickForm 2.x built-in one
28
 *
29
 * @category    HTML
30
 * @package     HTML_QuickForm
31
 * @author      Alexey Borzov <[email protected]>
32
 * @author      Adam Daniel <[email protected]>
33
 * @author      Bertrand Mansion <[email protected]>
34
 * @version     Release: 3.2.11
35
 * @since       3.0
36
 */
37
class HTML_QuickForm_Renderer_Default extends HTML_QuickForm_Renderer
38
{
39
    private $form;
40
    private $customElementTemplate;
41
42
    /**
43
     * @return mixed
44
     */
45
    public function getCustomElementTemplate()
46
    {
47
        return $this->customElementTemplate;
48
    }
49
50
    /**
51
     * This template will be taken instead of the default templates by element
52
     * @param string $customElementTemplate
53
     */
54
    public function setCustomElementTemplate($customElementTemplate)
55
    {
56
        $this->customElementTemplate = $customElementTemplate;
57
    }
58
59
   /**
60
    * The HTML of the form
61
    * @var      string
62
    * @access   private
63
    */
64
    var $_html;
65
66
   /**
67
    * Header Template string
68
    * @var      string
69
    * @access   private
70
    */
71
    var $_headerTemplate =
72
        "\n\t<tr>\n\t\t<td style=\"white-space: nowrap; background-color: #CCCCCC;\" align=\"left\" valign=\"top\" colspan=\"2\"><b>{header}</b></td>\n\t</tr>";
73
74
   /**
75
    * Element template string
76
    * @var      string
77
    * @access   private
78
    */
79
    var $_elementTemplate =
80
        "\n\t<tr>\n\t\t<td align=\"right\" valign=\"top\"><!-- BEGIN required --><span style=\"color: #ff0000\">*</span><!-- END required --><b>{label}</b></td>\n\t\t<td valign=\"top\" align=\"left\"><!-- BEGIN error --><span style=\"color: #ff0000\">{error}</span><br /><!-- END error -->\t{element}</td>\n\t</tr>";
81
82
   /**
83
    * Form template string
84
    * @var      string
85
    * @access   private
86
    */
87
    var $_formTemplate =
88
        "\n<form{attributes}>\n<div>\n{hidden}<table border=\"0\">\n{content}\n</table>\n</div>\n</form>";
89
90
   /**
91
    * Required Note template string
92
    * @var      string
93
    * @access   private
94
    */
95
    var $_requiredNoteTemplate =
96
        "\n\t<tr>\n\t\t<td></td>\n\t<td align=\"left\" valign=\"top\">{requiredNote}</td>\n\t</tr>";
97
98
   /**
99
    * Array containing the templates for customised elements
100
    * @var      array
101
    * @access   private
102
    */
103
    var $_templates = array();
104
105
   /**
106
    * Array containing the templates for group wraps.
107
    *
108
    * These templates are wrapped around group elements and groups' own
109
    * templates wrap around them. This is set by setGroupTemplate().
110
    *
111
    * @var      array
112
    * @access   private
113
    */
114
    var $_groupWraps = array();
115
116
   /**
117
    * Array containing the templates for elements within groups
118
    * @var      array
119
    * @access   private
120
    */
121
    var $_groupTemplates = array();
122
123
   /**
124
    * True if we are inside a group
125
    * @var      bool
126
    * @access   private
127
    */
128
    var $_inGroup = false;
129
130
   /**
131
    * Array with HTML generated for group elements
132
    * @var      array
133
    * @access   private
134
    */
135
    var $_groupElements = array();
136
137
   /**
138
    * Template for an element inside a group
139
    * @var      string
140
    * @access   private
141
    */
142
    var $_groupElementTemplate = '';
143
144
   /**
145
    * HTML that wraps around the group elements
146
    * @var      string
147
    * @access   private
148
    */
149
    var $_groupWrap = '';
150
151
   /**
152
    * HTML for the current group
153
    * @var      string
154
    * @access   private
155
    */
156
    var $_groupTemplate = '';
157
158
   /**
159
    * Collected HTML of the hidden fields
160
    * @var      string
161
    * @access   private
162
    */
163
    var $_hiddenHtml = '';
164
165
   /**
166
    * Constructor
167
    *
168
    * @access public
169
    */
170
    public function __construct()
171
    {
172
        parent::__construct();
173
    } // end constructor
174
175
   /**
176
    * returns the HTML generated for the form
177
    *
178
    * @access public
179
    * @return string
180
    */
181
    public function toHtml()
182
    {
183
        // _hiddenHtml is cleared in finishForm(), so this only matters when
184
        // finishForm() was not called (e.g. group::toHtml(), bug #3511)
185
        return $this->_hiddenHtml . $this->_html;
186
    } // end func toHtml
187
188
   /**
189
    * Called when visiting a form, before processing any form elements
190
    *
191
    * @param    HTML_QuickForm  form object being visited
192
    * @access   public
193
    * @return   void
194
    */
195
    function startForm(&$form)
196
    {
197
        $this->setForm($form);
198
199
        $this->_html = '';
200
        $this->_hiddenHtml = '';
201
    }
202
203
    /**
204
     * @return FormValidator
205
     */
206
    public function getForm()
207
    {
208
        return $this->form;
209
    }
210
211
    /**
212
     * @param mixed $form
213
     */
214
    public function setForm($form)
215
    {
216
        $this->form = $form;
217
    } // end func startForm
218
219
220
221
   /**
222
    * Called when visiting a form, after processing all form elements
223
    * Adds required note, form attributes, validation javascript and form content.
224
    *
225
    * @param    HTML_QuickForm  form object being visited
226
    * @access   public
227
    * @return   void
228
    */
229
    public function finishForm(&$form)
230
    {
231
        // add a required note, if one is needed
232
        if (!empty($form->_required) && !$form->_freezeAll) {
233
            $this->_html .= str_replace('{requiredNote}', $form->getRequiredNote(), $this->_requiredNoteTemplate);
234
        }
235
        // add form attributes and content
236
        $html = str_replace('{attributes}', $form->getAttributes(true), $this->_formTemplate);
237
238
        if (strpos($this->_formTemplate, '{hidden}')) {
239
            $html = str_replace('{hidden}', $this->_hiddenHtml, $html);
240
        } else {
241
            $this->_html .= $this->_hiddenHtml;
242
        }
243
        $this->_hiddenHtml = '';
244
        $this->_html = str_replace('{content}', $this->_html, $html);
245
        // add a validation script
246
        if ('' != ($script = $form->getValidationScript())) {
247
            $this->_html = $script . "\n" . $this->_html;
248
        }
249
    } // end func finishForm
250
251
   /**
252
    * Called when visiting a header element
253
    *
254
    * @param    HTML_QuickForm_header   header element being visited
255
    * @access   public
256
    * @return   void
257
    */
258
    function renderHeader(&$header)
259
    {
260
        $name = $header->getName();
261
        if (!empty($name) && isset($this->_templates[$name])) {
262
            $this->_html .= str_replace('{header}', $header->toHtml(), $this->_templates[$name]);
263
        } else {
264
            $this->_html .= str_replace('{header}', $header->toHtml(), $this->_headerTemplate);
265
        }
266
    } // end func renderHeader
267
268
   /**
269
    * Helper method for renderElement
270
    *
271
    * @param    HTML_QuickForm_element $element
272
    * @param    bool        Whether an element is required
273
    * @param    string      $required Error message associated with the element
274
    * @param    string      $error Label for ID
275
    * @access   private
276
    * @see      renderElement()
277
    * @return   string      Html for element
278
    */
279
    private function _prepareTemplate(HTML_QuickForm_element $element, $required, $error)
280
    {
281
        $name = $element->getName();
282
        $label = $element->getLabel();
283
        $labelForId = $element->getAttribute('id');
284
        $icon = $element->getIconToHtml();
285
286
        if (is_array($label)) {
287
            $nameLabel = array_shift($label);
288
        } else {
289
            $nameLabel = $label;
290
        }
291
292
        $labelFor = !empty($labelForId) ? 'for="' . $labelForId . '"' : 'for="' . $element->getName() . '"';
293
294
        if (isset($this->_templates[$name])) {
295
            // Custom template
296
            $html = str_replace('{label}', $nameLabel, $this->_templates[$name]);
297
        } else {
298
            $customElementTemplate = $this->getCustomElementTemplate();
299
            if (empty($customElementTemplate)) {
300
                if (method_exists($element, 'getTemplate')) {
301
                    $template = $element->getTemplate(
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class HTML_QuickForm_element as the method getTemplate() does only exist in the following sub-classes of HTML_QuickForm_element: DatePicker, DateRangePicker, DateTimePicker, HTML_QuickForm_CAPTCHA_Image, HTML_QuickForm_advmultiselect, HTML_QuickForm_autocomplete, HTML_QuickForm_button, HTML_QuickForm_hiddenselect, HTML_QuickForm_password, HTML_QuickForm_reset, HTML_QuickForm_select, HTML_QuickForm_text, HTML_QuickForm_textarea, HtmlEditor, Number, SelectAjax, SelectLanguage, SelectTheme, Url. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
302
                        $this->getForm()->getLayout()
303
                    );
304
                } else {
305
                    $template = $this->getForm()->getDefaultElementTemplate();
306
                }
307
            } else {
308
                $template = $customElementTemplate;
309
            }
310
            $html = str_replace('{label}', $nameLabel, $template);
311
        }
312
        $html = str_replace('{label-for}', $labelFor, $html);
313
        $html = str_replace('{icon}', $icon, $html);
314
315 View Code Duplication
        if ($required) {
316
            $html = str_replace('<!-- BEGIN required -->', '', $html);
317
            $html = str_replace('<!-- END required -->', '', $html);
318
        } else {
319
            $html = preg_replace("/([ \t\n\r]*)?<!-- BEGIN required -->.*<!-- END required -->([ \t\n\r]*)?/isU", '', $html);
320
        }
321
        if (isset($error)) {
322
323
            $html = str_replace('{error}', $error, $html);
324
            $html = str_replace('{error_class}', 'error has-error', $html);
325
            $html = str_replace('<!-- BEGIN error -->', '', $html);
326
            $html = str_replace('<!-- END error -->', '', $html);
327
        } else {
328
            $html = str_replace('{error_class}', '', $html);
329
            $html = preg_replace("/([ \t\n\r]*)?<!-- BEGIN error -->.*<!-- END error -->([ \t\n\r]*)?/isU", '', $html);
330
        }
331 View Code Duplication
        if (is_array($label)) {
332
            foreach ($label as $key => $text) {
333
                $key  = is_int($key)? $key + 2: $key;
334
                $html = str_replace("{label_{$key}}", $text, $html);
335
                $html = str_replace("<!-- BEGIN label_{$key} -->", '', $html);
336
                $html = str_replace("<!-- END label_{$key} -->", '', $html);
337
            }
338
        }
339
        if (strpos($html, '{label_')) {
340
            $html = preg_replace('/\s*<!-- BEGIN label_(\S+) -->.*<!-- END label_\1 -->\s*/is', '', $html);
341
        }
342
343
        return $html;
344
    } // end func _prepareTemplate
345
346
   /**
347
    * Renders an element Html
348
    * Called when visiting an element
349
    *
350
    * @param HTML_QuickForm_element form element being visited
351
    * @param bool                   Whether an element is required
352
    * @param string                 An error message associated with an element
353
    * @access public
354
    * @return void
355
    */
356
    public function renderElement(&$element, $required, $error)
357
    {
358
        if (!$this->_inGroup) {
359
            $html = $this->_prepareTemplate(
360
                $element,
361
                $required,
362
                $error
363
            );
364
365
            $this->_html .= str_replace('{element}', $element->toHtml(), $html);
366
        } elseif (!empty($this->_groupElementTemplate)) {
367
            $html = str_replace('{label}', $element->getLabel(), $this->_groupElementTemplate);
368
            $html = str_replace('{label-for}', $element->getLabelFor(), $this->_groupElementTemplate);
369 View Code Duplication
            if ($required) {
370
                $html = str_replace('<!-- BEGIN required -->', '', $html);
371
                $html = str_replace('<!-- END required -->', '', $html);
372
            } else {
373
                $html = preg_replace("/([ \t\n\r]*)?<!-- BEGIN required -->.*<!-- END required -->([ \t\n\r]*)?/isU", '', $html);
374
            }
375
            $this->_groupElements[] = str_replace('{element}', $element->toHtml(), $html);
376
377
        } else {
378
            $this->_groupElements[] = $element->toHtml();
379
        }
380
    } // end func renderElement
381
382
   /**
383
    * Renders an hidden element
384
    * Called when visiting a hidden element
385
    *
386
    * @param HTML_QuickForm_element     form element being visited
387
    * @access public
388
    * @return void
389
    */
390
    function renderHidden(&$element)
391
    {
392
        $this->_hiddenHtml .= $element->toHtml() . "\n";
393
    } // end func renderHidden
394
395
   /**
396
    * Called when visiting a raw HTML/text pseudo-element
397
    *
398
    * @param  HTML_QuickForm_html   element being visited
399
    * @access public
400
    * @return void
401
    */
402
    function renderHtml(&$data)
403
    {
404
        $this->_html .= $data->toHtml();
405
    } // end func renderHtml
406
407
   /**
408
    * Called when visiting a group, before processing any group elements
409
    *
410
    * @param HTML_QuickForm_group   group being visited
411
    * @param bool       Whether a group is required
412
    * @param string     An error message associated with a group
413
    * @access public
414
    * @return void
415
    */
416
    function startGroup(&$group, $required, $error)
417
    {
418
        $name = $group->getName();
419
        $this->_groupTemplate        = $this->_prepareTemplate($group, $required, $error);
420
        $this->_groupElementTemplate = empty($this->_groupTemplates[$name])? '': $this->_groupTemplates[$name];
421
        $this->_groupWrap            = empty($this->_groupWraps[$name])? '': $this->_groupWraps[$name];
422
        $this->_groupElements        = array();
423
        $this->_inGroup              = true;
424
    } // end func startGroup
425
426
   /**
427
    * Called when visiting a group, after processing all group elements
428
    *
429
    * @param    HTML_QuickForm_group    group being visited
430
    * @access   public
431
    * @return   void
432
    */
433
    function finishGroup(&$group)
434
    {
435
        $separator = $group->_separator;
436
        if (is_array($separator)) {
437
            $count = count($separator);
438
            $html  = '';
439
            for ($i = 0; $i < count($this->_groupElements); $i++) {
440
                $html .= (0 == $i? '': $separator[($i - 1) % $count]) . $this->_groupElements[$i];
441
            }
442
        } else {
443
            if (is_null($separator)) {
444
                $separator = '&nbsp;';
445
            }
446
            $html = implode((string)$separator, $this->_groupElements);
447
        }
448
        if (!empty($this->_groupWrap)) {
449
            $html = str_replace('{content}', $html, $this->_groupWrap);
450
        }
451
        $this->_html   .= str_replace('{element}', $html, $this->_groupTemplate);
452
        $this->_inGroup = false;
453
    } // end func finishGroup
454
455
    /**
456
     * Sets element template
457
     *
458
     * @param       string      The HTML surrounding an element
459
     * @param       string      (optional) Name of the element to apply template for
460
     * @access      public
461
     * @return      void
462
     */
463
    function setElementTemplate($html, $element = null)
464
    {
465
        if (is_null($element)) {
466
            $this->_elementTemplate = $html;
467
        } else {
468
            $this->_templates[$element] = $html;
469
        }
470
    } // end func setElementTemplate
471
472
473
    /**
474
     * Sets template for a group wrapper
475
     *
476
     * This template is contained within a group-as-element template
477
     * set via setTemplate() and contains group's element templates, set
478
     * via setGroupElementTemplate()
479
     *
480
     * @param       string      The HTML surrounding group elements
481
     * @param       string      Name of the group to apply template for
482
     * @access      public
483
     * @return      void
484
     */
485
    function setGroupTemplate($html, $group)
486
    {
487
        $this->_groupWraps[$group] = $html;
488
    } // end func setGroupTemplate
489
490
    /**
491
     * Sets element template for elements within a group
492
     *
493
     * @param       string      The HTML surrounding an element
494
     * @param       string      Name of the group to apply template for
495
     * @access      public
496
     * @return      void
497
     */
498
    function setGroupElementTemplate($html, $group)
499
    {
500
        $this->_groupTemplates[$group] = $html;
501
    } // end func setGroupElementTemplate
502
503
    /**
504
     * Sets header template
505
     *
506
     * @param       string      The HTML surrounding the header
507
     * @access      public
508
     * @return      void
509
     */
510
    function setHeaderTemplate($html)
511
    {
512
        $this->_headerTemplate = $html;
513
    } // end func setHeaderTemplate
514
515
    /**
516
     * Sets form template
517
     *
518
     * @param     string    The HTML surrounding the form tags
519
     * @access    public
520
     * @return    void
521
     */
522
    function setFormTemplate($html) {
523
        $this->_formTemplate = $html;
524
    } // end func setFormTemplate
525
526
    /**
527
     * Sets the note indicating required fields template
528
     *
529
     * @param       string      The HTML surrounding the required note
530
     * @access      public
531
     * @return      void
532
     */
533
    function setRequiredNoteTemplate($html)
534
    {
535
        $this->_requiredNoteTemplate = $html;
536
    } // end func setRequiredNoteTemplate
537
538
    /**
539
     * Clears all the HTML out of the templates that surround notes, elements, etc.
540
     * Useful when you want to use addData() to create a completely custom form look
541
     *
542
     * @access  public
543
     * @return  void
544
     */
545
    function clearAllTemplates()
546
    {
547
        $this->setElementTemplate('{element}');
548
        $this->setFormTemplate("\n\t<form{attributes}>{content}\n\t</form>\n");
549
        $this->setRequiredNoteTemplate('');
550
        $this->_templates = array();
551
    } // end func clearAllTemplates
552
} // end class HTML_QuickForm_Renderer_Default
553