Completed
Push — master ( 9b8b24...6e1754 )
by Julito
58:58
created

FormValidator   F

Complexity

Total Complexity 135

Size/Duplication

Total Lines 1768
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 1768
rs 0.6314
c 0
b 0
f 0
wmc 135

60 Methods

Rating   Name   Duplication   Size   Complexity  
A addButtonImport() 0 11 1
A getDefaultRenderer() 0 5 2
A addButtonSearch() 0 7 2
A addButtonDelete() 0 11 1
A addLabel() 0 3 1
A addButtonMove() 0 11 1
A addSelectLanguage() 0 3 1
A addButtonSend() 0 11 1
A addButtonNext() 0 10 1
A addSelectAjax() 0 11 2
A addHtml() 0 3 1
A addButtonFilter() 0 11 1
A addText() 0 9 2
A addButtonDownload() 0 11 1
A addMultipleUpload() 0 18 1
B addMultipleUploadJavascript() 0 102 2
A addDateRangePicker() 0 8 2
A addUrl() 0 8 2
B addSelectFromCollection() 0 24 5
A addButtonCancel() 0 11 1
B addTextAlphanumeric() 0 35 2
A addDatePicker() 0 3 1
A addProgress() 0 10 2
B addPasswordRule() 0 31 5
A addFile() 0 22 3
A addButtonAdvancedSettings() 0 5 2
B addFloat() 0 66 5
A addHeader() 0 3 1
A addButtonPreview() 0 11 1
A addRadio() 0 8 2
A addDateTimePicker() 0 3 1
B addGeoLocationMapField() 0 138 2
A addButtonCopy() 0 11 1
A addButtonExport() 0 11 1
A addTextarea() 0 3 1
F addHtmlEditor() 0 32 9
A addCheckBoxGroup() 0 15 2
B addTextLettersAndSpaces() 0 35 2
B addTextAlphanumericAndSpaces() 0 35 2
A add_multiple_required_rule() 0 4 1
B addButtonReset() 0 30 2
A getLayout() 0 3 1
A return_form() 0 3 1
A getDefaultElementTemplate() 0 3 1
A addButtonUpdate() 0 11 1
A addButtonUpload() 0 11 1
A addHidden() 0 3 1
A addSelect() 0 3 1
F create() 0 50 20
B addTextLettersOnly() 0 35 2
B returnForm() 0 30 5
A addUserAvatar() 0 3 1
B addButton() 0 32 2
D __construct() 0 83 13
A display() 0 3 1
A addButtonSave() 0 11 1
A addButtonCreate() 0 11 1
A getFormTemplate() 0 3 1
A addCheckBox() 0 3 1
A setLayout() 0 3 1

How to fix   Complexity   

Complex Class

Complex classes like FormValidator often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use FormValidator, and based on these observations, apply Extract Interface, too.

1
<?php
2
/* For licensing terms, see /license.txt */
3
4
/**
5
 * Class FormValidator
6
 * create/manipulate/validate user input.
7
 */
