Passed
Push — master ( 190bd7...86c511 )
by Julito
09:39
created

FormValidator::addDateTimeRangePicker()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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

1339
        $result = new FormValidator($form_name, $form_method, $form_action, $form_target, $form_attributes, /** @scrutinizer ignore-type */ $form_track_submit);
Loading history...
1340
1341
        $defaults = [];
1342
        foreach ($form_data['items'] as $item) {
1343
            $name = $item['name'];
1344
            $type = isset($item['type']) ? $item['type'] : 'text';
1345
            $label = isset($item['label']) ? $item['label'] : '';
1346
            if ($type == 'wysiwyg') {
1347
                $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...
1348
            } else {
1349
                $element = $result->addElement($type, $name, $label);
1350
            }
1351
            if (isset($item['attributes'])) {
1352
                $attributes = $item['attributes'];
1353
                $element->setAttributes($attributes);
1354
            }
1355
            if (isset($item['value'])) {
1356
                $value = $item['value'];
1357
                $element->setValue($value);
1358
            }
1359
            if (isset($item['default'])) {
1360
                $defaults[$name] = $item['default'];
1361
            }
1362
            if (isset($item['rules'])) {
1363
                $rules = $item['rules'];
1364
                foreach ($rules as $rule) {
1365
                    $message = $rule['message'];
1366
                    $type = $rule['type'];
1367
                    $format = isset($rule['format']) ? $rule['format'] : null;
1368
                    $validation = isset($rule['validation']) ? $rule['validation'] : 'server';
1369
                    $force = isset($rule['force']) ? $rule['force'] : false;
1370
                    $result->addRule($name, $message, $type, $format, $validation, $reset, $force);
1371
                }
1372
            }
1373
        }
1374
        $result->setDefaults($defaults);
1375
1376
        return $result;
1377
    }
1378
1379
    /**
1380
     * @return HTML_QuickForm_Renderer_Default
1381
     */
1382
    public static function getDefaultRenderer()
1383
    {
1384
        return
1385
            isset($GLOBALS['_HTML_QuickForm_default_renderer']) ?
1386
                $GLOBALS['_HTML_QuickForm_default_renderer'] : null;
1387
    }
1388
1389
    /**
1390
     * Adds a input of type url to the form.
1391
     *
1392
     * @param string $name       The label for the form-element
1393
     * @param string $label      The element name
1394
     * @param bool   $required   Optional. Is the form-element required (default=true)
1395
     * @param array  $attributes Optional. List of attributes for the form-element
1396
     */
1397
    public function addUrl($name, $label, $required = true, $attributes = [])
1398
    {
1399
        $this->addElement('url', $name, $label, $attributes);
1400
        $this->applyFilter($name, 'trim');
1401
        $this->addRule($name, get_lang('InsertAValidUrl'), 'url');
1402
1403
        if ($required) {
1404
            $this->addRule($name, get_lang('ThisFieldIsRequired'), 'required');
1405
        }
1406
    }
1407
1408
    /**
1409
     * Adds a text field for letters to the form.
1410
     * A trim-filter is attached to the field.
1411
     *
1412
     * @param string $name       The element name
1413
     * @param string $label      The label for the form-element
1414
     * @param bool   $required   Optional. Is the form-element required (default=true)
1415
     * @param array  $attributes Optional. List of attributes for the form-element
1416
     */
1417
    public function addTextLettersOnly(
1418
        $name,
1419
        $label,
1420
        $required = false,
1421
        $attributes = []
1422
    ) {
1423
        $attributes = array_merge(
1424
            $attributes,
1425
            [
1426
                'pattern' => '[a-zA-ZñÑ]+',
1427
                'title' => get_lang('OnlyLetters'),
1428
            ]
1429
        );
1430
1431
        $this->addElement(
1432
            'text',
1433
            $name,
1434
            [
1435
                $label,
1436
                get_lang('OnlyLetters'),
1437
            ],
1438
            $attributes
1439
        );
1440
1441
        $this->applyFilter($name, 'trim');
1442
1443
        if ($required) {
1444
            $this->addRule($name, get_lang('ThisFieldIsRequired'), 'required');
1445
        }
1446
1447
        $this->addRule(
1448
            $name,
1449
            get_lang('OnlyLetters'),
1450
            'regex',
1451
            '/^[a-zA-ZñÑ]+$/'
1452
        );
1453
    }
1454
1455
    /**
1456
     * Adds a text field for alphanumeric characters to the form.
1457
     * A trim-filter is attached to the field.
1458
     *
1459
     * @param string $name       The element name
1460
     * @param string $label      The label for the form-element
1461
     * @param bool   $required   Optional. Is the form-element required (default=true)
1462
     * @param array  $attributes Optional. List of attributes for the form-element
1463
     */
1464
    public function addTextAlphanumeric(
1465
        $name,
1466
        $label,
1467
        $required = false,
1468
        $attributes = []
1469
    ) {
1470
        $attributes = array_merge(
1471
            $attributes,
1472
            [
1473
                'pattern' => '[a-zA-Z0-9ñÑ]+',
1474
                'title' => get_lang('OnlyLettersAndNumbers'),
1475
            ]
1476
        );
1477
1478
        $this->addElement(
1479
            'text',
1480
            $name,
1481
            [
1482
                $label,
1483
                get_lang('OnlyLettersAndNumbers'),
1484
            ],
1485
            $attributes
1486
        );
1487
1488
        $this->applyFilter($name, 'trim');
1489
1490
        if ($required) {
1491
            $this->addRule($name, get_lang('ThisFieldIsRequired'), 'required');
1492
        }
1493
1494
        $this->addRule(
1495
            $name,
1496
            get_lang('OnlyLettersAndNumbers'),
1497
            'regex',
1498
            '/^[a-zA-Z0-9ÑÑ]+$/'
1499
        );
1500
    }
1501
1502
    /**
1503
     * @param string $name
1504
     * @param $label
1505
     * @param bool  $required
1506
     * @param array $attributes
1507
     * @param bool  $allowNegative
1508
     * @param int   $minValue
1509
     * @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...
1510
     */
1511
    public function addFloat(
1512
        $name,
1513
        $label,
1514
        $required = false,
1515
        $attributes = [],
1516
        $allowNegative = false,
1517
        $minValue = null,
1518
        $maxValue = null
1519
    ) {
1520
        $this->addElement(
1521
            'FloatNumber',
1522
            $name,
1523
            $label,
1524
            $attributes
1525
        );
1526
1527
        $this->applyFilter($name, 'trim');
1528
1529
        if ($required) {
1530
            $this->addRule($name, get_lang('ThisFieldIsRequired'), 'required');
1531
        }
1532
1533
        // Rule allows "," and "."
1534
        /*$this->addRule(
1535
            $name,
1536
            get_lang('OnlyNumbers'),
1537
            'regex',
1538
            '/(^-?\d\d*\.\d*$)|(^-?\d\d*$)|(^-?\.\d\d*$)|(^-?\d\d*\,\d*$)|(^-?\,\d\d*$)/'
1539
        );*/
1540
1541
        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...
1542
            $this->addRule(
1543
                $name,
1544
                get_lang('NegativeValue'),
1545
                'compare',
1546
                '>=',
1547
                'server',
1548
                false,
1549
                false,
1550
                0
1551
            );
1552
        }
1553
1554
        if (!is_null($minValue)) {
1555
            $this->addRule(
1556
                $name,
1557
                get_lang('UnderMin'),
1558
                'compare',
1559
                '>=',
1560
                'server',
1561
                false,
1562
                false,
1563
                $minValue
1564
            );
1565
        }
1566
1567
        if (!is_null($maxValue)) {
1568
            $this->addRule(
1569
                $name,
1570
                get_lang('OverMax'),
1571
                'compare',
1572
                '<=',
1573
                'server',
1574
                false,
1575
                false,
1576
                $maxValue
1577
            );
1578
        }
1579
    }
1580
1581
    /**
1582
     * Adds a text field for letters and spaces to the form.
1583
     * A trim-filter is attached to the field.
1584
     *
1585
     * @param string $name       The element name
1586
     * @param string $label      The label for the form-element
1587
     * @param bool   $required   Optional. Is the form-element required (default=true)
1588
     * @param array  $attributes Optional. List of attributes for the form-element
1589
     */