8
class FormValidator extends HTML_QuickForm
9
{
10
    const LAYOUT_HORIZONTAL = 'horizontal';
11
    const LAYOUT_INLINE = 'inline';
12
    const LAYOUT_BOX = 'box';
13
    const LAYOUT_BOX_NO_LABEL = 'box-no-label';
14
15
    public $with_progress_bar = false;
16
    private $layout;
17
18
    /**
19
     * Constructor
20
     * @param string $name Name of the form
21
     * @param string $method (optional) Method ('post' (default) or 'get')
22
     * @param string $action (optional) Action (default is $PHP_SELF)
23
     * @param string $target (optional) Form's target defaults to '_self'
24
     * @param mixed $attributes (optional) Extra attributes for <form> tag
25
     * @param string $layout
26
     * @param bool $trackSubmit (optional) Whether to track if the form was
27
     * submitted by adding a special hidden field (default = true)
28
     */
29
    public function __construct(
30
        $name,
31
        $method = 'post',
32
        $action = '',
33
        $target = '',
34
        $attributes = array(),
35
        $layout = self::LAYOUT_HORIZONTAL,
36
        $trackSubmit = true
37
    ) {
38
        // Default form class.
39
        if (is_array($attributes) && !isset($attributes['class']) || empty($attributes)) {
40
            $attributes['class'] = 'form-horizontal';
41
        }
42
43
        if (isset($attributes['class']) && strpos($attributes['class'], 'form-search') !== false) {
44
            $layout = 'inline';
45
        }
46
47
        $this->setLayout($layout);
48
49
        switch ($layout) {
50
            case self::LAYOUT_HORIZONTAL:
51
                $attributes['class'] = 'form-horizontal';
52
                break;
53
            case self::LAYOUT_INLINE:
54
            case self::LAYOUT_BOX:
55
                $attributes['class'] = 'form-inline';
56
                break;
57
        }
58
59
        parent::__construct($name, $method, $action, $target, $attributes, $trackSubmit);
60
61
        // Modify the default templates
62
        $renderer = & $this->defaultRenderer();
63
64
        // Form template
65
        $formTemplate = $this->getFormTemplate();
66
        $renderer->setFormTemplate($formTemplate);
67
68
        // Element template
69
        if (isset($attributes['class']) && $attributes['class'] == 'form-inline') {
70
            $elementTemplate = ' {label}  {element} ';
71
            $renderer->setElementTemplate($elementTemplate);
72
        } elseif (isset($attributes['class']) && $attributes['class'] == 'form-search') {
73
            $elementTemplate = ' {label}  {element} ';
74
            $renderer->setElementTemplate($elementTemplate);
75
        } else {
76
            $renderer->setElementTemplate($this->getDefaultElementTemplate());
77
78
            // Display a gray div in the buttons
79
            $templateSimple = '<div class="form-actions">{label} {element}</div>';
80
            $renderer->setElementTemplate($templateSimple, 'submit_in_actions');
81
82
            //Display a gray div in the buttons + makes the button available when scrolling
83
            $templateBottom = '<div class="form-actions bottom_actions bg-form">{label} {element}</div>';
84
            $renderer->setElementTemplate($templateBottom, 'submit_fixed_in_bottom');
85
86
            //When you want to group buttons use something like this
87
            /* $group = array();
88
              $group[] = $form->createElement('button', 'mark_all', get_lang('MarkAll'));
89
              $group[] = $form->createElement('button', 'unmark_all', get_lang('UnmarkAll'));
90
              $form->addGroup($group, 'buttons_in_action');
91
             */
92
            $renderer->setElementTemplate($templateSimple, 'buttons_in_action');
93
94
            $templateSimpleRight = '<div class="form-actions"> <div class="pull-right">{label} {element}</div></div>';
95
            $renderer->setElementTemplate($templateSimpleRight, 'buttons_in_action_right');
96
        }
97
98
        //Set Header template
99
        $renderer->setHeaderTemplate('<legend>{header}</legend>');
100
101
        //Set required field template
102
        $this->setRequiredNote(
103
            '<span class="form_required">*</span> <small>'.get_lang('ThisFieldIsRequired').'</small>'
104
        );
105
106
        $noteTemplate = <<<EOT
107
	<div class="form-group">
108
		<div class="col-sm-offset-2 col-sm-10">{requiredNote}</div>
109
	</div>
110
EOT;
111
        $renderer->setRequiredNoteTemplate($noteTemplate);
112
    }
113
114
    /**
115
     * @return string
116
     */
117
    public function getFormTemplate()
118
    {
119
        return '<form{attributes}>
120
        <fieldset>
121
            {content}
122
        </fieldset>
123
        {hidden}
124
        </form>';
125
    }
126
127
    /**
128
     * @todo this function should be added in the element class
129
     * @return string
130
     */
131
    public function getDefaultElementTemplate()
132
    {
133
        return '
134
            <div class="form-group {error_class}">
135
                <label {label-for} class="col-sm-2 control-label {extra_label_class}" >
136
                    <!-- BEGIN required --><span class="form_required">*</span><!-- END required -->
137
                    {label}
138
                </label>
139
                <div class="col-sm-8">
140
                    {icon}
141
                    {element}
142
143
                    <!-- BEGIN label_2 -->
144
                        <p class="help-block">{label_2}</p>
145
                    <!-- END label_2 -->
146
147
                    <!-- BEGIN error -->
148
                        <span class="help-inline help-block">{error}</span>
149
                    <!-- END error -->
150
                </div>
151
                <div class="col-sm-2">
152
                    <!-- BEGIN label_3 -->
153
                        {label_3}
154
                    <!-- END label_3 -->
155
                </div>
156
            </div>';
157
    }
158
159
    /**
160
     * @return string
161
     */
162
    public function getLayout()
163
    {
164
        return $this->layout;
165
    }
166
167
    /**
168
     * @param string $layout
169
     */
170
    public function setLayout($layout)
171
    {
172
        $this->layout = $layout;
173
    }
174
175
    /**
176
     * Adds a text field to the form.
177
     * A trim-filter is attached to the field.
178
     * @param string $label The label for the form-element
179
     * @param string $name The element name
180
     * @param bool $required (optional)    Is the form-element required (default=true)
181
     * @param array $attributes (optional)    List of attributes for the form-element
182
     * @return HTML_QuickForm_text
183
     */
184
    public function addText($name, $label, $required = true, $attributes = array())
185
    {
186
        $element = $this->addElement('text', $name, $label, $attributes);
187
        $this->applyFilter($name, 'trim');
188
        if ($required) {
189
            $this->addRule($name, get_lang('ThisFieldIsRequired'), 'required');
190
        }
191
192
        return $element;
193
    }
194
195
    /**
196
     * The "date_range_picker" element creates 2 hidden fields
197
     * "elementName" + "_start"  and "elementName" + "_end"
198
     * For example if the name is "range", you will have 2 new fields
199
     * when executing $form->getSubmitValues()
200
     * "range_start" and "range_end"
201
     *
202
     * @param string $name
203
     * @param string $label
204
     * @param bool   $required
205
     * @param array  $attributes
206
     */
207
    public function addDateRangePicker($name, $label, $required = true, $attributes = array())
208
    {
209
        $this->addElement('date_range_picker', $name, $label, $attributes);
210
        $this->addElement('hidden', $name.'_start');
211
        $this->addElement('hidden', $name.'_end');
212
213
        if ($required) {
214
            $this->addRule($name, get_lang('ThisFieldIsRequired'), 'required');
215
        }
216
    }
217
218
    /**
219
     * @param string $name
220
     * @param string $label
221
     * @param array $attributes
222
     *
223
     * @return mixed
224
     */
225
    public function addDatePicker($name, $label, $attributes = [])
226
    {
227
        return $this->addElement('DatePicker', $name, $label, $attributes);
228
    }
229
230
    /**
231
     * @param string $name
232
     * @param string $label
233
     * @param array $attributes
234
     *
235
     * @return mixed
236
     */
237
    public function addSelectLanguage($name, $label, $options = [], $attributes = [])
238
    {
239
        return $this->addElement('SelectLanguage', $name, $label, $options, $attributes);
240
    }
241
242
    /**
243
     * @param string $name
244
     * @param string $label
245
     * @param array $options
246
     * @param array $attributes
247
     * @throws
248
     */
249
    public function addSelectAjax($name, $label, $options = [], $attributes = [])
250
    {
251
        if (!isset($attributes['url'])) {
252
            throw new \Exception('select_ajax needs an URL');
253
        }
254
        $this->addElement(
255
            'select_ajax',
256
            $name,
257
            $label,
258
            $options,
259
            $attributes
260
        );
261
    }
262
263
    /**
264
     * @param string $name
265
     * @param string $label
266
     * @param array $attributes
267
     *
268
     * @return mixed
269
     */
270
    public function addDateTimePicker($name, $label, $attributes = [])
271
    {
272
        return $this->addElement('DateTimePicker', $name, $label, $attributes);
273
    }
274
275
    /**
276
     * @param string $name
277
     * @param string $value
278
     */
279
    public function addHidden($name, $value)
280
    {
281
        $this->addElement('hidden', $name, $value);
282
    }
283
284
    /**
285
     * @param string $name
286
     * @param string $label
287
     * @param array  $attributes
288
     *
289
     * @return HTML_QuickForm_textarea
290
     */
291
    public function addTextarea($name, $label, $attributes = array())
292
    {
293
        return $this->addElement('textarea', $name, $label, $attributes);
294
    }
295
296
    /**
297
     * @param string $name
298
     * @param string $label
299
     * @param string $icon font-awesome
300
     * @param string $style default|primary|success|info|warning|danger|link
301
     * @param string $size large|default|small|extra-small
302
     * @param string $class Example plus is transformed to icon fa fa-plus
303
     * @param array  $attributes
304
     *
305
     * @return HTML_QuickForm_button
306
     */
307
    public function addButton(
308
        $name,
309
        $label,
310
        $icon = 'check',
311
        $style = 'default',
312
        $size = 'default',
313
        $class = null,
314
        $attributes = array(),
315
        $createElement = false
316
    ) {
317
        if ($createElement) {
318
            return $this->createElement(
319
                'button',
320
                $name,
321
                $label,
322
                $icon,
323
                $style,
324
                $size,
325
                $class,
326
                $attributes
327
            );
328
        }
329
330
        return $this->addElement(
331
            'button',
332
            $name,
333
            $label,
334
            $icon,
335
            $style,
336
            $size,
337
            $class,
338
            $attributes
339
        );
340
    }
341
342
    /**
343
     * Returns a button with the primary color and a check mark
344
     * @param string $label Text appearing on the button
345
     * @param string $name Element name (for form treatment purposes)
346
     * @param bool $createElement Whether to use the create or add method
347
     *
348
     * @return HTML_QuickForm_button
349
     */
350
    public function addButtonSave($label, $name = 'submit', $createElement = false)
351
    {
352
        return $this->addButton(
353
            $name,
354
            $label,
355
            'check',
356
            'primary',
357
            null,
358
            null,
359
            array(),
360
            $createElement
361
        );
362
    }
363
364
    /**
365
     * Returns a cancel button
366
     * @param string $label Text appearing on the button
367
     * @param string $name Element name (for form treatment purposes)
368
     * @param bool $createElement Whether to use the create or add method
369
     *
370
     * @return HTML_QuickForm_button
371
     */
372
    public function addButtonCancel($label, $name = 'submit', $createElement = false)
373
    {
374
        return $this->addButton(
375
            $name,
376
            $label,
377
            'times',
378
            'danger',
379
            null,
380
            null,
381
            array(),
382
            $createElement
383
        );
384
    }
385
386
    /**
387
     * Returns a button with the primary color and a "plus" icon
388
     * @param string $label Text appearing on the button
389
     * @param string $name Element name (for form treatment purposes)
390
     * @param bool $createElement Whether to use the create or add method
391
     * @param array $attributes Additional attributes
392
     *
393
     * @return HTML_QuickForm_button
394
     */
395
    public function addButtonCreate($label, $name = 'submit', $createElement = false, $attributes = array())
396
    {
397
        return $this->addButton(
398
            $name,
399
            $label,
400
            'plus',
401
            'primary',
402
            null,
403
            null,
404
            $attributes,
405
            $createElement
406
        );
407
    }
408
409
    /**
410
     * Returns a button with the primary color and a pencil icon
411
     * @param string $label Text appearing on the button
412
     * @param string $name Element name (for form treatment purposes)
413
     * @param bool $createElement Whether to use the create or add method
414
     * @return HTML_QuickForm_button
415
     */
416
    public function addButtonUpdate($label, $name = 'submit', $createElement = false)
417
    {
418
        return $this->addButton(
419
            $name,
420
            $label,
421
            'pencil',
422
            'primary',
423
            null,
424
            null,
425
            array(),
426
            $createElement
427
        );
428
    }
429
430
    /**
431
     * Returns a button with the danger color and a trash icon
432
     * @param string $label Text appearing on the button
433
     * @param string $name Element name (for form treatment purposes)
434
     * @param bool $createElement Whether to use the create or add method
435
     *
436
     * @return HTML_QuickForm_button
437
     */
438
    public function addButtonDelete($label, $name = 'submit', $createElement = false)
439
    {
440
        return $this->addButton(
441
            $name,
442
            $label,
443
            'trash',
444
            'danger',
445
            null,
446
            null,
447
            array(),
448
            $createElement
449
        );
450
    }
451
452
    /**
453
     * Returns a move style button
454
     * @param string $label Text appearing on the button
455
     * @param string $name Element name (for form treatment purposes)
456
     * @param bool $createElement Whether to use the create or add method
457
     *
458
     * @return HTML_QuickForm_button
459
     */
460
    public function addButtonMove($label, $name = 'submit', $createElement = false)
461
    {
462
        return $this->addButton(
463
            $name,
464
            $label,
465
            'arrow-circle-right',
466
            'primary',
467
            null,
468
            null,
469
            array(),
470
            $createElement
471
        );
472
    }
473
474
    /**
475
     * Returns a button with the primary color and a paper-plane icon
476
     * @param string $label Text appearing on the button
477
     * @param string $name Element name (for form treatment purposes)
478
     * @param bool $createElement Whether to use the create or add method
479
     * @param array $attributes
480
     *
481
     * @return HTML_QuickForm_button
482
     */
483
    public function addButtonSend($label, $name = 'submit', $createElement = false, $attributes = [])
484
    {
485
        return $this->addButton(
486
            $name,
487
            $label,
488
            'paper-plane',
489
            'primary',
490
            null,
491
            null,
492
            $attributes,
493
            $createElement
494
        );
495
    }
496
497
    /**
498
     * Returns a button with the default (grey?) color and a magnifier icon
499
     * @param string $label Text appearing on the button
500
     * @param string $name Element name (for form treatment purposes)
501
     *
502
     * @return HTML_QuickForm_button
503
     */
504
    public function addButtonSearch($label = null, $name = 'submit')
505
    {
506
        if (empty($label)) {
507
            $label = get_lang('Search');
508
        }
509
510
        return $this->addButton($name, $label, 'search', 'default');
511
    }
512
513
    /**
514
     * Returns a button with the primary color and a right-pointing arrow icon
515
     * @param string $label Text appearing on the button
516
     * @param string $name Element name (for form treatment purposes)
517
     * @param array $attributes Additional attributes
518
     * @return HTML_QuickForm_button
519
     */
520
    public function addButtonNext($label, $name = 'submit', $attributes = [])
521
    {
522
        return $this->addButton(
523
            $name,
524
            $label,
525
            'arrow-right',
526
            'primary',
527
            null,
528
            null,
529
            $attributes
530
        );
531
    }
532
533
    /**
534
     * Returns a button with the primary color and a check mark icon
535
     * @param string $label Text appearing on the button
536
     * @param string $name Element name (for form treatment purposes)
537
     * @param bool $createElement Whether to use the create or add method
538
     * @return HTML_QuickForm_button
539
     */
540
    public function addButtonImport($label, $name = 'submit', $createElement = false)
541
    {
542
        return $this->addButton(
543
            $name,
544
            $label,
545
            'check',
546
            'primary',
547
            null,
548
            null,
549
            array(),
550
            $createElement
551
        );
552
    }
553
554
    /**
555
     * Returns a button with the primary color and a check-mark icon
556
     * @param string $label Text appearing on the button
557
     * @param string $name Element name (for form treatment purposes)
558
     * @param bool $createElement Whether to use the create or add method
559
     * @return HTML_QuickForm_button
560
     */
561
    public function addButtonExport($label, $name = 'submit', $createElement = false)
562
    {
563
        return $this->addButton(
564
            $name,
565
            $label,
566
            'check',
567
            'primary',
568
            null,
569
            null,
570
            array(),
571
            $createElement
572
        );
573
    }
574
575
    /**
576
     * Shortcut to filter button
577
     * @param string $label Text appearing on the button
578
     * @param string $name Element name (for form treatment purposes)
579
     * @param bool $createElement Whether to use the create or add method
580
     * @return HTML_QuickForm_button
581
     */
582
    public function addButtonFilter($label, $name = 'submit', $createElement = false)
583
    {
584
        return $this->addButton(
585
            $name,
586
            $label,
587
            'filter',
588
            'primary',
589
            null,
590
            null,
591
            array(),
592
            $createElement
593
        );
594
    }
595
596
    /**
597
     * Shortcut to reset button
598
     * @param string $label Text appearing on the button
599
     * @param string $name Element name (for form treatment purposes)
600
     * @param bool $createElement Whether to use the create or add method
601
     * @return HTML_QuickForm_button
602
     */
603
    public function addButtonReset($label, $name = 'reset', $createElement = false)
604
    {
605
        $icon = 'eraser';
606
        $style = 'default';
607
        $size = 'default';
608
        $class = null;
609
        $attributes = array();
610
611
        if ($createElement) {
612
            return $this->createElement(
613
                'reset',
614
                $name,
615
                $label,
616
                $icon,
617
                $style,
618
                $size,
619
                $class,
620
                $attributes
621
            );
622
        }
623
624
        return $this->addElement(
625
            'reset',
626
            $name,
627
            $label,
628
            $icon,
629
            $style,
630
            $size,
631
            $class,
632
            $attributes
633
        );
634
    }
635
636
    /**
637
     * Returns a button with the primary color and an upload icon
638
     * @param string $label Text appearing on the button
639
     * @param string $name Element name (for form treatment purposes)
640
     * @param bool $createElement Whether to use the create or add method
641
     *
642
     * @return HTML_QuickForm_button
643
     */
644
    public function addButtonUpload($label, $name = 'submit', $createElement = false)
645
    {
646
        return $this->addButton(
647
            $name,
648
            $label,
649
            'upload',
650
            'primary',
651
            null,
652
            null,
653
            array(),
654
            $createElement
655
        );
656
    }
657
658
    /**
659
     * Returns a button with the primary color and a download icon
660
     * @param string $label Text appearing on the button
661
     * @param string $name Element name (for form treatment purposes)
662
     * @param bool $createElement Whether to use the create or add method
663
     *
664
     * @return HTML_QuickForm_button
665
     */
666
    public function addButtonDownload($label, $name = 'submit', $createElement = false)
667
    {
668
        return $this->addButton(
669
            $name,
670
            $label,
671
            'download',
672
            'primary',
673
            null,
674
            null,
675
            array(),
676
            $createElement
677
        );
678
    }
679
680
    /**
681
     * Returns a button with the primary color and a magnifier icon
682
     * @param string $label Text appearing on the button
683
     * @param string $name Element name (for form treatment purposes)
684
     * @param bool $createElement Whether to use the create or add method
685
     *
686
     * @return HTML_QuickForm_button
687
     */
688
    public function addButtonPreview($label, $name = 'submit', $createElement = false)
689
    {
690
        return $this->addButton(
691
            $name,
692
            $label,
693
            'search',
694
            'primary',
695
            null,
696
            null,
697
            array(),
698
            $createElement
699
        );
700
    }
701
702
    /**
703
     * Returns a button with the primary color and a copy (double sheet) icon
704
     * @param string $label Text appearing on the button
705
     * @param string $name Element name (for form treatment purposes)
706
     * @param bool $createElement Whether to use the create or add method
707
     *
708
     * @return HTML_QuickForm_button
709
     */
710
    public function addButtonCopy($label, $name = 'submit', $createElement = false)
711
    {
712
        return $this->addButton(
713
            $name,
714
            $label,
715
            'copy',
716
            'primary',
717
            null,
718
            null,
719
            array(),
720
            $createElement
721
        );
722
    }
723
724
    /**
725
     * @param string $name
726
     * @param string $label
727
     * @param string $text
728
     * @param array  $attributes
729
     *
730
     * @return HTML_QuickForm_checkbox
731
     */
732
    public function addCheckBox($name, $label, $text = '', $attributes = [])
733
    {
734
        return $this->addElement('checkbox', $name, $label, $text, $attributes);
735
    }
736
737
    /**
738
     * @param string $name
739
     * @param string $label
740
     * @param array  $options
741
     * @param array  $attributes
742
     *
743
     * @return HTML_QuickForm_group
744
     */
745
    public function addCheckBoxGroup($name, $label, $options = array(), $attributes = array())
746
    {
747
        $group = array();
748
        foreach ($options as $value => $text) {
749
            $attributes['value'] = $value;
750
            $group[] = $this->createElement(
751
                'checkbox',
752
                $value,
753
                null,
754
                $text,
755
                $attributes
756
            );
757
        }
758
759
        return $this->addGroup($group, $name, $label);
760
    }
761
762
    /**
763
     * @param string $name
764
     * @param string $label
765
     * @param array  $options
766
     * @param array  $attributes
767
     *
768
     * @return HTML_QuickForm_group
769
     */
770
    public function addRadio($name, $label, $options = [], $attributes = [])
771
    {
772
        $group = array();
773
        foreach ($options as $key => $value) {
774
            $group[] = $this->createElement('radio', null, null, $value, $key, $attributes);
775
        }
776
777
        return $this->addGroup($group, $name, $label);
778
    }
779
780
    /**
781
     * @param string $name
782
     * @param string $label
783
     * @param array  $options
784
     * @param array  $attributes
785
     *
786
     * @return HTML_QuickForm_select
787
     */
788
    public function addSelect($name, $label, $options = [], $attributes = [])
789
    {
790
        return $this->addElement('select', $name, $label, $options, $attributes);
791
    }
792
793
    /**
794
     * @param $name
795
     * @param $label
796
     * @param $collection
797
     * @param array $attributes
798
     * @param bool $addNoneOption
799
     * @param string $textCallable set a function getStringValue() by default __toString()
800
     *
801
     * @return HTML_QuickForm_element
802
     */
803
    public function addSelectFromCollection(
804
        $name,
805
        $label,
806
        $collection,
807
        $attributes = array(),
808
        $addNoneOption = false,
809
        $textCallable = ''
810
    ) {
811
        $options = [];
812
813
        if ($addNoneOption) {
814
            $options[0] = get_lang('None');
815
        }
816
817
        if (!empty($collection)) {
818
            foreach ($collection as $item) {
819
                $text = $item;
820
                if (!empty($textCallable)) {
821
                    $text = $item->$textCallable();
822
                }
823
                $options[$item->getId()] = $text;
824
            }
825
        }
826
        return $this->addElement('select', $name, $label, $options, $attributes);
827
    }
828
829
    /**
830
     * @param string $label
831
     * @param string $text
832
     *
833
     * @return HTML_QuickForm_label
834
     */
835
    public function addLabel($label, $text)
836
    {
837
        return $this->addElement('label', $label, $text);
838
    }
839
840
    /**
841
     * @param string $text
842
     */
843
    public function addHeader($text)
844
    {
845
        $this->addElement('header', $text);
846
    }
847
848
    /**
849
     * @param string $name
850
     * @param string $label
851
     * @param array  $attributes
852
     * @throws Exception if the file doesn't have an id
853
     */
854
    public function addFile($name, $label, $attributes = array())
855
    {
856
        $element = $this->addElement('file', $name, $label, $attributes);
857
        if (isset($attributes['crop_image'])) {
858
            $id = $element->getAttribute('id');
859
            if (empty($id)) {
860
                throw new Exception('If you use the crop functionality the element must have an id');
861
            }
862
            $this->addHtml('
863
                <div class="form-group" id="'.$id.'-form-group" style="display: none;">
864
                    <div class="col-sm-offset-2 col-sm-8">
865
                        <div id="'.$id.'_crop_image" class="cropCanvas thumbnail">
866
                            <img id="'.$id.'_preview_image">
867
                        </div>
868
                        <button class="btn btn-primary" type="button" name="cropButton" id="'.$id.'_crop_button">
869
                            <em class="fa fa-crop"></em> '.get_lang('CropYourPicture').'
870
                        </button>
871
                    </div>
872
                </div>'
873
            );
874
            $this->addHidden($id.'_crop_result', '');
875
            $this->addHidden($id.'_crop_image_base_64', '');
876
        }
877
    }
878
879
    /**
880
     * @param string $snippet
881
     */
882
    public function addHtml($snippet)
883
    {
884
        $this->addElement('html', $snippet);
885
    }
886
887
    /**
888
     * Adds a HTML-editor to the form
889
     * @param string $name
890
     * @param string $label The label for the form-element
891
     * @param bool   $required (optional) Is the form-element required (default=true)
892
     * @param bool   $fullPage (optional) When it is true, the editor loads completed html code for a full page.
893
     * @param array  $config (optional) Configuration settings for the online editor.
894
     * @param bool   $style
895
     */
896
    public function addHtmlEditor(
897
        $name,
898
        $label,
899
        $required = true,
900
        $fullPage = false,
901
        $config = [],
902
        $style = false
903
    ) {
904
        $attributes = [];
905
        $attributes['rows'] = isset($config['rows']) ? $config['rows'] : 15;
906
        $attributes['cols'] = isset($config['cols']) ? $config['cols'] : 80;
907
        $attributes['cols-size'] = isset($config['cols-size']) ? $config['cols-size'] : [];
908
        $attributes['class'] = isset($config['class']) ? $config['class'] : [];
909
910
        $this->addElement('html_editor', $name, $label, $attributes, $config);
911
        $this->applyFilter($name, 'trim');
912
        if ($required) {
913
            $this->addRule($name, get_lang('ThisFieldIsRequired'), 'required');
914
        }
915
916
        /** @var HtmlEditor $element */
917
        $element = $this->getElement($name);
918
919
        if ($style) {
920
            $config['style'] = true;
921
        }
922
        if ($fullPage) {
923
            $config['fullPage'] = true;
924
        }
925
926
        if ($element->editor) {
927
            $element->editor->processConfig($config);
928
        }
929
    }
930
931
    /**
932
     * Adds a Google Maps Geolocalization field to the form
933
     *
934
     * @param $name
935
     * @param $label
936
     */
937
    public function addGeoLocationMapField($name, $label)
938
    {
939
        $gMapsPlugin = GoogleMapsPlugin::create();
940
        $geolocalization = $gMapsPlugin->get('enable_api') === 'true';
941
942
        if ($geolocalization) {
943
            $gmapsApiKey = $gMapsPlugin->get('api_key');
944
            $this->addHtml(
945
                '<script type="text/javascript" src="//maps.googleapis.com/maps/api/js?key='.$gmapsApiKey.'" ></script>'
946
            );
947
        }
948
        $this->addElement(
949
            'text',
950
            $name,
951
            $label,
952
            ['id' => $name]
953
        );
954
        $this->applyFilter($name, 'stripslashes');
955
        $this->applyFilter($name, 'trim');
956
        $this->addHtml('
957
            <div class="form-group">
958
                <label for="geolocalization_'.$name.'" class="col-sm-2 control-label"></label>
959
                <div class="col-sm-8">
960
                    <button class="null btn btn-default " id="geolocalization_'.$name.'" name="geolocalization_'.$name.'" type="submit">
961
                        <em class="fa fa-map-marker"></em> '.get_lang('Geolocalization').'
962
                    </button>
963
                    <button class="null btn btn-default " id="myLocation_'.$name.'" name="myLocation_'.$name.'" type="submit">
964
                    <em class="fa fa-crosshairs"></em> 
965
                    '.get_lang('MyLocation').'
966
                    </button>
967
                </div>
968
            </div>
969
        ');
970
971
        $this->addHtml('
972
            <div class="form-group">
973
                <label for="map_'.$name.'" class="col-sm-2 control-label">
974
                    '.$label.' - '.get_lang('Map').'
975
                </label>
976
                <div class="col-sm-8">
977
                    <div name="map_'.$name.'" id="map_'.$name.'" style="width:100%; height:300px;">
978
                    </div>
979
                </div>
980
            </div>
981
        ');
982
983
        $this->addHtml('<script>
984
            $(document).ready(function() {
985
                if (typeof google === "object") {
986
                    var address = $("#' . $name.'").val();
987
                    initializeGeo'.$name.'(address, false);
988
989
                    $("#geolocalization_'.$name.'").on("click", function() {
990
                        var address = $("#'.$name.'").val();
991
                        initializeGeo'.$name.'(address, false);
992
                        return false;
993
                    });
994
995
                    $("#myLocation_'.$name.'").on("click", function() {
996
                        myLocation'.$name.'();
997
                        return false;
998
                    });
999
1000
                    $("#'.$name.'").keypress(function (event) {
1001
                        if (event.which == 13) {
1002
                            $("#geolocalization_'.$name.'").click();
1003
                            return false;
1004
                        }
1005
                    });
1006
                } else {
1007
                    $("#map_'.$name.'").html("<div class=\"alert alert-info\">'.get_lang('YouNeedToActivateTheGoogleMapsPluginInAdminPlatformToSeeTheMap').'</div>");
1008
                }
1009
            });
1010
1011
            function myLocation'.$name.'() {
1012
                if (navigator.geolocation) {
1013
                    var geoPosition = function(position) {
1014
                        var lat = position.coords.latitude;
1015
                        var lng = position.coords.longitude;
1016
                        var latLng = new google.maps.LatLng(lat, lng);
1017
                        initializeGeo'.$name.'(false, latLng)
1018
                    };
1019
1020
                    var geoError = function(error) {
1021
                        alert("Geocode ' . get_lang('Error').': " + error);
1022
                    };
1023
1024
                    var geoOptions = {
1025
                        enableHighAccuracy: true
1026
                    };
1027
                    navigator.geolocation.getCurrentPosition(geoPosition, geoError, geoOptions);
1028
                }
1029
            }
1030
1031
            function initializeGeo'.$name.'(address, latLng) {
1032
                var geocoder = new google.maps.Geocoder();
1033
                var latlng = new google.maps.LatLng(-34.397, 150.644);
1034
                var myOptions = {
1035
                    zoom: 15,
1036
                    center: latlng,
1037
                    mapTypeControl: true,
1038
                    mapTypeControlOptions: {
1039
                        style: google.maps.MapTypeControlStyle.DROPDOWN_MENU
1040
                    },
1041
                    navigationControl: true,
1042
                    mapTypeId: google.maps.MapTypeId.ROADMAP
1043
                };
1044
1045
                map_'.$name.' = new google.maps.Map(document.getElementById("map_'.$name.'"), myOptions);
1046
1047
                var parameter = address ? { "address": address } : latLng ? { "latLng": latLng } : false;
1048
1049
                if (geocoder && parameter) {
1050
                    geocoder.geocode(parameter, function(results, status) {
1051
                        if (status == google.maps.GeocoderStatus.OK) {
1052
                            if (status != google.maps.GeocoderStatus.ZERO_RESULTS) {
1053
                                map_'.$name.'.setCenter(results[0].geometry.location);
1054
                                if (!address) {
1055
                                    $("#'.$name.'").val(results[0].formatted_address);
1056
                                }
1057
                                var infowindow = new google.maps.InfoWindow({
1058
                                    content: "<b>" + $("#'.$name.'").val() + "</b>",
1059
                                    size: new google.maps.Size(150, 50)
1060
                                });
1061
1062
                                var marker = new google.maps.Marker({
1063
                                    position: results[0].geometry.location,
1064
                                    map: map_'.$name.',
1065
                                    title: $("#'.$name.'").val()
1066
                                });
1067
                                google.maps.event.addListener(marker, "click", function() {
1068
                                    infowindow.open(map_'.$name.', marker);
1069
                                });
1070
                            } else {
1071
                                alert("' . get_lang("NotFound").'");
1072
                            }
1073
                        } else {
1074
                            alert("Geocode ' . get_lang('Error').': '.get_lang("AddressField").' '.get_lang("NotFound").'");
1075
                        }
1076
                    });
1077
                }
1078
            }
1079
        </script>
1080
        ');
1081
    }
1082
1083
    /**
1084
     * @param string $name
1085
     * @param string $label
1086
     *
1087
     * @return mixed
1088
     */
1089
    public function addButtonAdvancedSettings($name, $label = '')
1090
    {
1091
        $label = !empty($label) ? $label : get_lang('AdvancedParameters');
1092
1093
        return $this->addElement('advanced_settings', $name, $label);
1094
    }
1095
1096
    /**
1097
     * Adds a progress loading image to the form.
1098
     *
1099
     */
1100
    public function addProgress($delay = 2, $label = '')
1101
    {
1102
        if (empty($label)) {
1103
            $label = get_lang('PleaseStandBy');
1104
        }
1105
        $this->with_progress_bar = true;
1106
        $id = $this->getAttribute('id');
1107
1108
        $this->updateAttributes("onsubmit=\"javascript: addProgress('".$id."')\"");
1109
        $this->addHtml('<script language="javascript" src="'.api_get_path(WEB_LIBRARY_PATH).'javascript/upload.js" type="text/javascript"></script>');
1110
    }
1111
1112
    /**
1113
     * This function has been created for avoiding changes directly within QuickForm class.
1114
     * When we use it, the element is threated as 'required' to be dealt during validation.
1115
     * @param array $elements The array of elements
1116
     * @param string $message The message displayed
1117
     */
1118
    public function add_multiple_required_rule($elements, $message)
1119
    {
1120
        $this->_required[] = $elements[0];
1121
        $this->addRule($elements, $message, 'multiple_required');
1122
    }
1123
1124
    /**
1125
     * Displays the form.
1126
     * If an element in the form didn't validate, an error message is showed
1127
     * asking the user to complete the form.
1128
     */
1129
    public function display()
1130
    {
1131
        echo $this->returnForm();
1132
    }
1133
1134
    /**
1135
     * Returns the HTML code of the form.
1136
     * @return string $return_value HTML code of the form
1137
     */
1138
    public function returnForm()
1139
    {
1140
        $returnValue = '';
1141
1142
        /** @var HTML_QuickForm_element $element */
1143
        foreach ($this->_elements as $element) {
1144
            $elementError = parent::getElementError($element->getName());
1145
            if (!is_null($elementError)) {
1146
                $returnValue .= Display::return_message($elementError, 'warning').'<br />';
1147
                break;
1148
            }
1149
        }
1150
1151
        $returnValue .= parent::toHtml();
1152
        // Add div-element which is to hold the progress bar
1153
        $id = $this->getAttribute('id');
1154
        if (isset($this->with_progress_bar) && $this->with_progress_bar) {
1155
            // Deprecated
1156
            // $icon = Display::return_icon('progress_bar.gif');
1157
1158
            // @todo improve UI
1159
            $returnValue .= '<br />
1160
1161
            <div id="loading_div_'.$id.'" class="loading_div" style="display:none;margin-left:40%; margin-top:10px; height:50px;">
1162
                <div class="wobblebar-loader"></div>
1163
            </div>
1164
            ';
1165
        }
1166
1167
        return $returnValue;
1168
    }
1169
1170
    /**
1171
     * Returns the HTML code of the form.
1172
     * If an element in the form didn't validate, an error message is showed
1173
     * asking the user to complete the form.
1174
     *
1175
     * @return string $return_value HTML code of the form
1176
     *
1177
     * @author Patrick Cool <[email protected]>, Ghent University, august 2006
1178
     * @author Julio Montoya
1179
     * @deprecated use returnForm()
1180
     */
1181
    public function return_form()
1182
    {
1183
        return $this->returnForm();
1184
    }
1185
1186
    /**
1187
     * Create a form validator based on an array of form data:
1188
     *
1189
     *         array(
1190
     *             'name' => 'zombie_report_parameters',    //optional
1191
     *             'method' => 'GET',                       //optional
1192
     *             'items' => array(
1193
     *                 array(
1194
     *                     'name' => 'ceiling',
1195
     *                     'label' => 'Ceiling',            //optional
1196
     *                     'type' => 'date',
1197
     *                     'default' => date()              //optional
1198
     *                 ),
1199
     *                 array(
1200
     *                     'name' => 'active_only',
1201
     *                     'label' => 'ActiveOnly',
1202
     *                     'type' => 'checkbox',
1203
     *                     'default' => true
1204
     *                 ),
1205
     *                 array(
1206
     *                     'name' => 'submit_button',
1207
     *                     'type' => 'style_submit_button',
1208
     *                     'value' => get_lang('Search'),
1209
     *                     'attributes' => array('class' => 'search')
1210
     *                 )
1211
     *             )
1212
     *         );
1213
     *
1214
     * @param array $form_data
1215
     * @deprecated use normal FormValidator construct
1216
     *
1217
     * @return FormValidator
1218
     */
1219
    public static function create($form_data)
1220
    {
1221
        if (empty($form_data)) {
1222
            return null;
1223
        }
1224
        $form_name = isset($form_data['name']) ? $form_data['name'] : 'form';
1225
        $form_method = isset($form_data['method']) ? $form_data['method'] : 'POST';
1226
        $form_action = isset($form_data['action']) ? $form_data['action'] : '';
1227
        $form_target = isset($form_data['target']) ? $form_data['target'] : '';
1228
        $form_attributes = isset($form_data['attributes']) ? $form_data['attributes'] : null;
1229
        $form_track_submit = isset($form_data['track_submit']) ? $form_data['track_submit'] : true;
1230
        $reset = null;
1231
        $result = new FormValidator($form_name, $form_method, $form_action, $form_target, $form_attributes, $form_track_submit);
0 ignored issues
show
Bug introduced by
It seems like $form_track_submit can also be of type true; however, parameter $layout of FormValidator::__construct() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1231
        $result = new FormValidator($form_name, $form_method, $form_action, $form_target, $form_attributes, /** @scrutinizer ignore-type */ $form_track_submit);
Loading history...
1232
1233
        $defaults = array();
1234
        foreach ($form_data['items'] as $item) {
1235
            $name = $item['name'];
1236
            $type = isset($item['type']) ? $item['type'] : 'text';
1237
            $label = isset($item['label']) ? $item['label'] : '';
1238
            if ($type == 'wysiwyg') {
1239
                $element = $result->addHtmlEditor($name, $label);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $element is correct as $result->addHtmlEditor($name, $label) targeting FormValidator::addHtmlEditor() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
1240
            } else {
1241
                $element = $result->addElement($type, $name, $label);
1242
            }
1243
            if (isset($item['attributes'])) {
1244
                $attributes = $item['attributes'];
1245
                $element->setAttributes($attributes);
1246
            }
1247
            if (isset($item['value'])) {
1248
                $value = $item['value'];
1249
                $element->setValue($value);
1250
            }
1251
            if (isset($item['default'])) {
1252
                $defaults[$name] = $item['default'];
1253
            }
1254
            if (isset($item['rules'])) {
1255
                $rules = $item['rules'];
1256
                foreach ($rules as $rule) {
1257
                    $message = $rule['message'];
1258
                    $type = $rule['type'];
1259
                    $format = isset($rule['format']) ? $rule['format'] : null;
1260
                    $validation = isset($rule['validation']) ? $rule['validation'] : 'server';
1261
                    $force = isset($rule['force']) ? $rule['force'] : false;
1262
                    $result->addRule($name, $message, $type, $format, $validation, $reset, $force);
1263
                }
1264
            }
1265
        }
1266
        $result->setDefaults($defaults);
1267
1268
        return $result;
1269
    }
1270
1271
    /**
1272
     * @return HTML_QuickForm_Renderer_Default
1273
     */
1274
    public static function getDefaultRenderer()
1275
    {
1276
        return
1277
            isset($GLOBALS['_HTML_QuickForm_default_renderer']) ?
1278
                $GLOBALS['_HTML_QuickForm_default_renderer'] : null;
1279
    }
1280
1281
    /**
1282
     * Adds a input of type url to the form.
1283
     * @param string $name The label for the form-element
1284
     * @param string $label The element name
1285
     * @param bool $required Optional. Is the form-element required (default=true)
1286
     * @param array $attributes Optional. List of attributes for the form-element
1287
     */
1288
    public function addUrl($name, $label, $required = true, $attributes = [])
1289
    {
1290
        $this->addElement('url', $name, $label, $attributes);
1291
        $this->applyFilter($name, 'trim');
1292
        $this->addRule($name, get_lang('InsertAValidUrl'), 'url');
1293
1294
        if ($required) {
1295
            $this->addRule($name, get_lang('ThisFieldIsRequired'), 'required');
1296
        }
1297
    }
1298
1299
    /**
1300
     * Adds a text field for letters to the form.
1301
     * A trim-filter is attached to the field.
1302
     * @param string $name The element name
1303
     * @param string $label The label for the form-element
1304
     * @param bool $required Optional. Is the form-element required (default=true)
1305
     * @param array $attributes Optional. List of attributes for the form-element
1306
     */
1307
    public function addTextLettersOnly(
1308
        $name,
1309
        $label,
1310
        $required = false,
1311
        $attributes = []
1312
    ) {
1313
        $attributes = array_merge(
1314
            $attributes,
1315
            [
1316
                'pattern' => '[a-zA-ZñÑ]+',
1317
                'title' => get_lang('OnlyLetters')
1318
            ]
1319
        );
1320
1321
        $this->addElement(
1322
            'text',
1323
            $name,
1324
            [
1325
                $label,
1326
                get_lang('OnlyLetters')
1327
            ],
1328
            $attributes
1329
        );
1330
1331
        $this->applyFilter($name, 'trim');
1332
1333
        if ($required) {
1334
            $this->addRule($name, get_lang('ThisFieldIsRequired'), 'required');
1335
        }
1336
1337
        $this->addRule(
1338
            $name,
1339
            get_lang('OnlyLetters'),
1340
            'regex',
1341
            '/^[a-zA-ZñÑ]+$/'
1342
        );
1343
    }
1344
1345
    /**
1346
     * Adds a text field for alphanumeric characters to the form.
1347
     * A trim-filter is attached to the field.
1348
     * @param string $name The element name
1349
     * @param string $label The label for the form-element
1350
     * @param bool $required Optional. Is the form-element required (default=true)
1351
     * @param array $attributes Optional. List of attributes for the form-element
1352
     */
1353
    public function addTextAlphanumeric(
1354
        $name,
1355
        $label,
1356
        $required = false,
1357
        $attributes = []
1358
    ) {
1359
        $attributes = array_merge(
1360
            $attributes,
1361
            [
1362
                'pattern' => '[a-zA-Z0-9ñÑ]+',
1363
                'title' => get_lang('OnlyLettersAndNumbers')
1364
            ]
1365
        );
1366
1367
        $this->addElement(
1368
            'text',
1369
            $name,
1370
            [
1371
                $label,
1372
                get_lang('OnlyLettersAndNumbers')
1373
            ],
1374
            $attributes
1375
        );
1376
1377
        $this->applyFilter($name, 'trim');
1378
1379
        if ($required) {
1380
            $this->addRule($name, get_lang('ThisFieldIsRequired'), 'required');
1381
        }
1382
1383
        $this->addRule(
1384
            $name,
1385
            get_lang('OnlyLettersAndNumbers'),
1386
            'regex',
1387
            '/^[a-zA-Z0-9ÑÑ]+$/'
1388
        );
1389
    }
1390
1391
    /**
1392
     * @param string $name
1393
     * @param $label
1394
     * @param bool $required
1395
     * @param array $attributes
1396
     * @param bool $allowNegative
1397
     * @param integer $minValue
1398
     * @param null $maxValue
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $maxValue is correct as it would always require null to be passed?
Loading history...
1399
     */
1400
    public function addFloat(
1401
        $name,
1402
        $label,
1403
        $required = false,
1404
        $attributes = [],
1405
        $allowNegative = false,
1406
        $minValue = null,
1407
        $maxValue = null
1408
    ) {
1409
        $this->addElement(
1410
            'FloatNumber',
1411
            $name,
1412
            $label,
1413
            $attributes
1414
        );
1415
1416
        $this->applyFilter($name, 'trim');
1417
1418
        if ($required) {
1419
            $this->addRule($name, get_lang('ThisFieldIsRequired'), 'required');
1420
        }
1421
1422
        // Rule allows "," and "."
1423
        /*$this->addRule(
1424
            $name,
1425
            get_lang('OnlyNumbers'),
1426
            'regex',
1427
            '/(^-?\d\d*\.\d*$)|(^-?\d\d*$)|(^-?\.\d\d*$)|(^-?\d\d*\,\d*$)|(^-?\,\d\d*$)/'
1428
        );*/
1429
1430
        if ($allowNegative == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
1431
            $this->addRule(
1432
                $name,
1433
                get_lang('NegativeValue'),
1434
                'compare',
1435
                '>=',
1436
                'server',
1437
                false,
1438
                false,
1439
                0
1440
            );
1441
        }
1442
1443
        if (!is_null($minValue)) {
1444
            $this->addRule(
1445
                $name,
1446
                get_lang('UnderMin'),
1447
                'compare',
1448
                '>=',
1449
                'server',
1450
                false,
1451
                false,
1452
                $minValue
1453
            );
1454
        }
1455
1456
        if (!is_null($maxValue)) {
1457
            $this->addRule(
1458
                $name,
1459
                get_lang('OverMax'),
1460
                'compare',
1461
                '<=',
1462
                'server',
1463
                false,
1464
                false,
1465
                $maxValue
1466
            );
1467
        }
1468
    }
1469
1470
    /**
1471
     * Adds a text field for letters and spaces to the form.
1472
     * A trim-filter is attached to the field.
1473
     * @param string $name The element name
1474
     * @param string $label The label for the form-element
1475
     * @param bool $required Optional. Is the form-element required (default=true)
1476
     * @param array $attributes Optional. List of attributes for the form-element
1477
     */
1478
    public function addTextLettersAndSpaces(
1479
        $name,
1480
        $label,
1481
        $required = false,
1482
        $attributes = []
1483
    ) {
1484
        $attributes = array_merge(
1485
            $attributes,
1486
            [
1487
                'pattern' => '[a-zA-ZñÑ\s]+',
1488
                'title' => get_lang('OnlyLettersAndSpaces')
1489
            ]
1490
        );
1491
1492
        $this->addElement(
1493
            'text',
1494
            $name,
1495
            [
1496
                $label,
1497
                get_lang('OnlyLettersAndSpaces')
1498
            ],
1499
            $attributes
1500
        );
1501
1502
        $this->applyFilter($name, 'trim');
1503
1504
        if ($required) {
1505
            $this->addRule($name, get_lang('ThisFieldIsRequired'), 'required');
1506
        }
1507
1508
        $this->addRule(
1509
            $name,
1510
            get_lang('OnlyLettersAndSpaces'),
1511
            'regex',
1512
            '/^[a-zA-ZñÑ\s]+$/'
1513
        );
1514
    }
1515
1516
    /**
1517
     * Adds a text field for alphanumeric and spaces characters to the form.
1518
     * A trim-filter is attached to the field.
1519
     * @param string $name The element name
1520
     * @param string $label The label for the form-element
1521
     * @param bool $required Optional. Is the form-element required (default=true)
1522
     * @param array $attributes Optional. List of attributes for the form-element
1523
     */
1524
    public function addTextAlphanumericAndSpaces(
1525
        $name,
1526
        $label,
1527
        $required = false,
1528
        $attributes = []
1529
    ) {
1530
        $attributes = array_merge(
1531
            $attributes,
1532
            [
1533
                'pattern' => '[a-zA-Z0-9ñÑ\s]+',
1534
                'title' => get_lang('OnlyLettersAndNumbersAndSpaces')
1535
            ]
1536
        );
1537
1538
        $this->addElement(
1539
            'text',
1540
            $name,
1541
            [
1542
                $label,
1543
                get_lang('OnlyLettersAndNumbersAndSpaces')
1544
            ],
1545
            $attributes
1546
        );
1547
1548
        $this->applyFilter($name, 'trim');
1549
1550
        if ($required) {
1551
            $this->addRule($name, get_lang('ThisFieldIsRequired'), 'required');
1552
        }
1553
1554
        $this->addRule(
1555
            $name,
1556
            get_lang('OnlyLettersAndNumbersAndSpaces'),
1557
            'regex',
1558
            '/^[a-zA-Z0-9ñÑ\s]+$/'
1559
        );
1560
    }
1561
1562
    /**
1563
     * @param string $url
1564
     * @param string $urlToRedirect after upload redirect to this page
1565
     */
1566
    public function addMultipleUpload($url, $urlToRedirect = '')
1567
    {
1568
        $inputName = 'input_file_upload';
1569
        $this->addMultipleUploadJavascript($url, $inputName, $urlToRedirect);
1570
1571
        $this->addHtml('
1572
            <div class="description-upload">
1573
            '.get_lang('ClickToSelectOrDragAndDropMultipleFilesOnTheUploadField').'
1574
            </div>
1575
            <span class="btn btn-success fileinput-button">
1576
                <i class="glyphicon glyphicon-plus"></i>
1577
                <span>'.get_lang('AddFiles').'</span>
1578
                <!-- The file input field used as target for the file upload widget -->
1579
                <input id="'.$inputName.'" type="file" name="files[]" multiple>
1580
            </span>
1581
            <div id="dropzone">
1582
                <div class="button-load">
1583
                '.get_lang('UploadFiles').'
1584
                </div>
1585
            </div>
1586
            <br />
1587
            <!-- The global progress bar -->
1588
            <div id="progress" class="progress">
1589
                <div class="progress-bar progress-bar-success"></div>
1590
            </div>
1591
            <div id="files" class="files"></div>
1592
        ');
1593
    }
1594
1595
    /**
1596
     *
1597
     * @param string $url page that will handle the upload
1598
     * @param string $inputName
1599
     * @param string $urlToRedirect
1600
     */
1601
    private function addMultipleUploadJavascript($url, $inputName, $urlToRedirect = '')
1602
    {
1603
        $redirectCondition = '';
1604
        if (!empty($urlToRedirect)) {
1605
            $redirectCondition = "window.location.replace('$urlToRedirect'); ";
1606
        }
1607
        $icon = Display::return_icon('file_txt.gif');
1608
        $this->addHtml("
1609
        <script>
1610
        $(function () {
1611
            'use strict';
1612
            $('#".$this->getAttribute('id')."').submit(function() {
1613
                return false;
1614
            });
1615
1616
            $('#dropzone').on('click', function() {
1617
                $('#".$inputName."').click();
1618
            });
1619
1620
            var url = '".$url."';
1621
            var uploadButton = $('<button/>')
1622
                .addClass('btn btn-primary')
1623
                .prop('disabled', true)
1624
                .text('".addslashes(get_lang('Loading'))."')
1625
                .on('click', function () {
1626
                    var \$this = $(this),
1627
                    data = \$this.data();
1628
1629
                    \$this
1630
                        .off('click')
1631
                        .text('".addslashes(get_lang('Cancel'))."')
1632
                        .on('click', function () {
1633
                            \$this.remove();
1634
                            data.abort();
1635
                        });
1636
                    data.submit().always(function () {
1637
                        \$this.remove();
1638
                    });
1639
                });               
1640
                
1641
            $('#".$inputName."').fileupload({
1642
                url: url,
1643
                dataType: 'json',
1644
                // Enable image resizing, except for Android and Opera,
1645
                // which actually support image resizing, but fail to
1646
                // send Blob objects via XHR requests:
1647
                disableImageResize: /Android(?!.*Chrome)|Opera/.test(window.navigator.userAgent),
1648
                previewMaxWidth: 50,
1649
                previewMaxHeight: 50,
1650
                previewCrop: true,
1651
                dropzone: $('#dropzone'),                                
1652
            }).on('fileuploadadd', function (e, data) {
1653
                data.context = $('<div class=\"row\" />').appendTo('#files');
1654
                $.each(data.files, function (index, file) {
1655
                    var node = $('<div class=\"col-sm-5 file_name\">').text(file.name);                    
1656
                    node.appendTo(data.context);
1657
                });
1658
            }).on('fileuploadprocessalways', function (e, data) {
1659
                var index = data.index,
1660
                    file = data.files[index],
1661
                    node = $(data.context.children()[index]);
1662
                if (file.preview) {
1663
                    data.context
1664
                        .prepend($('<div class=\"col-sm-2\">').html(file.preview))
1665
                    ;
1666
                } else {
1667
                    data.context
1668
                        .prepend($('<div class=\"col-sm-2\">').html('".$icon."'))
1669
                    ;
1670
                }
1671
                if (index + 1 === data.files.length) {
1672
                    data.context.find('button')
1673
                        .text('Upload')
1674
                        .prop('disabled', !!data.files.error);
1675
                }
1676
            }).on('fileuploadprogressall', function (e, data) {
1677
                var progress = parseInt(data.loaded / data.total * 100, 10);
1678
                $('#progress .progress-bar').css(
1679
                    'width',
1680
                    progress + '%'
1681
                );
1682
            }).on('fileuploaddone', function (e, data) {
1683
                $.each(data.result.files, function (index, file) {
1684
                    if (file.url) {
1685
                        var link = $('<a>')
1686
                            .attr({target: '_blank', class : 'panel-image'})
1687
                            .prop('href', file.url);
1688
                        $(data.context.children()[index]).parent().wrap(link);
1689
                        // Update file name with new one from Chamilo
1690
                        $(data.context.children()[index]).parent().find('.file_name').html(file.name);                        
1691
                        var successMessage = $('<div class=\"col-sm-3\">').html($('<span class=\"message-image-success\"/>').text('".addslashes(get_lang('UplUploadSucceeded'))."'));
1692
                        $(data.context.children()[index]).parent().append(successMessage);                    
1693
                    } else if (file.error) {
1694
                        var error = $('<div class=\"col-sm-3\">').html($('<span class=\"message-image-danger\"/>').text(file.error));
1695
                        $(data.context.children()[index]).parent().append(error);                        
1696
                    }
1697
                });                
1698
                $('#dropzone').removeClass('hover');                
1699
                ".$redirectCondition."
1700
            }).on('fileuploadfail', function (e, data) {
1701
                $.each(data.files, function (index) {
1702
                    var failedMessage = '" . addslashes(get_lang('UplUploadFailed'))."';
1703
                    var error = $('<div class=\"col-sm-3\">').html($('<span class=\"alert alert-danger\"/>').text(failedMessage));
1704
                    $(data.context.children()[index]).parent().append(error);
1705
                });
1706
                $('#dropzone').removeClass('hover');
1707
            }).prop('disabled', !$.support.fileInput).parent().addClass($.support.fileInput ? undefined : 'disabled');            
1708
            
1709
            $('#dropzone').on('dragover', function (e) {
1710
                // dragleave callback implementation                
1711
                $('#dropzone').addClass('hover');
1712
            });
1713
            
1714
            $('#dropzone').on('dragleave', function (e) {                
1715
                $('#dropzone').removeClass('hover');
1716
            });
1717
            $('.fileinput-button').hide();
1718
        });
1719
        </script>");
1720
    }
1721
1722
    /**
1723
     * @param string $elementName
1724
     * @param string $groupName if element is inside a group
1725
     * @throws Exception
1726
     */
1727
    public function addPasswordRule($elementName, $groupName = '')
1728
    {
1729
        // Constant defined in old config/profile.conf.php
1730
        if (CHECK_PASS_EASY_TO_FIND === true) {
1731
            $message = get_lang('PassTooEasy').': '.api_generate_password();
1732
1733
            if (!empty($groupName)) {
1734
                $groupObj = $this->getElement($groupName);
1735
1736
                if ($groupObj instanceof HTML_QuickForm_group) {
1737
                    $elementName = $groupObj->getElementName($elementName);
1738
1739
                    if ($elementName === false) {
1740
                        throw new Exception("The $groupName doesn't have the element $elementName");
1741
                    }
1742
1743
                    $this->_rules[$elementName][] = array(
1744
                        'type' => 'callback',
1745
                        'format' => 'api_check_password',
1746
                        'message' => $message,
1747
                        'validation' => '',
1748
                        'reset' => false,
1749
                        'group' => $groupName
1750
                    );
1751
                }
1752
            } else {
1753
                $this->addRule(
1754
                    $elementName,
1755
                    $message,
1756
                    'callback',
1757
                    'api_check_password'
1758
                );
1759
            }
1760
        }
1761
    }
1762
1763
    /**
1764
     * Add an element with user ID and avatar to the form.
1765
     * It needs a Chamilo\UserBundle\Entity\User as value. The exported value is the Chamilo\UserBundle\Entity\User ID
1766
     * @see \UserAvatar
1767
     * @param string $name
1768
     * @param string $label
1769
     * @param string $imageSize Optional. Small, medium or large image
1770
     * @param string $subtitle Optional. The subtitle for the field
1771
     * @return \UserAvatar
1772
     */
1773
    public function addUserAvatar($name, $label, $imageSize = 'small', $subtitle = '')
1774
    {
1775
        return $this->addElement('UserAvatar', $name, $label, ['image_size' => $imageSize, 'sub_title' => $subtitle]);
1776
    }
1777
}
1778
1779
/**
1780
 * Cleans HTML text filter
1781
 * @param string $html HTML to clean
1782
 * @param int $mode (optional)
1783
 * @return string The cleaned HTML
1784
 */
1785
function html_filter($html, $mode = NO_HTML)
1786
{
1787
    $allowed_tags = HTML_QuickForm_Rule_HTML::get_allowed_tags($mode);
1788
    $cleaned_html = kses($html, $allowed_tags);
1789
    return $cleaned_html;
1790
}
1791
1792
function html_filter_teacher($html)
1793
{
1794
    return html_filter($html, TEACHER_HTML);
1795
}
1796
1797
function html_filter_student($html)
1798
{
1799
    return html_filter($html, STUDENT_HTML);
1800
}
1801
1802
function html_filter_teacher_fullpage($html)
1803
{
1804
    return html_filter($html, TEACHER_HTML_FULLPAGE);
1805
}
1806
1807
function html_filter_student_fullpage($html)
1808
{
1809
    return html_filter($html, STUDENT_HTML_FULLPAGE);
1810
}
1811
1812
/**
1813
 * Cleans mobile phone number text
1814
 * @param string $mobilePhoneNumber Mobile phone number to clean
1815
 * @return string The cleaned mobile phone number
1816
 */
1817
function mobile_phone_number_filter($mobilePhoneNumber)
1818
{
1819
    $mobilePhoneNumber = str_replace(array('+', '(', ')'), '', $mobilePhoneNumber);
1820
1821
    return ltrim($mobilePhoneNumber, '0');
1822
}
1823