1590
    public function addTextLettersAndSpaces(
1591
        $name,
1592
        $label,
1593
        $required = false,
1594
        $attributes = []
1595
    ) {
1596
        $attributes = array_merge(
1597
            $attributes,
1598
            [
1599
                'pattern' => '[a-zA-ZñÑ\s]+',
1600
                'title' => get_lang('OnlyLettersAndSpaces'),
1601
            ]
1602
        );
1603
1604
        $this->addElement(
1605
            'text',
1606
            $name,
1607
            [
1608
                $label,
1609
                get_lang('OnlyLettersAndSpaces'),
1610
            ],
1611
            $attributes
1612
        );
1613
1614
        $this->applyFilter($name, 'trim');
1615
1616
        if ($required) {
1617
            $this->addRule($name, get_lang('ThisFieldIsRequired'), 'required');
1618
        }
1619
1620
        $this->addRule(
1621
            $name,
1622
            get_lang('OnlyLettersAndSpaces'),
1623
            'regex',
1624
            '/^[a-zA-ZñÑ\s]+$/'
1625
        );
1626
    }
1627
1628
    /**
1629
     * Adds a text field for alphanumeric and spaces characters to the form.
1630
     * A trim-filter is attached to the field.
1631
     *
1632
     * @param string $name       The element name
1633
     * @param string $label      The label for the form-element
1634
     * @param bool   $required   Optional. Is the form-element required (default=true)
1635
     * @param array  $attributes Optional. List of attributes for the form-element
1636
     */
1637
    public function addTextAlphanumericAndSpaces(
1638
        $name,
1639
        $label,
1640
        $required = false,
1641
        $attributes = []
1642
    ) {
1643
        $attributes = array_merge(
1644
            $attributes,
1645
            [
1646
                'pattern' => '[a-zA-Z0-9ñÑ\s]+',
1647
                'title' => get_lang('OnlyLettersAndNumbersAndSpaces'),
1648
            ]
1649
        );
1650
1651
        $this->addElement(
1652
            'text',
1653
            $name,
1654
            [
1655
                $label,
1656
                get_lang('OnlyLettersAndNumbersAndSpaces'),
1657
            ],
1658
            $attributes
1659
        );
1660
1661
        $this->applyFilter($name, 'trim');
1662
1663
        if ($required) {
1664
            $this->addRule($name, get_lang('ThisFieldIsRequired'), 'required');
1665
        }
1666
1667
        $this->addRule(
1668
            $name,
1669
            get_lang('OnlyLettersAndNumbersAndSpaces'),
1670
            'regex',
1671
            '/^[a-zA-Z0-9ñÑ\s]+$/'
1672
        );
1673
    }
1674
1675
    /**
1676
     * @param string $url
1677
     * @param string $urlToRedirect after upload redirect to this page
1678
     */
1679
    public function addMultipleUpload($url, $urlToRedirect = '')
1680
    {
1681
        $inputName = 'input_file_upload';
1682
        $this->addMultipleUploadJavascript($url, $inputName, $urlToRedirect);
1683
1684
        $this->addHtml('
1685
            <div class="description-upload">
1686
            '.get_lang('ClickToSelectOrDragAndDropMultipleFilesOnTheUploadField').'
1687
            </div>
1688
            <span class="btn btn-success fileinput-button">
1689
                <i class="glyphicon glyphicon-plus"></i>
1690
                <span>'.get_lang('AddFiles').'</span>
1691
                <!-- The file input field used as target for the file upload widget -->
1692
                <input id="'.$inputName.'" type="file" name="files[]" multiple>
1693
            </span>
1694
            <div id="dropzone">
1695
                <div class="button-load">
1696
                '.get_lang('UploadFiles').'
1697
                </div>
1698
            </div>
1699
            <br />
1700
            <!-- The global progress bar -->
1701
            <div id="progress" class="progress">
1702
                <div class="progress-bar progress-bar-success"></div>
1703
            </div>
1704
            <div id="files" class="files"></div>
1705
        ');
1706
    }
1707
1708
    /**
1709
     * @param string $elementName
1710
     * @param string $groupName   if element is inside a group
1711
     *
1712
     * @throws Exception
1713
     */
1714
    public function addPasswordRule($elementName, $groupName = '')
1715
    {
1716
        if (api_get_setting('security.check_password') == 'true') {
1717
            $message = get_lang('PassTooEasy').': '.api_generate_password();
1718
1719
            if (!empty($groupName)) {
1720
                $groupObj = $this->getElement($groupName);
1721
1722
                if ($groupObj instanceof HTML_QuickForm_group) {
1723
                    $elementName = $groupObj->getElementName($elementName);
1724
1725
                    if ($elementName === false) {
1726
                        throw new Exception("The $groupName doesn't have the element $elementName");
1727
                    }
1728
1729
                    $this->_rules[$elementName][] = [
0 ignored issues
show
Bug Best Practice introduced by
The property _rules does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
1730
                        'type' => 'callback',
1731
                        'format' => 'api_check_password',
1732
                        'message' => $message,
1733
                        'validation' => '',
1734
                        'reset' => false,
1735
                        'group' => $groupName,
1736
                    ];
1737
                }
1738
            } else {
1739
                $this->addRule(
1740
                    $elementName,
1741
                    $message,
1742
                    'callback',
1743
                    'api_check_password'
1744
                );
1745
            }
1746
        }
1747
    }
1748
1749
    /**
1750
     * Add an element with user ID and avatar to the form.
1751
     * It needs a Chamilo\UserBundle\Entity\User as value. The exported value is the Chamilo\UserBundle\Entity\User ID.
1752
     *
1753
     * @see \UserAvatar
1754
     *
1755
     * @param string $name
1756
     * @param string $label
1757
     * @param string $imageSize Optional. Small, medium or large image
1758
     * @param string $subtitle  Optional. The subtitle for the field
1759
     *
1760
     * @return \UserAvatar
1761
     */
1762
    public function addUserAvatar($name, $label, $imageSize = 'small', $subtitle = '')
1763
    {
1764
        return $this->addElement('UserAvatar', $name, $label, ['image_size' => $imageSize, 'sub_title' => $subtitle]);
1765
    }
1766
1767
    /**
1768
     * @param string $url           page that will handle the upload
1769
     * @param string $inputName
1770
     * @param string $urlToRedirect
1771
     */
1772
    private function addMultipleUploadJavascript($url, $inputName, $urlToRedirect = '')
1773
    {
1774
        $redirectCondition = '';
1775
        if (!empty($urlToRedirect)) {
1776
            $redirectCondition = "window.location.replace('$urlToRedirect'); ";
1777
        }
1778
        $icon = Display::return_icon('file_txt.gif');
1779
        $this->addHtml("
1780
        <script>
1781
        $(function () {
1782
            'use strict';
1783
            $('#".$this->getAttribute('id')."').submit(function() {
1784
                return false;
1785
            });
1786
1787
            $('#dropzone').on('click', function() {
1788
                $('#".$inputName."').click();
1789
            });
1790
1791
            var url = '".$url."';
1792
            var uploadButton = $('<button/>')
1793
                .addClass('btn btn-primary')
1794
                .prop('disabled', true)
1795
                .text('".addslashes(get_lang('Loading'))."')
1796
                .on('click', function () {
1797
                    var \$this = $(this),
1798
                    data = \$this.data();
1799
                    \$this
1800
                        .off('click')
1801
                        .text('".addslashes(get_lang('Cancel'))."')
1802
                        .on('click', function () {
1803
                            \$this.remove();
1804
                            data.abort();
1805
                        });
1806
                    data.submit().always(function () {
1807
                        \$this.remove();
1808
                    });
1809
                });               
1810
                
1811
            $('#".$inputName."').fileupload({
1812
                url: url,
1813
                dataType: 'json',
1814
                // Enable image resizing, except for Android and Opera,
1815
                // which actually support image resizing, but fail to
1816
                // send Blob objects via XHR requests:
1817
                disableImageResize: /Android(?!.*Chrome)|Opera/.test(window.navigator.userAgent),
1818
                previewMaxWidth: 50,
1819
                previewMaxHeight: 50,
1820
                previewCrop: true,
1821
                dropzone: $('#dropzone'),                                
1822
            }).on('fileuploadadd', function (e, data) {                
1823
                data.context = $('<div class=\"row\" />').appendTo('#files');
1824
                $.each(data.files, function (index, file) {
1825
                    var node = $('<div class=\"col-sm-5 file_name\">').text(file.name);                    
1826
                    node.appendTo(data.context);
1827
                });
1828
            }).on('fileuploadprocessalways', function (e, data) {
1829
                var index = data.index,
1830
                    file = data.files[index],
1831
                    node = $(data.context.children()[index]);
1832
                if (file.preview) {
1833
                    data.context.prepend($('<div class=\"col-sm-2\">').html(file.preview));
1834
                } else {
1835
                    data.context.prepend($('<div class=\"col-sm-2\">').html('".$icon."'));
1836
                }
1837
                if (index + 1 === data.files.length) {
1838
                    data.context.find('button')
1839
                        .text('Upload')
1840
                        .prop('disabled', !!data.files.error);
1841
                }
1842
            }).on('fileuploadprogressall', function (e, data) {
1843
                var progress = parseInt(data.loaded / data.total * 100, 10);
1844
                $('#progress .progress-bar').css(
1845
                    'width',
1846
                    progress + '%'
1847
                );
1848
            }).on('fileuploaddone', function (e, data) {
1849
                $.each(data.result.files, function (index, file) {
1850
                    if (file.error) {
1851
                        var link = $('<div>')
1852
                            .attr({class : 'panel-image'})                            ;
1853
                        $(data.context.children()[index]).parent().wrap(link);
1854
                        // Update file name with new one from Chamilo
1855
                        $(data.context.children()[index]).parent().find('.file_name').html(file.name);
1856
                        var message = $('<div class=\"col-sm-3\">').html(
1857
                            $('<span class=\"message-image-danger\"/>').text(file.error)
1858
                        );
1859
                        $(data.context.children()[index]).parent().append(message);
1860
1861
                        return;
1862
                    }
1863
                    if (file.url) {
1864
                        var link = $('<a>')
1865
                            .attr({target: '_blank', class : 'panel-image'})
1866
                            .prop('href', file.url);
1867
                        $(data.context.children()[index]).parent().wrap(link);
1868
                    }
1869
                    // Update file name with new one from Chamilo
1870
                    $(data.context.children()[index]).parent().find('.file_name').html(file.name);
1871
                    var message = $('<div class=\"col-sm-3\">').html(
1872
                        $('<span class=\"message-image-success\"/>').text('".addslashes(get_lang('UplUploadSucceeded'))."')
1873
                    );
1874
                    $(data.context.children()[index]).parent().append(message);
1875
                });                
1876
                $('#dropzone').removeClass('hover');                
1877
                ".$redirectCondition."
1878
            }).on('fileuploadfail', function (e, data) {
1879
                $.each(data.files, function (index) {
1880
                    var failedMessage = '".addslashes(get_lang('UplUploadFailed'))."';
1881
                    var error = $('<div class=\"col-sm-3\">').html(
1882
                        $('<span class=\"alert alert-danger\"/>').text(failedMessage)
1883
                    );
1884
                    $(data.context.children()[index]).parent().append(error);
1885
                });
1886
                $('#dropzone').removeClass('hover');
1887
            }).prop('disabled', !$.support.fileInput).parent().addClass($.support.fileInput ? undefined : 'disabled');           
1888
            
1889
            $('#dropzone').on('dragover', function (e) {
1890
                // dragleave callback implementation                
1891
                $('#dropzone').addClass('hover');
1892
            });
1893
            
1894
            $('#dropzone').on('dragleave', function (e) {                
1895
                $('#dropzone').removeClass('hover');
1896
            });
1897
            $('.fileinput-button').hide();
1898
        });
1899
        </script>");
1900
    }
1901
}
1902
1903
/**
1904
 * Cleans HTML text filter.
1905
 *
1906
 * @param string $html HTML to clean
1907
 * @param int    $mode (optional)
1908
 *
1909
 * @return string The cleaned HTML
1910
 */
1911
function html_filter($html, $mode = NO_HTML)
1912
{
1913
    $allowed_tags = HTML_QuickForm_Rule_HTML::get_allowed_tags($mode);
1914
    $cleaned_html = kses($html, $allowed_tags);
0 ignored issues
show
Bug introduced by
The function kses was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

1914
    $cleaned_html = /** @scrutinizer ignore-call */ kses($html, $allowed_tags);
Loading history...
1915
1916
    return $cleaned_html;
1917
}
1918
1919
function html_filter_teacher($html)
1920
{
1921
    return html_filter($html, TEACHER_HTML);
1922
}
1923
1924
function html_filter_student($html)
1925
{
1926
    return html_filter($html, STUDENT_HTML);
1927
}
1928
1929
function html_filter_teacher_fullpage($html)
1930
{
1931
    return html_filter($html, TEACHER_HTML_FULLPAGE);
1932
}
1933
1934
function html_filter_student_fullpage($html)
1935
{
1936
    return html_filter($html, STUDENT_HTML_FULLPAGE);
1937
}
1938
1939
/**
1940
 * Cleans mobile phone number text.
1941
 *
1942
 * @param string $mobilePhoneNumber Mobile phone number to clean
1943
 *
1944
 * @return string The cleaned mobile phone number
1945
 */
1946
function mobile_phone_number_filter($mobilePhoneNumber)
1947
{
1948
    $mobilePhoneNumber = str_replace(['+', '(', ')'], '', $mobilePhoneNumber);
1949
1950
    return ltrim($mobilePhoneNumber, '0');
1951
}
1952