Passed
Push — master ( c8b87f...30f75c )
by Julito
11:29
created

ExtraField::set_extra_fields_in_form()   F

Complexity

Conditions 139
Paths 3

Size

Total Lines 859
Code Lines 537

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 139
eloc 537
c 0
b 0
f 0
nc 3
nop 16
dl 0
loc 859
rs 3.3333

How to fix   Long Method    Complexity    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
use Chamilo\CoreBundle\Entity\Asset;
6
use Chamilo\CoreBundle\Entity\ExtraField as EntityExtraField;
7
use Chamilo\CoreBundle\Entity\ExtraFieldRelTag;
8
use Chamilo\CoreBundle\Entity\Tag;
9
use Chamilo\CoreBundle\Framework\Container;
10
11
class ExtraField extends Model
12
{
13
    public const FIELD_TYPE_TEXT = 1;
14
    public const FIELD_TYPE_TEXTAREA = 2;
15
    public const FIELD_TYPE_RADIO = 3;
16
    public const FIELD_TYPE_SELECT = 4;
17
    public const FIELD_TYPE_SELECT_MULTIPLE = 5;
18
    public const FIELD_TYPE_DATE = 6;
19
    public const FIELD_TYPE_DATETIME = 7;
20
    public const FIELD_TYPE_DOUBLE_SELECT = 8;
21
    public const FIELD_TYPE_DIVIDER = 9;
22
    public const FIELD_TYPE_TAG = 10;
23
    public const FIELD_TYPE_TIMEZONE = 11;
24
    public const FIELD_TYPE_SOCIAL_PROFILE = 12;
25
    public const FIELD_TYPE_CHECKBOX = 13;
26
    public const FIELD_TYPE_MOBILE_PHONE_NUMBER = 14;
27
    public const FIELD_TYPE_INTEGER = 15;
28
    public const FIELD_TYPE_FILE_IMAGE = 16;
29
    public const FIELD_TYPE_FLOAT = 17;
30
    public const FIELD_TYPE_FILE = 18;
31
    public const FIELD_TYPE_VIDEO_URL = 19;
32
    public const FIELD_TYPE_LETTERS_ONLY = 20;
33
    public const FIELD_TYPE_ALPHANUMERIC = 21;
34
    public const FIELD_TYPE_LETTERS_SPACE = 22;
35
    public const FIELD_TYPE_ALPHANUMERIC_SPACE = 23;
36
    public const FIELD_TYPE_GEOLOCALIZATION = 24;
37
    public const FIELD_TYPE_GEOLOCALIZATION_COORDINATES = 25;
38
    public const FIELD_TYPE_SELECT_WITH_TEXT_FIELD = 26;
39
    public const FIELD_TYPE_TRIPLE_SELECT = 27;
40
41
    public $columns = [
42
        'id',
43
        'field_type',
44
        'variable',
45
        'description',
46
        'display_text',
47
        'default_value',
48
        'field_order',
49
        'visible_to_self',
50
        'visible_to_others',
51
        'changeable',
52
        'filter',
53
        'extra_field_type',
54
        //Enable this when field_loggeable is introduced as a table field (2.0)
55
        //'field_loggeable',
56
        'created_at',
57
    ];
58
59
    public $ops = [
60
        'eq' => '=', //equal
61
        'ne' => '<>', //not equal
62
        'lt' => '<', //less than
63
        'le' => '<=', //less than or equal
64
        'gt' => '>', //greater than
65
        'ge' => '>=', //greater than or equal
66
        'bw' => 'LIKE', //begins with
67
        'bn' => 'NOT LIKE', //doesn't begin with
68
        'in' => 'LIKE', //is in
69
        'ni' => 'NOT LIKE', //is not in
70
        'ew' => 'LIKE', //ends with
71
        'en' => 'NOT LIKE', //doesn't end with
72
        'cn' => 'LIKE', //contains
73
        'nc' => 'NOT LIKE',  //doesn't contain
74
    ];
75
76
    public $type = 'user';
77
    public $pageName;
78
    public $pageUrl;
79
    public $extraFieldType = 0;
80
    public $table_field_options;
81
    public $table_field_values;
82
    public $table_field_tag;
83
    public $table_field_rel_tag;
84
    public $handler_id;
85
    public $primaryKey;
86
87
    /**
88
     * @param string $type
89
     */
90
    public function __construct($type)
91
    {
92
        parent::__construct();
93
94
        $this->type = $type;
95
        $this->table = Database::get_main_table(TABLE_EXTRA_FIELD);
96
        $this->table_field_options = Database::get_main_table(TABLE_EXTRA_FIELD_OPTIONS);
97
        $this->table_field_values = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
98
        $this->table_field_tag = Database::get_main_table(TABLE_MAIN_TAG);
99
        $this->table_field_rel_tag = Database::get_main_table(TABLE_MAIN_EXTRA_FIELD_REL_TAG);
100
        $this->handler_id = 'item_id';
101
        $this->extraFieldType = self::getExtraFieldTypeFromString($this->type);
102
103
        switch ($this->type) {
104
            case 'session':
105
            case 'user':
106
            case 'calendar_event':
107
            case 'course':
108
                $this->primaryKey = 'id';
109
                break;
110
        }
111
112
        $this->pageUrl = 'extra_fields.php?type='.$this->type;
113
        // Example QuestionFields
114
        $this->pageName = ucwords($this->type).'Fields';
115
    }
116
117
    public static function getTypeList(): array
118
    {
119
        return [
120
            'calendar_event' => EntityExtraField::CALENDAR_FIELD_TYPE,
121
            'course' => EntityExtraField::COURSE_FIELD_TYPE,
122
            'user' => EntityExtraField::USER_FIELD_TYPE,
123
            'session' => EntityExtraField::SESSION_FIELD_TYPE,
124
            'exercise' => EntityExtraField::EXERCISE_FIELD_TYPE,
125
            'question' => EntityExtraField::QUESTION_FIELD_TYPE,
126
            'lp' => EntityExtraField::LP_FIELD_TYPE,
127
            'lp_item' => EntityExtraField::LP_ITEM_FIELD_TYPE,
128
            'skill' => EntityExtraField::SKILL_FIELD_TYPE,
129
            'work' => EntityExtraField::WORK_FIELD_TYPE,
130
            'career' => EntityExtraField::CAREER_FIELD_TYPE,
131
            'user_certificate' => EntityExtraField::USER_CERTIFICATE,
132
            'survey' => EntityExtraField::SURVEY_FIELD_TYPE,
133
            'scheduled_announcement' => EntityExtraField::SCHEDULED_ANNOUNCEMENT,
134
            'terms_and_condition' => EntityExtraField::TERMS_AND_CONDITION_TYPE,
135
            'forum_category' => EntityExtraField::FORUM_CATEGORY_TYPE,
136
            'forum_post' => EntityExtraField::FORUM_POST_TYPE,
137
            'track_exercise' => EntityExtraField::TRACK_EXERCISE_FIELD_TYPE,
138
            'portfolio' => EntityExtraField::PORTFOLIO_TYPE,
139
            'lp_view' => EntityExtraField::LP_VIEW_TYPE,
140
        ];
141
    }
142
143
    public static function getExtraFieldTypeFromString($extraFieldTypeInString): string
144
    {
145
        return self::getTypeList()[$extraFieldTypeInString];
146
    }
147
148
    public static function getExtraFieldTypeFromInt($extraFieldTypeInt)
149
    {
150
        $reversed = array_flip(self::getTypeList());
151
152
        return $reversed[$extraFieldTypeInt];
153
    }
154
155
    /**
156
     * @return array
157
     */
158
    public static function getValidExtraFieldTypes()
159
    {
160
        $result = [
161
            'user',
162
            'course',
163
            'session',
164
            'question',
165
            'lp',
166
            'calendar_event',
167
            'lp_item',
168
            'skill',
169
            'work',
170
            'career',
171
            'user_certificate',
172
            'survey',
173
            'terms_and_condition',
174
            'forum_category',
175
            'forum_post',
176
            'exercise',
177
            'track_exercise',
178
            'lp_view',
179
        ];
180
181
        if (api_get_configuration_value('allow_scheduled_announcements')) {
182
            $result[] = 'scheduled_announcement';
183
        }
184
        if (api_get_configuration_value('allow_portfolio_tool')) {
185
            $result[] = 'portfolio';
186
        }
187
        sort($result);
188
189
        return $result;
190
    }
191
192
    /**
193
     * Converts a string like this:
194
     * France:Paris;Bretagne;Marseille;Lyon|Belgique:Bruxelles;Namur;Liège;Bruges|Peru:Lima;Piura;
195
     * into
196
     * array(
197
     *   'France' =>
198
     *      array('Paris', 'Bretagne', 'Marseille'),
199
     *   'Belgique' =>
200
     *      array('Namur', 'Liège')
201
     * ), etc.
202
     *
203
     * @param string $string
204
     *
205
     * @return array
206
     */
207
    public static function extra_field_double_select_convert_string_to_array($string)
208
    {
209
        $options = explode('|', $string);
210
        $options_parsed = [];
211
        $id = 0;
212
213
        if (!empty($options)) {
214
            foreach ($options as $sub_options) {
215
                $options = explode(':', $sub_options);
216
                $sub_sub_options = isset($options[1]) ? explode(';', $options[1]) : [];
217
                $options_parsed[$id] = [
218
                    'label' => $options[0],
219
                    'options' => $sub_sub_options,
220
                ];
221
                $id++;
222
            }
223
        }
224
225
        return $options_parsed;
226
    }
227
228
    /**
229
     * @param $string
230
     *
231
     * @return array
232
     */
233
    public static function tripleSelectConvertStringToArray($string)
234
    {
235
        $options = [];
236
        foreach (explode('|', $string) as $i => $item0) {
237
            $level1 = explode('\\', $item0);
238
239
            foreach ($level1 as $j => $item1) {
240
                if (0 === $j) {
241
                    $options[] = ['label' => $item1, 'options' => []];
242
243
                    continue;
244
                }
245
246
                foreach (explode(':', $item1) as $k => $item2) {
247
                    if (0 === $k) {
248
                        $options[$i]['options'][] = ['label' => $item2, 'options' => []];
249
250
                        continue;
251
                    }
252
253
                    $options[$i]['options'][$j - 1]['options'][] = explode(';', $item2);
254
                }
255
            }
256
        }
257
258
        array_walk_recursive(
259
            $options,
260
            function (&$item) {
261
                $item = trim($item);
262
            }
263
        );
264
265
        return $options;
266
    }
267
268
    /**
269
     * @param array $options the result of the get_field_options_by_field() array
270
     *
271
     * @return string
272
     */
273
    public static function extra_field_double_select_convert_array_to_string($options)
274
    {
275
        $string = null;
276
        $optionsParsed = self::extra_field_double_select_convert_array_to_ordered_array($options);
277
278
        if (!empty($optionsParsed)) {
279
            foreach ($optionsParsed as $option) {
280
                foreach ($option as $key => $item) {
281
                    $string .= $item['display_text'];
282
                    if (0 == $key) {
283
                        $string .= ':';
284
                    } else {
285
                        if (isset($option[$key + 1])) {
286
                            $string .= ';';
287
                        }
288
                    }
289
                }
290
                $string .= '|';
291
            }
292
        }
293
294
        if (!empty($string)) {
295
            $string = substr($string, 0, strlen($string) - 1);
296
        }
297
298
        return $string;
299
    }
300
301
    /**
302
     * @param array $options The result of the get_field_options_by_field() array
303
     *
304
     * @return string
305
     */
306
    public static function extraFieldSelectWithTextConvertArrayToString(array $options)
307
    {
308
        $parsedOptions = self::extra_field_double_select_convert_array_to_ordered_array($options);
309
310
        if (empty($parsedOptions)) {
311
            return '';
312
        }
313
314
        $string = '';
315
        foreach ($parsedOptions as $options) {
316
            $option = current($options);
317
            $string .= $option['display_text'];
318
            $string .= '|';
319
        }
320
321
        return rtrim($string, '|');
322
    }
323
324
    /**
325
     * @return string
326
     */
327
    public static function tripleSelectConvertArrayToString(array $options)
328
    {
329
        $parsedOptions = self::tripleSelectConvertArrayToOrderedArray($options);
330
        $string = '';
331
        foreach ($parsedOptions['level1'] as $item1) {
332
            $string .= $item1['display_text'];
333
            $level2 = self::getOptionsFromTripleSelect($parsedOptions['level2'], $item1['id']);
334
335
            foreach ($level2 as $item2) {
336
                $string .= '\\'.$item2['display_text'].':';
337
                $level3 = self::getOptionsFromTripleSelect($parsedOptions['level3'], $item2['id']);
338
339
                $string .= implode(';', array_column($level3, 'display_text'));
340
            }
341
342
            $string .= '|';
343
        }
344
345
        return trim($string, '\\|;');
346
    }
347
348
    /**
349
     * @param string $variable
350
     * @param string $dataValue
351
     *
352
     * @return string
353
     */
354
    public static function getLocalizationJavascript($variable, $dataValue)
355
    {
356
        $dataValue = addslashes($dataValue);
357
        $html = "<script>
358
            $(function() {
359
                if (typeof google === 'object') {
360
                    var address = '$dataValue';
361
                    initializeGeo{$variable}(address, false);
362
363
                    $('#geolocalization_extra_{$variable}').on('click', function() {
364
                        var address = $('#{$variable}').val();
365
                        initializeGeo{$variable}(address, false);
366
                        return false;
367
                    });
368
369
                    $('#myLocation_extra_{$variable}').on('click', function() {
370
                        myLocation{$variable}();
371
                        return false;
372
                    });
373
374
                    // When clicking enter
375
                    $('#{$variable}').keypress(function(event) {
376
                        if (event.which == 13) {
377
                            $('#geolocalization_extra_{$variable}').click();
378
                            return false;
379
                        }
380
                    });
381
382
                    // On focus out update city
383
                    $('#{$variable}').focusout(function() {
384
                        $('#geolocalization_extra_{$variable}').click();
385
                        return false;
386
                    });
387
388
                    return;
389
                }
390
391
                $('#map_extra_{$variable}')
392
                    .html('<div class=\"alert alert-info\">"
393
            .addslashes(get_lang('YouNeedToActivateTheGoogleMapsPluginInAdminPlatformToSeeTheMap'))
394
            ."</div>');
395
            });
396
397
            function myLocation{$variable}()
398
            {
399
                if (navigator.geolocation) {
400
                    var geoPosition = function(position) {
401
                        var lat = position.coords.latitude;
402
                        var lng = position.coords.longitude;
403
                        var latLng = new google.maps.LatLng(lat, lng);
404
                        initializeGeo{$variable}(false, latLng);
405
                    };
406
407
                    var geoError = function(error) {
408
                        alert('Geocode ".get_lang('Error').": ' + error);
409
                    };
410
411
                    var geoOptions = {
412
                        enableHighAccuracy: true
413
                    };
414
                    navigator.geolocation.getCurrentPosition(geoPosition, geoError, geoOptions);
415
                }
416
            }
417
418
            function initializeGeo{$variable}(address, latLng)
419
            {
420
                var geocoder = new google.maps.Geocoder();
421
                var latlng = new google.maps.LatLng(-34.397, 150.644);
422
                var myOptions = {
423
                    zoom: 15,
424
                    center: latlng,
425
                    mapTypeControl: true,
426
                    mapTypeControlOptions: {
427
                        style: google.maps.MapTypeControlStyle.DROPDOWN_MENU
428
                    },
429
                    navigationControl: true,
430
                    mapTypeId: google.maps.MapTypeId.ROADMAP
431
                };
432
433
                map_{$variable} = new google.maps.Map(
434
                    document.getElementById('map_extra_{$variable}'),
435
                    myOptions
436
                );
437
438
                var parameter = address ? {'address': address} : latLng ? {'latLng': latLng} : false;
439
440
                if (geocoder && parameter) {
441
                    geocoder.geocode(parameter, function(results, status) {
442
                        if (status == google.maps.GeocoderStatus.OK) {
443
                            if (status != google.maps.GeocoderStatus.ZERO_RESULTS) {
444
                                map_{$variable}.setCenter(results[0].geometry.location);
445
446
                                // get city and country
447
                                var defaultAddress = results[0].formatted_address;
448
                                var city = '';
449
                                var country = '';
450
451
                                for (var i=0; i<results[0].address_components.length; i++) {
452
                                    if (results[0].address_components[i].types[0] == \"locality\") {
453
                                        //this is the object you are looking for City
454
                                        city = results[0].address_components[i];
455
                                    }
456
                                    /*if (results[j].address_components[i].types[0] == \"administrative_area_level_1\") {
457
                                        //this is the object you are looking for State
458
                                        region = results[0].address_components[i];
459
                                    }*/
460
                                    if (results[0].address_components[i].types[0] == \"country\") {
461
                                        //this is the object you are looking for
462
                                        country = results[0].address_components[i];
463
                                    }
464
                                }
465
466
                                if (city && city.long_name && country && country.long_name) {
467
                                    defaultAddress = city.long_name + ', ' + country.long_name;
468
                                }
469
                                $('#{$variable}').val(defaultAddress);
470
                                $('#{$variable}_coordinates').val(
471
                                    results[0].geometry.location.lat()+','+results[0].geometry.location.lng()
472
                                );
473
474
                                var infowindow = new google.maps.InfoWindow({
475
                                    content: '<b>' + $('#extra_{$variable}').val() + '</b>',
476
                                    size: new google.maps.Size(150, 50)
477
                                });
478
479
                                var marker = new google.maps.Marker({
480
                                    position: results[0].geometry.location,
481
                                    map: map_{$variable},
482
                                    title: $('#extra_{$variable}').val()
483
                                });
484
                                google.maps.event.addListener(marker, 'click', function() {
485
                                    infowindow.open(map_{$variable}, marker);
486
                                });
487
                            } else {
488
                                alert('".get_lang('NotFound')."');
489
                            }
490
                        } else {
491
                            alert('Geocode ".get_lang('Error').': '.get_lang('AddressField').' '.get_lang('NotFound')."');
492
                        }
493
                    });
494
                }
495
            }
496
            </script>";
497
498
        return $html;
499
    }
500
501
    /**
502
     * @param string $variable
503
     * @param string $text
504
     *
505
     * @return string
506
     */
507
    public static function getLocalizationInput($variable, $text)
508
    {
509
        $textHelp = $text;
510
        if (is_array($text)) {
511
            $textHelp = $text[0];
512
        }
513
        return '
514
                <div class="form-group">
515
                    <label for="geolocalization_extra_'.$variable.'"
516
                        class="col-sm-2 control-label"></label>
517
                    <div class="col-sm-8">
518
                        <button class="btn btn-default"
519
                            id="geolocalization_extra_'.$variable.'"
520
                            name="geolocalization_extra_'.$variable.'"
521
                            type="submit">
522
                            <em class="fa fa-map-marker"></em> '.get_lang('SearchGeolocalization').'
523
                        </button>
524
                        <button class="btn btn-default" id="myLocation_extra_'.$variable.'"
525
                            name="myLocation_extra_'.$variable.'"
526
                            type="submit">
527
                            <em class="fa fa-crosshairs"></em> '.get_lang('MyLocation').'
528
                        </button>
529
                    </div>
530
                </div>
531
                <div class="form-group">
532
                    <label for="map_extra_'.$variable.'" class="col-sm-2 control-label">
533
                        '.$textHelp.' - '.get_lang('Map').'
534
                    </label>
535
                    <div class="col-sm-8">
536
                        <div name="map_extra_'.$variable.'"
537
                            id="map_extra_'.$variable.'" style="width:100%; height:300px;">
538
                        </div>
539
                    </div>
540
                </div>
541
            ';
542
    }
543
544
    /**
545
     * @return int
546
     */
547
    public function get_count()
548
    {
549
        $em = Database::getManager();
550
        $query = $em->getRepository(EntityExtraField::class)->createQueryBuilder('e');
551
        $query->select('count(e.id)');
552
        $query->where('e.extraFieldType = :type');
553
        $query->setParameter('type', $this->getExtraFieldType());
554
555
        return $query->getQuery()->getSingleScalarResult();
556
    }
557
558
    /**
559
     * @return int
560
     */
561
    public function getExtraFieldType()
562
    {
563
        return (int) $this->extraFieldType;
564
    }
565
566
    /**
567
     * @param string $sidx
568
     * @param string $sord
569
     * @param int    $start
570
     * @param int    $limit
571
     *
572
     * @return array
573
     */
574
    public function getAllGrid($sidx, $sord, $start, $limit)
575
    {
576
        switch ($sidx) {
577
            case 'field_order':
578
                $sidx = 'e.fieldOrder';
579
                break;
580
            case 'variable':
581
                $sidx = 'e.variable';
582
                break;
583
            case 'display_text':
584
                $sidx = 'e.displayText';
585
                break;
586
            case 'changeable':
587
                $sidx = 'e.changeable';
588
                break;
589
            case 'visible_to_self':
590
                $sidx = 'e.visibleToSelf';
591
                break;
592
            case 'visible_to_others':
593
                $sidx = 'e.visibleToOthers';
594
                break;
595
            case 'filter':
596
                $sidx = 'e.filter';
597
                break;
598
        }
599
        $em = Database::getManager();
600
        $query = $em->getRepository(EntityExtraField::class)->createQueryBuilder('e');
601
        $query->select('e')
602
            ->where('e.extraFieldType = :type')
603
            ->setParameter('type', $this->getExtraFieldType())
604
            ->orderBy($sidx, $sord)
605
            ->setFirstResult($start)
606
            ->setMaxResults($limit);
607
608
        return $query->getQuery()->getArrayResult();
609
    }
610
611
    /**
612
     * Get all the field info for tags.
613
     *
614
     * @param string $variable
615
     *
616
     * @return array|bool
617
     */
618
    public function get_handler_field_info_by_tags($variable)
619
    {
620
        $variable = Database::escape_string($variable);
621
        $sql = "SELECT * FROM {$this->table}
622
                WHERE
623
                    variable = '$variable' AND
624
                    extra_field_type = $this->extraFieldType";
625
        $result = Database::query($sql);
626
        $extraFieldRepo = Container::getExtraFieldRepository();
627
        if (Database::num_rows($result)) {
628
            $row = Database::fetch_array($result, 'ASSOC');
629
            $extraFieldId = $row['id'];
630
            /** @var \Chamilo\CoreBundle\Entity\ExtraField $extraField */
631
            $extraField = $extraFieldRepo->find($extraFieldId);
632
            $row['display_text'] = $extraField->getDisplayText();
633
634
            // All the tags of the field
635
            $sql = "SELECT * FROM $this->table_field_tag
636
                    WHERE field_id='".$extraFieldId."'
637
                    ORDER BY id ASC";
638
            $result = Database::query($sql);
639
            while ($option = Database::fetch_array($result, 'ASSOC')) {
640
                $row['options'][$option['id']] = $option;
641
            }
642
643
            return $row;
644
        }
645
646
        return false;
647
    }
648
649
    /**
650
     * @param int $fieldId
651
     *
652
     * @return array|bool
653
     */
654
    public function getFieldInfoByFieldId($fieldId)
655
    {
656
        $fieldId = (int) $fieldId;
657
        $sql = "SELECT * FROM {$this->table}
658
                WHERE
659
                    id = '$fieldId' AND
660
                    extra_field_type = $this->extraFieldType";
661
        $result = Database::query($sql);
662
        if (Database::num_rows($result)) {
663
            $row = Database::fetch_array($result, 'ASSOC');
664
665
            // All the options of the field
666
            $sql = "SELECT * FROM $this->table_field_options
667
                    WHERE field_id='".$fieldId."'
668
                    ORDER BY option_order ASC";
669
            $result = Database::query($sql);
670
            while ($option = Database::fetch_array($result)) {
671
                $row['options'][$option['id']] = $option;
672
            }
673
674
            return $row;
675
        } else {
676
            return false;
677
        }
678
    }
679
680
    /**
681
     * Add elements to a form.
682
     *
683
     * @param FormValidator $form                            The form object to which to attach this element
684
     * @param int           $itemId                          The item (course, user, session, etc) this extra_field is
685
     *                                                       linked to
686
     * @param array         $exclude                         Variables of extra field to exclude
687
     * @param bool          $filter                          Whether to get only the fields with the "filter" flag set
688
     *                                                       to 1 (true) or not (false)
689
     * @param bool          $useTagAsSelect                  Whether to show tag fields as select drop-down or not
690
     * @param array         $showOnlyTheseFields             Limit the extra fields shown to just the list given here
691
     * @param array         $orderFields                     An array containing the names of the fields shown, in the
692
     *                                                       right order
693
     * @param array         $extraData
694
     * @param bool          $orderDependingDefaults
695
     * @param bool          $adminPermissions
696
     * @param array         $separateExtraMultipleSelect
697
     * @param array         $customLabelsExtraMultipleSelect
698
     * @param bool          $addEmptyOptionSelects
699
     * @param array         $introductionTextList
700
     * @param array         $requiredFields
701
     * @param bool          $hideGeoLocalizationDetails
702
     *
703
     * @throws Exception
704
     *
705
     * @return array|bool If relevant, returns a one-element array with JS code to be added to the page HTML headers.
706
     *                    Returns false if the form object was not given
707
     */
708
    public function addElements(
709
        $form,
710
        $itemId = 0,
711
        $exclude = [],
712
        $filter = false,
713
        $useTagAsSelect = false,
714
        $showOnlyTheseFields = [],
715
        $orderFields = [],
716
        $extraData = [],
717
        $orderDependingDefaults = false,
718
        $adminPermissions = false,
719
        $separateExtraMultipleSelect = [],
720
        $customLabelsExtraMultipleSelect = [],
721
        $addEmptyOptionSelects = false,
722
        $introductionTextList = [],
723
        $requiredFields = [],
724
        $hideGeoLocalizationDetails = false,
725
        $help = false
726
    ) {
727
        if (empty($form)) {
728
            return false;
729
        }
730
731
        $itemId = (int) $itemId;
732
        $form->addHidden('item_id', $itemId);
733
        $extraData = false;
734
        if (!empty($itemId)) {
735
            $extraData = $this->get_handler_extra_data($itemId);
736
            if (!empty($showOnlyTheseFields)) {
737
                $setData = [];
738
                foreach ($showOnlyTheseFields as $variable) {
739
                    $extraName = 'extra_'.$variable;
740
                    if (in_array($extraName, array_keys($extraData))) {
741
                        $setData[$extraName] = $extraData[$extraName];
742
                    }
743
                }
744
                $form->setDefaults($setData);
745
            } else {
746
                $form->setDefaults($extraData);
747
            }
748
        }
749
750
        $conditions = [];
751
        if ($filter) {
752
            $conditions = ['filter = ?' => 1];
753
        }
754
755
        $extraFields = $this->get_all($conditions, 'option_order');
756
        $extra = $this->set_extra_fields_in_form(
757
            $form,
758
            $extraData,
759
            $adminPermissions,
760
            $extraFields,
761
            $itemId,
762
            $exclude,
763
            $useTagAsSelect,
764
            $showOnlyTheseFields,
765
            $orderFields,
766
            $orderDependingDefaults,
767
            $separateExtraMultipleSelect,
768
            $customLabelsExtraMultipleSelect,
769
            $addEmptyOptionSelects,
770
            $introductionTextList,
771
            $hideGeoLocalizationDetails,
772
            $help
773
        );
774
775
        if (!empty($requiredFields)) {
776
            /** @var HTML_QuickForm_input $element */
777
            foreach ($form->getElements() as $element) {
778
                $name = str_replace('extra_', '', $element->getName());
779
                if (in_array($name, $requiredFields)) {
780
                    $form->setRequired($element);
781
                }
782
            }
783
        }
784
785
        return $extra;
786
    }
787
788
    /**
789
     * Return an array of all the extra fields available for this item.
790
     *
791
     * @param int $itemId (session_id, question_id, course id)
792
     *
793
     * @return array
794
     */
795
    public function get_handler_extra_data($itemId)
796
    {
797
        if (empty($itemId)) {
798
            return [];
799
        }
800
801
        $extra_data = [];
802
        $fields = $this->get_all();
803
        $field_values = new ExtraFieldValue($this->type);
804
805
        if (!empty($fields)) {
806
            foreach ($fields as $field) {
807
                $field_value = $fieldValueArray = $field_values->get_values_by_handler_and_field_id(
808
                    $itemId,
809
                    $field['id']
810
                );
811
812
                if (self::FIELD_TYPE_TAG == $field['field_type']) {
813
                    $tags = UserManager::get_user_tags_to_string(
814
                        $itemId,
815
                        $field['id'],
816
                        false
817
                    );
818
                    $extra_data['extra_'.$field['variable']] = $tags;
819
820
                    continue;
821
                }
822
823
                if ($field_value) {
824
                    $variable = $field['variable'];
825
                    $field_value = $field_value['value'];
826
                    switch ($field['field_type']) {
827
                        case self::FIELD_TYPE_FILE_IMAGE:
828
                        case self::FIELD_TYPE_FILE:
829
                            // Get asset id
830
                            $extra_data['extra_'.$field['variable']] = $fieldValueArray['asset_id'] ?? 0;
831
                            break;
832
                        case self::FIELD_TYPE_TAG:
833
                            $tags = UserManager::get_user_tags_to_string(
834
                                $itemId,
835
                                $field['id'],
836
                                false
837
                            );
838
839
                            $extra_data['extra_'.$field['variable']] = $tags;
840
                            break;
841
                        case self::FIELD_TYPE_DOUBLE_SELECT:
842
                        case self::FIELD_TYPE_SELECT_WITH_TEXT_FIELD:
843
                            $selected_options = explode('::', $field_value);
844
                            $firstOption = isset($selected_options[0]) ? $selected_options[0] : '';
845
                            $secondOption = isset($selected_options[1]) ? $selected_options[1] : '';
846
                            $extra_data['extra_'.$field['variable']]['extra_'.$field['variable']] = $firstOption;
847
                            $extra_data['extra_'.$field['variable']]['extra_'.$field['variable'].'_second'] = $secondOption;
848
849
                            break;
850
                        case self::FIELD_TYPE_SELECT_MULTIPLE:
851
                            $field_value = explode(';', $field_value);
852
                            $extra_data['extra_'.$field['variable']] = $field_value;
853
                            break;
854
                        case self::FIELD_TYPE_RADIO:
855
                            $extra_data['extra_'.$field['variable']]['extra_'.$field['variable']] = $field_value;
856
                            break;
857
                        case self::FIELD_TYPE_TRIPLE_SELECT:
858
                            [$level1, $level2, $level3] = explode(';', $field_value);
859
860
                            $extra_data["extra_$variable"]["extra_$variable"] = $level1;
861
                            $extra_data["extra_$variable"]["extra_{$variable}_second"] = $level2;
862
                            $extra_data["extra_$variable"]["extra_{$variable}_third"] = $level3;
863
                            break;
864
                        default:
865
                            $extra_data['extra_'.$field['variable']] = $field_value;
866
                            break;
867
                    }
868
                } else {
869
                    // Set default values
870
                    if (isset($field['field_default_value']) &&
871
                        !empty($field['field_default_value'])
872
                    ) {
873
                        $extra_data['extra_'.$field['variable']] = $field['field_default_value'];
874
                    }
875
                }
876
            }
877
        }
878
879
        return $extra_data;
880
    }
881
882
    /**
883
     * Get an array of all the values from the extra_field and extra_field_options tables
884
     * based on the current object's type.
885
     *
886
     * @param array $options
887
     * @param null  $order_field_options_by
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $order_field_options_by is correct as it would always require null to be passed?
Loading history...
888
     *
889
     * @return array
890
     */
891
    public function get_all($options = [], $order_field_options_by = null)
892
    {
893
        $options = Database::parse_conditions(['where' => $options]);
894
895
        if (empty($options)) {
896
            $options .= ' WHERE extra_field_type = '.$this->extraFieldType;
897
        } else {
898
            $options .= ' AND extra_field_type = '.$this->extraFieldType;
899
        }
900
901
        $sql = "SELECT * FROM $this->table
902
                $options
903
                ORDER BY field_order ASC
904
        ";
905
906
        $result = Database::query($sql);
907
        $extraFields = Database::store_result($result, 'ASSOC');
908
909
        $extraFieldRepo = Container::getExtraFieldRepository();
910
        $option = new ExtraFieldOption($this->type);
911
        if (!empty($extraFields)) {
912
            foreach ($extraFields as &$extraField) {
913
                $extraFieldId = $extraField['id'];
914
                /** @var \Chamilo\CoreBundle\Entity\ExtraField $field */
915
                $field = $extraFieldRepo->find($extraFieldId);
916
                $extraField['display_text'] = $field->getDisplayText();
917
                $extraField['options'] = $option->get_field_options_by_field(
918
                    $extraField['id'],
919
                    false,
920
                    $order_field_options_by
921
                );
922
            }
923
        }
924
925
        return $extraFields;
926
    }
927
928
    /**
929
     * Add an element that matches the given extra field to the given $form object.
930
     *
931
     * @param FormValidator $form                The form these fields are to be attached to
932
     * @param array         $extraData
933
     * @param bool          $adminPermissions    Whether the display is considered without edition limits (true) or not
934
     *                                           (false)
935
     * @param array         $extra
936
     * @param int           $itemId              The item (course, user, session, etc) this extra_field is attached to
937
     * @param array         $exclude             Extra fields to be skipped, by textual ID
938
     * @param bool          $useTagAsSelect      Whether to show tag fields as select drop-down or not
939
     * @param array         $showOnlyTheseFields Limit the extra fields shown to just the list given here
940
     * @param array         $orderFields         An array containing the names of the fields shown, in the right order
941
     *
942
     * @throws Exception
943
     *
944
     * @return array If relevant, returns a one-element array with JS code to be added to the page HTML headers
945
     */
946
    public function set_extra_fields_in_form(
947
        $form,
948
        $extraData,
949
        $adminPermissions = false,
950
        $extra = [],
951
        $itemId = null,
952
        $exclude = [],
953
        $useTagAsSelect = false,
954
        $showOnlyTheseFields = [],
955
        $orderFields = [],
956
        $orderDependingDefaults = false,
957
        $separateExtraMultipleSelect = [],
958
        $customLabelsExtraMultipleSelect = [],
959
        $addEmptyOptionSelects = false,
960
        $introductionTextList = [],
961
        $hideGeoLocalizationDetails = false,
962
        $help = false
963
    ) {
964
        $jquery_ready_content = null;
965
966
        $assetRepo = Container::getAssetRepository();
967
        $extraFieldRepo = Container::getExtraFieldRepository();
968
969
        if (!empty($extra)) {
970
            $newOrder = [];
971
            if (!empty($orderFields)) {
972
                foreach ($orderFields as $order) {
973
                    foreach ($extra as $field_details) {
974
                        if ($order == $field_details['variable']) {
975
                            $newOrder[] = $field_details;
976
                        }
977
                    }
978
                }
979
                $extra = $newOrder;
980
            }
981
982
            foreach ($extra as $field_details) {
983
                $variable = $field_details['variable'];
984
                if (!empty($showOnlyTheseFields)) {
985
                    if (!in_array($variable, $showOnlyTheseFields)) {
986
                        continue;
987
                    }
988
                }
989
990
                // Getting default value id if is set
991
                $defaultValueId = null;
992
                if (isset($field_details['options']) && !empty($field_details['options'])) {
993
                    $valueToFind = null;
994
                    if (isset($field_details['field_default_value'])) {
995
                        $valueToFind = $field_details['field_default_value'];
996
                    }
997
                    // If a value is found we override the default value
998
                    if (isset($extraData['extra_'.$variable])) {
999
                        $valueToFind = $extraData['extra_'.$variable];
1000
                    }
1001
1002
                    foreach ($field_details['options'] as $option) {
1003
                        if ($option['option_value'] == $valueToFind) {
1004
                            $defaultValueId = $option['id'];
1005
                        }
1006
                    }
1007
                }
1008
1009
                if (!$adminPermissions) {
1010
                    if (0 == $field_details['visible_to_self']) {
1011
                        continue;
1012
                    }
1013
1014
                    if (in_array($variable, $exclude)) {
1015
                        continue;
1016
                    }
1017
                }
1018
1019
                if (!empty($introductionTextList) &&
1020
                    in_array($variable, array_keys($introductionTextList))
1021
                ) {
1022
                    $form->addHtml($introductionTextList[$variable]);
1023
                }
1024
1025
                $freezeElement = false;
1026
                if (!$adminPermissions) {
1027
                    $freezeElement = 0 == $field_details['visible_to_self'] || 0 == $field_details['changeable'];
1028
                }
1029
1030
                //$translatedDisplayText = $field_details['display_text'];
1031
                /** @var \Chamilo\CoreBundle\Entity\ExtraField $extraField */
1032
                $extraField = $extraFieldRepo->find($field_details['id']);
1033
                $translatedDisplayText = $extraField->getDisplayText();
1034
1035
                $translatedDisplayHelpText = '';
1036
                if ($help) {
1037
                    $translatedDisplayHelpText .= get_lang($field_details['display_text'].'Help');
1038
                }
1039
1040
                if (!empty($translatedDisplayText)) {
1041
                    if (!empty($translatedDisplayHelpText)) {
1042
                        // In this case, exceptionally, display_text is an array
1043
                        // which is then treated by display_form()
1044
                        $field_details['display_text'] = [$translatedDisplayText, $translatedDisplayHelpText];
1045
                    } else {
1046
                        // We have an helper text, use it
1047
                        $field_details['display_text'] = $translatedDisplayText;
1048
                    }
1049
                }
1050
1051
                switch ($field_details['field_type']) {
1052
                    case self::FIELD_TYPE_TEXT:
1053
                        $form->addElement(
1054
                            'text',
1055
                            'extra_'.$variable,
1056
                            $field_details['display_text'],
1057
                            [
1058
                                'id' => 'extra_'.$variable,
1059
                            ]
1060
                        );
1061
                        $form->applyFilter(
1062
                            'extra_'.$variable,
1063
                            'stripslashes'
1064
                        );
1065
                        $form->applyFilter(
1066
                            'extra_'.$variable,
1067
                            'trim'
1068
                        );
1069
                        if ($freezeElement) {
1070
                            $form->freeze('extra_'.$variable);
1071
                        }
1072
                        break;
1073
                    case self::FIELD_TYPE_TEXTAREA:
1074
                        $form->addHtmlEditor(
1075
                            'extra_'.$variable,
1076
                            $field_details['display_text'],
1077
                            false,
1078
                            false,
1079
                            [
1080
                                'ToolbarSet' => 'Profile',
1081
                                'Width' => '100%',
1082
                                'Height' => '130',
1083
                                'id' => 'extra_'.$variable,
1084
                            ]
1085
                        );
1086
                        $form->applyFilter('extra_'.$variable, 'stripslashes');
1087
                        $form->applyFilter('extra_'.$variable, 'trim');
1088
                        if ($freezeElement) {
1089
                            $form->freeze('extra_'.$variable);
1090
                        }
1091
                        break;
1092
                    case self::FIELD_TYPE_RADIO:
1093
                        $group = [];
1094
                        if (isset($field_details['options']) &&
1095
                            !empty($field_details['options'])
1096
                        ) {
1097
                            foreach ($field_details['options'] as $option_details) {
1098
                                $options[$option_details['option_value']] = $option_details['display_text'];
1099
                                $group[] = $form->createElement(
1100
                                    'radio',
1101
                                    'extra_'.$variable,
1102
                                    $option_details['option_value'],
1103
                                    $option_details['display_text'].'<br />',
1104
                                    $option_details['option_value']
1105
                                );
1106
                            }
1107
                        }
1108
                        $form->addGroup(
1109
                            $group,
1110
                            'extra_'.$variable,
1111
                            $field_details['display_text']
1112
                        );
1113
                        if ($freezeElement) {
1114
                            $form->freeze('extra_'.$variable);
1115
                        }
1116
                        break;
1117
                    case self::FIELD_TYPE_CHECKBOX:
1118
                        $group = [];
1119
                        if (isset($field_details['options']) &&
1120
                            !empty($field_details['options'])
1121
                        ) {
1122
                            foreach ($field_details['options'] as $option_details) {
1123
                                $options[$option_details['option_value']] = $option_details['display_text'];
1124
                                $group[] = $form->createElement(
1125
                                    'checkbox',
1126
                                    'extra_'.$variable,
1127
                                    $option_details['option_value'],
1128
                                    $option_details['display_text'].'<br />',
1129
                                    $option_details['option_value']
1130
                                );
1131
                            }
1132
                        } else {
1133
                            $fieldVariable = "extra_$variable";
1134
                            $checkboxAttributes = [];
1135
                            if (is_array($extraData) &&
1136
                                array_key_exists($fieldVariable, $extraData)
1137
                            ) {
1138
                                if (!empty($extraData[$fieldVariable])) {
1139
                                    $checkboxAttributes['checked'] = 1;
1140
                                }
1141
                            }
1142
1143
                            if (empty($checkboxAttributes) &&
1144
                                isset($field_details['default_value']) && empty($extraData)) {
1145
                                if (1 == $field_details['default_value']) {
1146
                                    $checkboxAttributes['checked'] = 1;
1147
                                }
1148
                            }
1149
1150
                            // We assume that is a switch on/off with 1 and 0 as values
1151
                            $group[] = $form->createElement(
1152
                                'checkbox',
1153
                                'extra_'.$variable,
1154
                                null,
1155
                                get_lang('Yes'),
1156
                                $checkboxAttributes
1157
                            );
1158
                        }
1159
1160
                        $form->addGroup(
1161
                            $group,
1162
                            'extra_'.$variable,
1163
                            $field_details['display_text']
1164
                        );
1165
                        if ($freezeElement) {
1166
                            $form->freeze('extra_'.$variable);
1167
                        }
1168
                        break;
1169
                    case self::FIELD_TYPE_SELECT:
1170
                        $this->addSelectElement($form, $field_details, $defaultValueId, $freezeElement);
1171
                        break;
1172
                    case self::FIELD_TYPE_SELECT_MULTIPLE:
1173
                        $options = [];
1174
                        if (empty($defaultValueId)) {
1175
                            $options[''] = get_lang('Please select an option');
1176
                        }
1177
                        if (isset($field_details['options']) && !empty($field_details['options'])) {
1178
                            foreach ($field_details['options'] as $optionDetails) {
1179
                                $options[$optionDetails['option_value']] = $optionDetails['display_text'];
1180
                            }
1181
                        }
1182
1183
                        if ($orderDependingDefaults) {
1184
                            if (isset($extraData['extra_'.$variable])) {
1185
                                $defaultOptions = $extraData['extra_'.$variable];
1186
                                $firstList = [];
1187
                                if ($addEmptyOptionSelects) {
1188
                                    $firstList[] = '';
1189
                                }
1190
                                foreach ($defaultOptions as $key) {
1191
                                    if (isset($options[$key])) {
1192
                                        $firstList[$key] = $options[$key];
1193
                                    }
1194
                                }
1195
                                if (!empty($firstList)) {
1196
                                    $options = array_merge($firstList, $options);
1197
                                }
1198
                            } else {
1199
                                $firstList = [];
1200
                                if ($addEmptyOptionSelects) {
1201
                                    $firstList[] = '&nbsp;';
1202
                                    $options = array_merge($firstList, $options);
1203
                                }
1204
                            }
1205
                        }
1206
                        // OFAJ
1207
                        $separateValue = 0;
1208
                        if (isset($separateExtraMultipleSelect[$variable])) {
1209
                            $separateValue = $separateExtraMultipleSelect[$variable];
1210
                        }
1211
1212
                        if ($separateValue > 0) {
1213
                            for ($i = 0; $i < $separateValue; $i++) {
1214
                                $form->addSelect(
1215
                                    'extra_'.$variable.'['.$i.']',
1216
                                    $customLabelsExtraMultipleSelect[$variable][$i],
1217
                                    $options,
1218
                                    ['id' => 'extra_'.$variable.'_'.$i]
1219
                                );
1220
                            }
1221
                        } else {
1222
                            // Ofaj
1223
                            $attributes = ['multiple' => 'multiple', 'id' => 'extra_'.$variable];
1224
                            $chosenSelect = [
1225
                                'ecouter',
1226
                                'lire',
1227
                                'participer_a_une_conversation',
1228
                                's_exprimer_oralement_en_continu',
1229
                                'ecrire',
1230
                            ];
1231
1232
                            if (in_array($variable, $chosenSelect)) {
1233
                                $attributes['select_chosen'] = true;
1234
                            }
1235
1236
                            // default behaviour
1237
                            $form->addSelect(
1238
                                'extra_'.$variable,
1239
                                $field_details['display_text'],
1240
                                $options,
1241
                                $attributes,
1242
                            );
1243
1244
                        }
1245
1246
                        if ($freezeElement) {
1247
                            $form->freeze('extra_'.$variable);
1248
                        }
1249
                        /*$form->addSelect(
1250
                            'extra_'.$variable,
1251
                            $field_details['display_text'],
1252
                            $options,
1253
                            [
1254
                                'multiple' => 'multiple',
1255
                                'id' => 'extra_'.$variable,
1256
                            ]
1257
                        );
1258
                        if ($freezeElement) {
1259
                            $form->freeze('extra_'.$variable);
1260
                        }*/
1261
                        break;
1262
                    case self::FIELD_TYPE_DATE:
1263
                        $form->addDatePicker('extra_'.$variable, $field_details['display_text']);
1264
                        if ($freezeElement) {
1265
                            $form->freeze('extra_'.$variable);
1266
                        }
1267
                        break;
1268
                    case self::FIELD_TYPE_DATETIME:
1269
                        $form->addDateTimePicker(
1270
                            'extra_'.$variable,
1271
                            $field_details['display_text']
1272
                        );
1273
1274
                        $defaults['extra_'.$variable] = api_get_local_time();
1275
                        if (!isset($form->_defaultValues['extra_'.$variable])) {
1276
                            $form->setDefaults($defaults);
1277
                        }
1278
                        if ($freezeElement) {
1279
                            $form->freeze('extra_'.$variable);
1280
                        }
1281
                        break;
1282
                    case self::FIELD_TYPE_DOUBLE_SELECT:
1283
                        $jquery_ready_content .= self::addDoubleSelectElement(
0 ignored issues
show
Bug Best Practice introduced by
The method ExtraField::addDoubleSelectElement() is not static, but was called statically. ( Ignorable by Annotation )

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

1283
                        $jquery_ready_content .= self::/** @scrutinizer ignore-call */ addDoubleSelectElement(
Loading history...
1284
                            $form,
1285
                            $field_details,
1286
                            $extraData,
1287
                            $freezeElement
1288
                        );
1289
                        break;
1290
                    case self::FIELD_TYPE_DIVIDER:
1291
                        $form->addHtml('
1292
                            <div class="form-group ">
1293
                                <div class="col-sm-12">
1294
                                    <div class="panel-separator">
1295
                                       <h4 id="'.$variable.'" class="form-separator">'
1296
                                            .$field_details['display_text'].'
1297
                                       </h4>
1298
                                    </div>
1299
                                </div>
1300
                            </div>
1301
                        ');
1302
                        break;
1303
                    case self::FIELD_TYPE_TAG:
1304
                        $field_id = $field_details['id'];
1305
                        $separateValue = 0;
1306
                        if (isset($separateExtraMultipleSelect[$variable])) {
1307
                            $separateValue = $separateExtraMultipleSelect[$variable];
1308
                        }
1309
1310
                        $selectedOptions = [];
1311
                        if ($separateValue > 0) {
1312
                            $em = Database::getManager();
1313
                            $fieldTags = $em
1314
                                ->getRepository(ExtraFieldRelTag::class)
1315
                                ->findBy(
1316
                                    [
1317
                                        'field' => $field_id,
1318
                                        'itemId' => $itemId,
1319
                                    ]
1320
                                );
1321
                            // ofaj.
1322
                            for ($i = 0; $i < $separateValue; $i++) {
1323
                                $tagsSelect = $form->addSelect(
1324
                                    'extra_'.$variable.'['.$i.']',
1325
                                    $customLabelsExtraMultipleSelect[$variable][$i], //$field_details['display_text'],
1326
                                    [],
1327
                                    ['id' => 'extra_'.$variable.'_'.$i]
1328
                                );
1329
1330
                                if ($addEmptyOptionSelects) {
1331
                                    $tagsSelect->addOption(
1332
                                        '',
1333
                                        ''
1334
                                    );
1335
                                }
1336
                                /** @var ExtraFieldRelTag $fieldTag */
1337
                                foreach ($fieldTags as $fieldTag) {
1338
                                    $tag = $fieldTag->getTag();
1339
1340
                                    if (empty($tag)) {
1341
                                        continue;
1342
                                    }
1343
1344
                                    $tagsSelect->addOption(
1345
                                        $tag->getTag(),
1346
                                        $tag->getTag()
1347
                                    );
1348
                                }
1349
                            }
1350
                        } else {
1351
                            $tagsSelect = $form->addSelect(
1352
                                "extra_{$variable}",
1353
                                $field_details['display_text'],
1354
                                [],
1355
                                ['style' => 'width: 100%;']
1356
                            );
1357
1358
                            if (false === $useTagAsSelect) {
1359
                                $tagsSelect->setAttribute('class', null);
1360
                            }
1361
1362
                            $tagsSelect->setAttribute(
1363
                                'id',
1364
                                "extra_{$variable}"
1365
                            );
1366
                            $tagsSelect->setMultiple(true);
1367
1368
                            $selectedOptions = [];
1369
                            if ('user' === $this->type) {
1370
                                // The magic should be here
1371
                                $user_tags = UserManager::get_user_tags(
1372
                                    $itemId,
1373
                                    $field_details['id']
1374
                                );
1375
1376
                                if (is_array($user_tags) && count($user_tags) > 0) {
1377
                                    foreach ($user_tags as $tag) {
1378
                                        if (empty($tag['tag'])) {
1379
                                            continue;
1380
                                        }
1381
                                        $tagsSelect->addOption(
1382
                                            $tag['tag'],
1383
                                            $tag['tag'],
1384
                                            [
1385
                                                'selected' => 'selected',
1386
                                                'class' => 'selected',
1387
                                            ]
1388
                                        );
1389
                                        $selectedOptions[] = $tag['tag'];
1390
                                    }
1391
                                }
1392
                                $url = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php';
1393
                            } else {
1394
                                $em = Database::getManager();
1395
                                $fieldTags = $em->getRepository(
1396
                                    ExtraFieldRelTag::class
1397
                                )
1398
                                ->findBy(
1399
                                    [
1400
                                        'field' => $field_id,
1401
                                        'itemId' => $itemId,
1402
                                    ]
1403
                                );
1404
1405
                                /** @var ExtraFieldRelTag $fieldTag */
1406
                                foreach ($fieldTags as $fieldTag) {
1407
                                    $tag = $fieldTag->getTag();
1408
                                    if (empty($tag)) {
1409
                                        continue;
1410
                                    }
1411
                                    $tagsSelect->addOption(
1412
                                        $tag->getTag(),
1413
                                        $tag->getTag()
1414
                                    );
1415
                                    $selectedOptions[] = $tag->getTag();
1416
                                }
1417
1418
                                if (!empty($extraData) && isset($extraData['extra_'.$variable])) {
1419
                                    $data = $extraData['extra_'.$variable];
1420
                                    if (!empty($data)) {
1421
                                        foreach ($data as $option) {
1422
                                            $tagsSelect->addOption(
1423
                                                $option,
1424
                                                $option
1425
                                            );
1426
                                        }
1427
                                    }
1428
                                }
1429
1430
                                if ($useTagAsSelect) {
1431
                                    $fieldTags = $em->getRepository(ExtraFieldRelTag::class)
1432
                                        ->findBy(
1433
                                            [
1434
                                                'field' => $field_id,
1435
                                            ]
1436
                                        );
1437
                                    $tagsAdded = [];
1438
                                    /** @var ExtraFieldRelTag $fieldTag */
1439
                                    foreach ($fieldTags as $fieldTag) {
1440
                                        $tag = $fieldTag->getTag();
1441
1442
                                        if (empty($tag)) {
1443
                                            continue;
1444
                                        }
1445
1446
                                        $tagText = $tag->getTag();
1447
                                        if (in_array($tagText, $tagsAdded)) {
1448
                                            continue;
1449
                                        }
1450
1451
                                        $tagsSelect->addOption(
1452
                                            $tag->getTag(),
1453
                                            $tag->getTag(),
1454
                                            []
1455
                                        );
1456
1457
                                        $tagsAdded[] = $tagText;
1458
                                    }
1459
                                }
1460
                                $url = api_get_path(WEB_AJAX_PATH).'extra_field.ajax.php';
1461
                            }
1462
1463
                            $form->setDefaults(
1464
                                [
1465
                                    'extra_'.$variable => $selectedOptions,
1466
                                ]
1467
                            );
1468
1469
                            if (false == $useTagAsSelect) {
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...
1470
                                $jquery_ready_content .= "
1471
                                $('#extra_$variable').select2({
1472
                                    ajax: {
1473
                                        url: '$url?a=search_tags&field_id=$field_id&type={$this->type}',
1474
                                        processResults: function (data) {
1475
                                            return {
1476
                                                results: data.items
1477
                                            }
1478
                                        }
1479
                                    },
1480
                                    cache: false,
1481
                                    tags: true,
1482
                                    tokenSeparators: [','],
1483
                                    placeholder: '".get_lang('Start to type, then click on this bar to validate tag')."'
1484
                                });
1485
                            ";
1486
                            }
1487
                        }
1488
1489
                        break;
1490
                    case self::FIELD_TYPE_TIMEZONE:
1491
                        $form->addSelect(
1492
                            'extra_'.$variable,
1493
                            $field_details['display_text'],
1494
                            api_get_timezones(),
1495
                        );
1496
                        if ($freezeElement) {
1497
                            $form->freeze('extra_'.$variable);
1498
                        }
1499
                        break;
1500
                    case self::FIELD_TYPE_SOCIAL_PROFILE:
1501
                        // get the social network's favicon
1502
                        $extra_data_variable = isset($extraData['extra_'.$variable]) ? $extraData['extra_'.$variable] : null;
1503
                        $field_default_value = isset($field_details['field_default_value']) ? $field_details['field_default_value'] : null;
1504
                        $icon_path = UserManager::get_favicon_from_url(
1505
                            $extra_data_variable,
1506
                            $field_default_value
1507
                        );
1508
                        // special hack for hi5
1509
                        $leftpad = '1.7';
1510
                        $top = '0.4';
1511
                        $domain = parse_url($icon_path, PHP_URL_HOST);
1512
                        if ('www.hi5.com' === $domain || 'hi5.com' === $domain) {
1513
                            $leftpad = '3';
1514
                            $top = '0';
1515
                        }
1516
                        // print the input field
1517
                        $form->addElement(
1518
                            'text',
1519
                            'extra_'.$variable,
1520
                            $field_details['display_text'],
1521
                            [
1522
                                //'size' => 60,
1523
                                'size' => implode(
1524
                                    '; ',
1525
                                    [
1526
                                        "background-image: url('$icon_path')",
1527
                                        'background-repeat: no-repeat',
1528
                                        "background-position: 0.4em {$top}em",
1529
                                        "padding-left: {$leftpad}em",
1530
                                    ]
1531
                                ),
1532
                            ]
1533
                        );
1534
                        $form->applyFilter('extra_'.$variable, 'stripslashes');
1535
                        $form->applyFilter('extra_'.$variable, 'trim');
1536
                        if ($freezeElement) {
1537
                            $form->freeze('extra_'.$variable);
1538
                        }
1539
                        break;
1540
                    case self::FIELD_TYPE_MOBILE_PHONE_NUMBER:
1541
                        $form->addElement(
1542
                            'text',
1543
                            'extra_'.$variable,
1544
                            $field_details['display_text'].' ('.get_lang('Include the country dial code').')',
1545
                            ['size' => 40, 'placeholder' => '(xx)xxxxxxxxx']
1546
                        );
1547
                        $form->applyFilter('extra_'.$variable, 'stripslashes');
1548
                        $form->applyFilter('extra_'.$variable, 'trim');
1549
                        $form->applyFilter('extra_'.$variable, 'mobile_phone_number_filter');
1550
                        $form->addRule(
1551
                            'extra_'.$variable,
1552
                            get_lang('Mobile phone number is incomplete or contains invalid characters'),
1553
                            'mobile_phone_number'
1554
                        );
1555
                        if ($freezeElement) {
1556
                            $form->freeze('extra_'.$variable);
1557
                        }
1558
                        break;
1559
                    case self::FIELD_TYPE_INTEGER:
1560
                        $form->addElement(
1561
                            'number',
1562
                            'extra_'.$variable,
1563
                            $field_details['display_text'],
1564
                            ['class' => 'span1', 'step' => 1]
1565
                        );
1566
1567
                        $form->applyFilter('extra_'.$variable, 'stripslashes');
1568
                        $form->applyFilter('extra_'.$variable, 'trim');
1569
                        $form->applyFilter('extra_'.$variable, 'intval');
1570
1571
                        if ($freezeElement) {
1572
                            $form->freeze('extra_'.$variable);
1573
                        }
1574
                        break;
1575
                    case self::FIELD_TYPE_FLOAT:
1576
                        $form->addElement(
1577
                            'number',
1578
                            'extra_'.$variable,
1579
                            $field_details['display_text'],
1580
                            ['class' => 'span1', 'step' => '0.01']
1581
                        );
1582
1583
                        $form->applyFilter('extra_'.$variable, 'stripslashes');
1584
                        $form->applyFilter('extra_'.$variable, 'trim');
1585
                        $form->applyFilter('extra_'.$variable, 'floatval');
1586
1587
                        if ($freezeElement) {
1588
                            $form->freeze('extra_'.$variable);
1589
                        }
1590
                        break;
1591
                    case self::FIELD_TYPE_FILE_IMAGE:
1592
                        $fieldVariable = "extra_{$variable}";
1593
                        $fieldTexts = [
1594
                            $field_details['display_text'],
1595
                        ];
1596
1597
                        if (is_array($extraData) && array_key_exists($fieldVariable, $extraData)) {
1598
                            $assetId = $extraData[$fieldVariable];
1599
                            if (!empty($assetId)) {
1600
                                $asset = $assetRepo->find($assetId);
1601
                                if (null !== $asset) {
1602
                                    $fieldTexts[] = Display::img(
1603
                                        $assetRepo->getAssetUrl($asset),
1604
                                        $field_details['display_text'],
1605
                                        ['width' => '300'],
1606
                                        false
1607
                                    );
1608
                                }
1609
                            }
1610
                        }
1611
1612
                        if ('Image' === $fieldTexts[0]) {
1613
                            $fieldTexts[0] = get_lang($fieldTexts[0]);
1614
                        }
1615
1616
                        $form->addFile(
1617
                            $fieldVariable,
1618
                            $fieldTexts,
1619
                            ['accept' => 'image/*', 'id' => 'extra_image', 'crop_image' => 'true']
1620
                        );
1621
1622
                        $form->applyFilter('extra_'.$variable, 'stripslashes');
1623
                        $form->applyFilter('extra_'.$variable, 'trim');
1624
1625
                        $allowedPictureTypes = ['jpg', 'jpeg', 'png', 'gif'];
1626
                        $form->addRule(
1627
                            'extra_'.$variable,
1628
                            get_lang('Only PNG, JPG or GIF images allowed').' ('.implode(',', $allowedPictureTypes).')',
1629
                            'filetype',
1630
                            $allowedPictureTypes
1631
                        );
1632
1633
                        if ($freezeElement) {
1634
                            $form->freeze('extra_'.$variable);
1635
                        }
1636
                        break;
1637
                    case self::FIELD_TYPE_FILE:
1638
                        $fieldVariable = "extra_{$variable}";
1639
                        $fieldTexts = [
1640
                            $field_details['display_text'],
1641
                        ];
1642
1643
                        if (is_array($extraData) &&
1644
                            array_key_exists($fieldVariable, $extraData)
1645
                        ) {
1646
                            $assetId = $extraData[$fieldVariable] ?? 0;
1647
                            /** @var Asset $asset */
1648
                            $asset = $assetRepo->find($assetId);
1649
                            if (null !== $asset) {
1650
                                $fileName = $asset->getTitle();
1651
                                $linkUrl = $assetRepo->getAssetUrl($asset);
1652
                                $linkToDelete = '';
1653
                                if (api_is_platform_admin()) {
1654
                                    $url = api_get_path(WEB_AJAX_PATH).'extra_field.ajax.php?type='.$this->type;
1655
                                    $url .= '&a=delete_file&field_id='.$field_details['id'].'&item_id='.$itemId;
1656
                                    $deleteId = $variable.'_delete';
1657
                                    $form->addHtml(
1658
                                        "
1659
                                        <script>
1660
                                            $(function() {
1661
                                                $('#".$deleteId."').on('click', function() {
1662
                                                    $.ajax({
1663
                                                        type: 'GET',
1664
                                                        url: '".$url."',
1665
                                                        success: function(result) {
1666
                                                            if (result == 1) {
1667
                                                                $('#".$variable."').html('".get_lang('Deleted')."');
1668
                                                            }
1669
                                                        }
1670
                                                    });
1671
                                                });
1672
                                            });
1673
                                        </script>
1674
                                    "
1675
                                    );
1676
1677
                                    $linkToDelete = '&nbsp;'.Display::url(
1678
                                        Display::return_icon('delete.png', get_lang('Delete')),
1679
                                        'javascript:void(0)',
1680
                                        ['id' => $deleteId]
1681
                                    );
1682
                                }
1683
                                $anchor = Display::url(
1684
                                    $fileName,
1685
                                    $linkUrl,
1686
                                    [
1687
                                        'title' => $field_details['display_text'],
1688
                                        'target' => '_blank',
1689
                                    ]
1690
                                );
1691
                                $fieldTexts[] = '<div id="'.$variable.'">'.$anchor.$linkToDelete.'</div>';
1692
                            }
1693
                        }
1694
1695
                        $form->addElement(
1696
                            'file',
1697
                            $fieldVariable,
1698
                            $fieldTexts,
1699
                            []
1700
                        );
1701
1702
                        $form->applyFilter('extra_'.$variable, 'stripslashes');
1703
                        $form->applyFilter('extra_'.$variable, 'trim');
1704
1705
                        if ($freezeElement) {
1706
                            $form->freeze('extra_'.$variable);
1707
                        }
1708
                        break;
1709
                    case self::FIELD_TYPE_VIDEO_URL:
1710
                        $form->addUrl(
1711
                            "extra_{$variable}",
1712
                            $field_details['display_text'],
1713
                            false,
1714
                            ['placeholder' => 'https://']
1715
                        );
1716
                        if ($freezeElement) {
1717
                            $form->freeze('extra_'.$variable);
1718
                        }
1719
                        break;
1720
                    case self::FIELD_TYPE_LETTERS_ONLY:
1721
                        $form->addTextLettersOnly(
1722
                            "extra_{$variable}",
1723
                            $field_details['display_text']
1724
                        );
1725
                        $form->applyFilter('extra_'.$variable, 'stripslashes');
1726
1727
                        if ($freezeElement) {
1728
                            $form->freeze('extra_'.$variable);
1729
                        }
1730
                        break;
1731
                    case self::FIELD_TYPE_ALPHANUMERIC:
1732
                        $form->addTextAlphanumeric(
1733
                            "extra_{$variable}",
1734
                            $field_details['display_text']
1735
                        );
1736
                        $form->applyFilter(
1737
                            'extra_'.$variable,
1738
                            'stripslashes'
1739
                        );
1740
                        if ($freezeElement) {
1741
                            $form->freeze('extra_'.$variable);
1742
                        }
1743
                        break;
1744
                    case self::FIELD_TYPE_LETTERS_SPACE:
1745
                        $form->addTextLettersAndSpaces(
1746
                            "extra_{$variable}",
1747
                            $field_details['display_text']
1748
                        );
1749
                        $form->applyFilter('extra_'.$variable, 'stripslashes');
1750
1751
                        if ($freezeElement) {
1752
                            $form->freeze('extra_'.$variable);
1753
                        }
1754
                        break;
1755
                    case self::FIELD_TYPE_ALPHANUMERIC_SPACE:
1756
                        $form->addTextAlphanumericAndSpaces(
1757
                            "extra_{$variable}",
1758
                            $field_details['display_text']
1759
                        );
1760
                        $form->applyFilter(
1761
                            'extra_'.$variable,
1762
                            'stripslashes'
1763
                        );
1764
                        if ($freezeElement) {
1765
                            $form->freeze('extra_'.$variable);
1766
                        }
1767
                        break;
1768
                    case self::FIELD_TYPE_GEOLOCALIZATION_COORDINATES:
1769
                    case self::FIELD_TYPE_GEOLOCALIZATION:
1770
                        $dataValue = isset($extraData['extra_'.$variable]) ? $extraData['extra_'.$variable] : '';
1771
                        $form->addGeoLocationMapField(
1772
                            'extra_'.$variable,
1773
                            $field_details['display_text'],
1774
                            $dataValue,
1775
                            $hideGeoLocalizationDetails
1776
                        );
1777
1778
                        if ($freezeElement) {
1779
                            $form->freeze('extra_'.$variable);
1780
                        }
1781
                        break;
1782
                    case self::FIELD_TYPE_SELECT_WITH_TEXT_FIELD:
1783
                        $jquery_ready_content .= $this->addSelectWithTextFieldElement(
1784
                            $form,
1785
                            $field_details,
1786
                            $freezeElement
1787
                        );
1788
                        break;
1789
                    case self::FIELD_TYPE_TRIPLE_SELECT:
1790
                        $jquery_ready_content .= $this->addTripleSelectElement(
1791
                            $form,
1792
                            $field_details,
1793
                            is_array($extraData) ? $extraData : [],
1794
                            $freezeElement
1795
                        );
1796
                        break;
1797
                }
1798
            }
1799
        }
1800
1801
        $return = [];
1802
        $return['jquery_ready_content'] = $jquery_ready_content;
1803
1804
        return $return;
1805
    }
1806
1807
    /**
1808
     * @param array $options
1809
     *
1810
     * @return array
1811
     */
1812
    public static function extra_field_double_select_convert_array_to_ordered_array($options)
1813
    {
1814
        $optionsParsed = [];
1815
        if (!empty($options)) {
1816
            foreach ($options as $option) {
1817
                if (0 == $option['option_value']) {
1818
                    $optionsParsed[$option['id']][] = $option;
1819
                } else {
1820
                    $optionsParsed[$option['option_value']][] = $option;
1821
                }
1822
            }
1823
        }
1824
1825
        return $optionsParsed;
1826
    }
1827
1828
    /**
1829
     * @return array
1830
     */
1831
    public static function tripleSelectConvertArrayToOrderedArray(array $options)
1832
    {
1833
        $level1 = self::getOptionsFromTripleSelect($options, 0);
1834
        $level2 = [];
1835
        $level3 = [];
1836
1837
        foreach ($level1 as $item1) {
1838
            $level2 += self::getOptionsFromTripleSelect($options, $item1['id']);
1839
        }
1840
1841
        foreach ($level2 as $item2) {
1842
            $level3 += self::getOptionsFromTripleSelect($options, $item2['id']);
1843
        }
1844
1845
        return ['level1' => $level1, 'level2' => $level2, 'level3' => $level3];
1846
    }
1847
1848
    /**
1849
     * @param string $type
1850
     *
1851
     * @return array
1852
     */
1853
    public function get_all_extra_field_by_type($type)
1854
    {
1855
        // all the information of the field
1856
        $sql = "SELECT * FROM {$this->table}
1857
                WHERE
1858
                    field_type = '".Database::escape_string($type)."' AND
1859
                    extra_field_type = $this->extraFieldType
1860
                ";
1861
        $result = Database::query($sql);
1862
1863
        $return = [];
1864
        while ($row = Database::fetch_array($result)) {
1865
            $return[] = $row['id'];
1866
        }
1867
1868
        return $return;
1869
    }
1870
1871
    /**
1872
     * @param int $id
1873
     */
1874
    public function get_field_type_by_id($id)
1875
    {
1876
        $types = $this->get_field_types();
1877
        if (isset($types[$id])) {
1878
            return $types[$id];
1879
        }
1880
1881
        return null;
1882
    }
1883
1884
    /**
1885
     * @return array
1886
     */
1887
    public function get_field_types()
1888
    {
1889
        return $this->get_extra_fields_by_handler($this->type);
1890
    }
1891
1892
    /**
1893
     * @param string $handler
1894
     *
1895
     * @return array
1896
     */
1897
    public static function get_extra_fields_by_handler($handler)
1898
    {
1899
        $types = [];
1900
        $types[self::FIELD_TYPE_TEXT] = get_lang('Text');
1901
        $types[self::FIELD_TYPE_TEXTAREA] = get_lang('Text area');
1902
        $types[self::FIELD_TYPE_RADIO] = get_lang('Radio buttons');
1903
        $types[self::FIELD_TYPE_SELECT] = get_lang('Select drop-down');
1904
        $types[self::FIELD_TYPE_SELECT_MULTIPLE] = get_lang('Multiple selection drop-down');
1905
        $types[self::FIELD_TYPE_DATE] = get_lang('Date');
1906
        $types[self::FIELD_TYPE_DATETIME] = get_lang('Date and time');
1907
        $types[self::FIELD_TYPE_DOUBLE_SELECT] = get_lang('Double select');
1908
        $types[self::FIELD_TYPE_DIVIDER] = get_lang('Visual divider');
1909
        $types[self::FIELD_TYPE_TAG] = get_lang('User tag');
1910
        $types[self::FIELD_TYPE_TIMEZONE] = get_lang('Timezone');
1911
        $types[self::FIELD_TYPE_SOCIAL_PROFILE] = get_lang('Social network link');
1912
        $types[self::FIELD_TYPE_MOBILE_PHONE_NUMBER] = get_lang('Mobile phone number');
1913
        $types[self::FIELD_TYPE_CHECKBOX] = get_lang('Checkbox');
1914
        $types[self::FIELD_TYPE_INTEGER] = get_lang('Integer');
1915
        $types[self::FIELD_TYPE_FILE_IMAGE] = get_lang('Image');
1916
        $types[self::FIELD_TYPE_FLOAT] = get_lang('Float');
1917
        $types[self::FIELD_TYPE_FILE] = get_lang('File');
1918
        $types[self::FIELD_TYPE_VIDEO_URL] = get_lang('Video URL');
1919
        $types[self::FIELD_TYPE_LETTERS_ONLY] = get_lang('Text only letters');
1920
        $types[self::FIELD_TYPE_ALPHANUMERIC] = get_lang('Text only alphanumeric characters');
1921
        $types[self::FIELD_TYPE_LETTERS_SPACE] = get_lang('Text letters and spaces');
1922
        $types[self::FIELD_TYPE_ALPHANUMERIC_SPACE] = get_lang('Text alphanumeric characters and spaces');
1923
        $types[self::FIELD_TYPE_GEOLOCALIZATION] = get_lang('Geolocalization');
1924
        $types[self::FIELD_TYPE_GEOLOCALIZATION_COORDINATES] = get_lang('Geolocalization by coordinates');
1925
        $types[self::FIELD_TYPE_SELECT_WITH_TEXT_FIELD] = get_lang('Select with text field');
1926
        $types[self::FIELD_TYPE_TRIPLE_SELECT] = get_lang('Triple select');
1927
1928
        switch ($handler) {
1929
            case 'course':
1930
            case 'session':
1931
            case 'user':
1932
            case 'skill':
1933
                break;
1934
        }
1935
1936
        return $types;
1937
    }
1938
1939
    /**
1940
     * @param array $params
1941
     * @param bool  $showQuery
1942
     *
1943
     * @return int|bool
1944
     */
1945
    public function save($params, $showQuery = false)
1946
    {
1947
        $fieldInfo = self::get_handler_field_info_by_field_variable($params['variable']);
0 ignored issues
show
Bug Best Practice introduced by
The method ExtraField::get_handler_...nfo_by_field_variable() is not static, but was called statically. ( Ignorable by Annotation )

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

1947
        /** @scrutinizer ignore-call */ 
1948
        $fieldInfo = self::get_handler_field_info_by_field_variable($params['variable']);
Loading history...
1948
        $params = $this->clean_parameters($params);
1949
        $params['extra_field_type'] = $this->extraFieldType;
1950
1951
        if ($fieldInfo) {
1952
            return $fieldInfo['id'];
1953
        } else {
1954
            $id = parent::save($params, $showQuery);
1955
            if ($id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $id of type false|integer is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
1956
                $fieldOption = new ExtraFieldOption($this->type);
1957
                $params['field_id'] = $id;
1958
                $fieldOption->save($params);
1959
            }
1960
1961
            return $id;
1962
        }
1963
    }
1964
1965
    /**
1966
     * @param string $variable
1967
     *
1968
     * @return array|bool
1969
     */
1970
    public function get_handler_field_info_by_field_variable($variable)
1971
    {
1972
        $variable = Database::escape_string($variable);
1973
        $sql = "SELECT * FROM {$this->table}
1974
                WHERE
1975
                    variable = '$variable' AND
1976
                    extra_field_type = $this->extraFieldType";
1977
        $result = Database::query($sql);
1978
        if (Database::num_rows($result)) {
1979
            $extraFieldRepo = Container::getExtraFieldRepository();
1980
            $row = Database::fetch_array($result, 'ASSOC');
1981
            if ($row) {
1982
                $extraFieldId = $row['id'];
1983
                /** @var \Chamilo\CoreBundle\Entity\ExtraField $extraField */
1984
                $field = $extraFieldRepo->find($extraFieldId);
1985
                $row['display_text'] = $field->getDisplayText();
1986
1987
                // All the options of the field
1988
                $sql = "SELECT * FROM $this->table_field_options
1989
                        WHERE field_id='".$extraFieldId."'
1990
                        ORDER BY option_order ASC";
1991
                $result = Database::query($sql);
1992
                while ($option = Database::fetch_array($result)) {
1993
                    $row['options'][$option['id']] = $option;
1994
                }
1995
1996
                return $row;
1997
            }
1998
        }
1999
2000
        return false;
2001
    }
2002
2003
    /**
2004
     * @param array $params
2005
     *
2006
     * @return array
2007
     */
2008
    public function clean_parameters($params)
2009
    {
2010
        if (!isset($params['variable']) || empty($params['variable'])) {
2011
            $params['variable'] = $params['display_text'];
2012
        }
2013
2014
        $params['variable'] = trim(strtolower(str_replace(' ', '_', $params['variable'])));
2015
2016
        if (!isset($params['field_order'])) {
2017
            $max_order = self::get_max_field_order();
0 ignored issues
show
Bug Best Practice introduced by
The method ExtraField::get_max_field_order() is not static, but was called statically. ( Ignorable by Annotation )

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

2017
            /** @scrutinizer ignore-call */ 
2018
            $max_order = self::get_max_field_order();
Loading history...
2018
            $params['field_order'] = $max_order;
2019
        } else {
2020
            $params['field_order'] = (int) $params['field_order'];
2021
        }
2022
2023
        return $params;
2024
    }
2025
2026
    /**
2027
     * @return int
2028
     */
2029
    public function get_max_field_order()
2030
    {
2031
        $sql = "SELECT MAX(field_order)
2032
                FROM {$this->table}
2033
                WHERE
2034
                    extra_field_type = '.$this->extraFieldType.'";
2035
        $res = Database::query($sql);
2036
2037
        $order = 0;
2038
        if (Database::num_rows($res) > 0) {
2039
            $row = Database::fetch_row($res);
2040
            $order = $row[0] + 1;
2041
        }
2042
2043
        return $order;
2044
    }
2045
2046
    /**
2047
     * {@inheritdoc}
2048
     */
2049
    public function update($params, $showQuery = false)
2050
    {
2051
        $params = $this->clean_parameters($params);
2052
        if (isset($params['id'])) {
2053
            $fieldOption = new ExtraFieldOption($this->type);
2054
            $params['field_id'] = $params['id'];
2055
            if (empty($params['field_type'])) {
2056
                $params['field_type'] = $this->type;
2057
            }
2058
            $fieldOption->save($params, $showQuery);
2059
        }
2060
2061
        return parent::update($params, $showQuery);
2062
    }
2063
2064
    /**
2065
     * @param $id
2066
     *
2067
     * @return bool
2068
     */
2069
    public function delete($id)
2070
    {
2071
        $em = Database::getManager();
2072
        $items = $em->getRepository(\Chamilo\CoreBundle\Entity\ExtraFieldSavedSearch::class)->findBy(['field' => $id]);
2073
        if ($items) {
2074
            foreach ($items as $item) {
2075
                $em->remove($item);
2076
            }
2077
            $em->flush();
2078
        }
2079
        $field_option = new ExtraFieldOption($this->type);
2080
        $field_option->delete_all_options_by_field_id($id);
2081
2082
        $session_field_values = new ExtraFieldValue($this->type);
2083
        $session_field_values->delete_all_values_by_field_id($id);
2084
2085
        return parent::delete($id);
2086
    }
2087
2088
    /**
2089
     * @param $breadcrumb
2090
     * @param $action
2091
     */
2092
    public function setupBreadcrumb(&$breadcrumb, $action)
2093
    {
2094
        if ('add' === $action) {
2095
            $breadcrumb[] = ['url' => $this->pageUrl, 'name' => $this->pageName];
2096
            $breadcrumb[] = ['url' => '#', 'name' => get_lang('Add')];
2097
        } elseif ('edit' === $action) {
2098
            $breadcrumb[] = ['url' => $this->pageUrl, 'name' => $this->pageName];
2099
            $breadcrumb[] = ['url' => '#', 'name' => get_lang('Edit')];
2100
        } else {
2101
            $breadcrumb[] = ['url' => '#', 'name' => $this->pageName];
2102
        }
2103
    }
2104
2105
    /**
2106
     * Displays the title + grid.
2107
     */
2108
    public function display()
2109
    {
2110
        $actions = '<a href="../admin/index.php">';
2111
        $actions .= Display::return_icon(
2112
            'back.png',
2113
            get_lang('Back to').' '.get_lang('Administration'),
2114
            '',
2115
            ICON_SIZE_MEDIUM
2116
        );
2117
        $actions .= '</a>';
2118
        $actions .= '<a href="'.api_get_self().'?action=add&type='.$this->type.'">';
2119
        $actions .= Display::return_icon(
2120
            'add_user_fields.png',
2121
            get_lang('Add'),
2122
            '',
2123
            ICON_SIZE_MEDIUM
2124
        );
2125
        $actions .= '</a>';
2126
2127
        echo Display::toolbarAction('toolbar', [$actions]);
2128
        echo Display::grid_html($this->type.'_fields');
2129
    }
2130
2131
    /**
2132
     * @return array
2133
     */
2134
    public function getJqgridColumnNames()
2135
    {
2136
        return [
2137
            get_lang('Name'),
2138
            get_lang('Field label'),
2139
            get_lang('Type'),
2140
            get_lang('Can change'),
2141
            get_lang('Visible to self'),
2142
            get_lang('Visible to others'),
2143
            get_lang('Filter'),
2144
            get_lang('Order'),
2145
            get_lang('Detail'),
2146
        ];
2147
    }
2148
2149
    /**
2150
     * @return array
2151
     */
2152
    public function getJqgridColumnModel()
2153
    {
2154
        return [
2155
            [
2156
                'name' => 'display_text',
2157
                'index' => 'display_text',
2158
                'width' => '140',
2159
                'align' => 'left',
2160
            ],
2161
            [
2162
                'name' => 'variable',
2163
                'index' => 'variable',
2164
                'width' => '90',
2165
                'align' => 'left',
2166
                'sortable' => 'true',
2167
            ],
2168
            [
2169
                'name' => 'field_type',
2170
                'index' => 'field_type',
2171
                'width' => '70',
2172
                'align' => 'left',
2173
                'sortable' => 'true',
2174
            ],
2175
            [
2176
                'name' => 'changeable',
2177
                'index' => 'changeable',
2178
                'width' => '35',
2179
                'align' => 'left',
2180
                'sortable' => 'true',
2181
            ],
2182
            [
2183
                'name' => 'visible_to_self',
2184
                'index' => 'visible_to_self',
2185
                'width' => '45',
2186
                'align' => 'left',
2187
                'sortable' => 'true',
2188
            ],
2189
            [
2190
                'name' => 'visible_to_others',
2191
                'index' => 'visible_to_others',
2192
                'width' => '35',
2193
                'align' => 'left',
2194
                'sortable' => 'true',
2195
            ],
2196
            [
2197
                'name' => 'filter',
2198
                'index' => 'filter',
2199
                'width' => '30',
2200
                'align' => 'left',
2201
                'sortable' => 'true',
2202
            ],
2203
            [
2204
                'name' => 'field_order',
2205
                'index' => 'field_order',
2206
                'width' => '25',
2207
                'align' => 'left',
2208
                'sortable' => 'true',
2209
            ],
2210
            [
2211
                'name' => 'actions',
2212
                'index' => 'actions',
2213
                'width' => '40',
2214
                'align' => 'left',
2215
                'formatter' => 'action_formatter',
2216
                'sortable' => 'false',
2217
            ],
2218
        ];
2219
    }
2220
2221
    /**
2222
     * @param string $url
2223
     * @param string $action
2224
     *
2225
     * @return FormValidator
2226
     */
2227
    public function return_form($url, $action)
2228
    {
2229
        $form = new FormValidator($this->type.'_field', 'post', $url);
2230
2231
        $form->addElement('hidden', 'type', $this->type);
2232
        $id = isset($_GET['id']) ? (int) $_GET['id'] : null;
2233
        $form->addElement('hidden', 'id', $id);
2234
2235
        // Setting the form elements
2236
        $header = get_lang('Add');
2237
        $defaults = [];
2238
2239
        if ('edit' === $action) {
2240
            $header = get_lang('Edit');
2241
            // Setting the defaults
2242
            $defaults = $this->get($id, false);
2243
        }
2244
2245
        $form->addElement('header', $header);
2246
2247
        if ('edit' === $action) {
2248
            $translateUrl = api_get_path(WEB_CODE_PATH).'extrafield/translate.php?'.http_build_query(['id' => $id]);
2249
            $translateButton = Display::toolbarButton(
2250
                get_lang('Translate this term'),
2251
                $translateUrl,
2252
                'language',
2253
                'link'
2254
            );
2255
2256
            $form->addText(
2257
                'display_text',
2258
                [get_lang('Name'), $translateButton]
2259
            );
2260
        } else {
2261
            $form->addElement('text', 'display_text', get_lang('Name'));
2262
        }
2263
2264
        $form->addHtmlEditor('description', get_lang('Description'), false);
2265
2266
        // Field type
2267
        $types = self::get_field_types();
0 ignored issues
show
Bug Best Practice introduced by
The method ExtraField::get_field_types() is not static, but was called statically. ( Ignorable by Annotation )

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

2267
        /** @scrutinizer ignore-call */ 
2268
        $types = self::get_field_types();
Loading history...
2268
2269
        $form->addSelect(
2270
            'field_type',
2271
            get_lang('Field type'),
2272
            $types,
2273
            ['id' => 'field_type']
2274
        );
2275
        $form->addElement('label', get_lang('Example'), '<div id="example">-</div>');
2276
        $form->addElement('text', 'variable', get_lang('Field label'), ['class' => 'span5']);
2277
        $form->addElement(
2278
            'text',
2279
            'field_options',
2280
            get_lang('Possible values'),
2281
            ['id' => 'field_options', 'class' => 'span6']
2282
        );
2283
2284
        $fieldWithOptions = [
2285
            self::FIELD_TYPE_RADIO,
2286
            self::FIELD_TYPE_SELECT_MULTIPLE,
2287
            self::FIELD_TYPE_SELECT,
2288
            self::FIELD_TYPE_TAG,
2289
            self::FIELD_TYPE_DOUBLE_SELECT,
2290
            self::FIELD_TYPE_SELECT_WITH_TEXT_FIELD,
2291
            self::FIELD_TYPE_TRIPLE_SELECT,
2292
        ];
2293
2294
        if ('edit' === $action) {
2295
            if (in_array($defaults['field_type'], $fieldWithOptions)) {
2296
                $url = Display::url(
2297
                    get_lang('Edit extra field options'),
2298
                    'extra_field_options.php?type='.$this->type.'&field_id='.$id,
2299
                    ['class' => 'btn']
2300
                );
2301
                $form->addElement('label', null, $url);
2302
2303
                if (self::FIELD_TYPE_SELECT == $defaults['field_type']) {
2304
                    $urlWorkFlow = Display::url(
2305
                        get_lang('Edit this field\'s workflow'),
2306
                        'extra_field_workflow.php?type='.$this->type.'&field_id='.$id,
2307
                        ['class' => 'btn']
2308
                    );
2309
                    $form->addElement('label', null, $urlWorkFlow);
2310
                }
2311
2312
                $form->freeze('field_options');
2313
            }
2314
        }
2315
        $form->addElement(
2316
            'text',
2317
            'default_value',
2318
            get_lang('Default value'),
2319
            ['id' => 'default_value']
2320
        );
2321
2322
        $group = [];
2323
        $group[] = $form->createElement('radio', 'visible_to_self', null, get_lang('Yes'), 1);
2324
        $group[] = $form->createElement('radio', 'visible_to_self', null, get_lang('No'), 0);
2325
        $form->addGroup($group, '', get_lang('Visible to self'), null, false);
2326
2327
        $group = [];
2328
        $group[] = $form->createElement('radio', 'visible_to_others', null, get_lang('Yes'), 1);
2329
        $group[] = $form->createElement('radio', 'visible_to_others', null, get_lang('No'), 0);
2330
        $form->addGroup($group, '', get_lang('Visible to others'), null, false);
2331
2332
        $group = [];
2333
        $group[] = $form->createElement('radio', 'changeable', null, get_lang('Yes'), 1);
2334
        $group[] = $form->createElement('radio', 'changeable', null, get_lang('No'), 0);
2335
        $form->addGroup($group, '', get_lang('Can change'), null, false);
2336
2337
        $group = [];
2338
        $group[] = $form->createElement('radio', 'filter', null, get_lang('Yes'), 1);
2339
        $group[] = $form->createElement('radio', 'filter', null, get_lang('No'), 0);
2340
        $form->addGroup($group, '', get_lang('Filter'), null, false);
2341
2342
        /* Enable this when field_loggeable is introduced as a table field (2.0)
2343
        $group   = array();
2344
        $group[] = $form->createElement('radio', 'field_loggeable', null, get_lang('Yes'), 1);
2345
        $group[] = $form->createElement('radio', 'field_loggeable', null, get_lang('No'), 0);
2346
        $form->addGroup($group, '', get_lang('Field changes should be logged'), '', false);
2347
        */
2348
2349
        $form->addElement('text', 'field_order', get_lang('Order'));
2350
2351
        if ('edit' == $action) {
2352
            $option = new ExtraFieldOption($this->type);
2353
            $defaults['field_options'] = $option->get_field_options_by_field_to_string($id);
2354
            $form->addButtonUpdate(get_lang('Edit'));
2355
        } else {
2356
            $defaults['visible_to_self'] = 0;
2357
            $defaults['visible_to_others'] = 0;
2358
            $defaults['changeable'] = 0;
2359
            $defaults['filter'] = 0;
2360
            $form->addButtonCreate(get_lang('Add'));
2361
        }
2362
2363
        /*if (!empty($defaults['created_at'])) {
2364
            $defaults['created_at'] = api_convert_and_format_date($defaults['created_at']);
2365
        }
2366
        if (!empty($defaults['updated_at'])) {
2367
            $defaults['updated_at'] = api_convert_and_format_date($defaults['updated_at']);
2368
        }*/
2369
        $form->setDefaults($defaults);
2370
2371
        // Setting the rules
2372
        $form->addRule('display_text', get_lang('Required field'), 'required');
2373
        $form->addRule('field_type', get_lang('Required field'), 'required');
2374
2375
        return $form;
2376
    }
2377
2378
    /**
2379
     * Gets an element.
2380
     *
2381
     * @param int  $id
2382
     * @param bool $translateDisplayText Optional
2383
     *
2384
     * @return array
2385
     */
2386
    public function get($id, $translateDisplayText = true)
2387
    {
2388
        $info = parent::get($id);
2389
2390
        if ($translateDisplayText) {
2391
            $extraFieldRepo = Container::getExtraFieldRepository();
2392
            /** @var \Chamilo\CoreBundle\Entity\ExtraField $extraField */
2393
            $field = $extraFieldRepo->find($id);
2394
            $info['display_text'] = $field->getDisplayText();
2395
        }
2396
2397
        return $info;
2398
    }
2399
2400
    /**
2401
     * @param $token
2402
     *
2403
     * @return string
2404
     */
2405
    public function getJqgridActionLinks($token)
2406
    {
2407
        //With this function we can add actions to the jgrid (edit, delete, etc)
2408
        $editIcon = Display::return_icon('edit.png', get_lang('Edit'), '', ICON_SIZE_SMALL);
2409
        $deleteIcon = Display::return_icon('delete.png', get_lang('Delete'), '', ICON_SIZE_SMALL);
2410
        $confirmMessage = addslashes(
2411
            api_htmlentities(get_lang("Please confirm your choice"), ENT_QUOTES)
2412
        );
2413
2414
        $editButton = <<<JAVASCRIPT
2415
            <a href="?action=edit&type={$this->type}&id=' + options.rowId + '" class="btn btn-link btn-xs">\
2416
                $editIcon\
2417
            </a>
2418
JAVASCRIPT;
2419
        $deleteButton = <<<JAVASCRIPT
2420
            <a \
2421
                    onclick="if (!confirm(\'$confirmMessage\')) {return false;}" \
2422
                href="?sec_token=$token&type={$this->type}&id=' + options.rowId + '&action=delete" \
2423
                class="btn btn-link btn-xs">\
2424
                $deleteIcon\
2425
            </a>
2426
JAVASCRIPT;
2427
2428
        return "function action_formatter(cellvalue, options, rowObject) {
2429
            return '$editButton $deleteButton';
2430
        }";
2431
    }
2432
2433
    /**
2434
     * @param array $columns
2435
     * @param array $column_model
2436
     * @param array $extraFields
2437
     *
2438
     * @return array
2439
     */
2440
    public function getRules(&$columns, &$column_model, $extraFields = [], $checkExtraFieldExistence = false)
2441
    {
2442
        $fields = $this->get_all(
2443
            [
2444
                'visible_to_self = ? AND filter = ?' => [1, 1],
2445
            ],
2446
            'display_text'
2447
        );
2448
        $extraFieldOption = new ExtraFieldOption($this->type);
2449
2450
        $rules = [];
2451
        if (!empty($fields)) {
2452
            foreach ($fields as $field) {
2453
                $search_options = [];
2454
                $type = 'text';
2455
                if (in_array($field['field_type'], [self::FIELD_TYPE_SELECT, self::FIELD_TYPE_DOUBLE_SELECT])) {
2456
                    $type = 'select';
2457
                    $search_options['sopt'] = ['eq', 'ne']; //equal not equal
2458
                } else {
2459
                    $search_options['sopt'] = ['cn', 'nc']; //contains not contains
2460
                }
2461
2462
                $search_options['searchhidden'] = 'true';
2463
                $search_options['defaultValue'] = isset($search_options['field_default_value'])
2464
                    ? $search_options['field_default_value']
2465
                    : null;
2466
2467
                if (self::FIELD_TYPE_DOUBLE_SELECT == $field['field_type']) {
2468
                    // Add 2 selects
2469
                    $options = $extraFieldOption->get_field_options_by_field($field['id']);
2470
                    $options = self::extra_field_double_select_convert_array_to_ordered_array($options);
2471
2472
                    $first_options = [];
2473
                    if (!empty($options)) {
2474
                        foreach ($options as $option) {
2475
                            foreach ($option as $sub_option) {
2476
                                if (0 == $sub_option['option_value']) {
2477
                                    $first_options[] = $sub_option['field_id'].'#'.$sub_option['id'].':'
2478
                                        .$sub_option['display_text'];
2479
                                }
2480
                            }
2481
                        }
2482
                    }
2483
2484
                    $search_options['value'] = implode(';', $first_options);
2485
                    $search_options['dataInit'] = 'fill_second_select';
2486
2487
                    // First
2488
                    $column_model[] = [
2489
                        'name' => 'extra_'.$field['variable'],
2490
                        'index' => 'extra_'.$field['variable'],
2491
                        'width' => '100',
2492
                        'hidden' => 'true',
2493
                        'search' => 'true',
2494
                        'stype' => 'select',
2495
                        'searchoptions' => $search_options,
2496
                    ];
2497
                    $columns[] = $field['display_text'].' (1)';
2498
                    $rules[] = [
2499
                        'field' => 'extra_'.$field['variable'],
2500
                        'op' => 'cn',
2501
                    ];
2502
2503
                    // Second
2504
                    $search_options['value'] = $field['id'].':';
2505
                    $search_options['dataInit'] = 'register_second_select';
2506
2507
                    $column_model[] = [
2508
                        'name' => 'extra_'.$field['variable'].'_second',
2509
                        'index' => 'extra_'.$field['variable'].'_second',
2510
                        'width' => '100',
2511
                        'hidden' => 'true',
2512
                        'search' => 'true',
2513
                        'stype' => 'select',
2514
                        'searchoptions' => $search_options,
2515
                    ];
2516
                    $columns[] = $field['display_text'].' (2)';
2517
                    $rules[] = ['field' => 'extra_'.$field['variable'].'_second', 'op' => 'cn'];
2518
                    continue;
2519
                } else {
2520
                    $search_options['value'] = $extraFieldOption->getFieldOptionsToString(
2521
                        $field['id'],
2522
                        false,
2523
                        'display_text'
2524
                    );
2525
                }
2526
                $column_model[] = [
2527
                    'name' => 'extra_'.$field['variable'],
2528
                    'index' => 'extra_'.$field['variable'],
2529
                    'width' => '100',
2530
                    'hidden' => 'true',
2531
                    'search' => 'true',
2532
                    'stype' => $type,
2533
                    'searchoptions' => $search_options,
2534
                ];
2535
                $columns[] = $field['display_text'];
2536
                $rules[] = [
2537
                    'field' => 'extra_'.$field['variable'],
2538
                    'op' => 'cn',
2539
                    'data' => '',
2540
                ];
2541
            }
2542
        }
2543
2544
        return $rules;
2545
    }
2546
2547
    public function processExtraFieldSearch($values, $form, $alias, $condition = 'OR')
2548
    {
2549
        // Parse params.
2550
        $fields = [];
2551
        foreach ($values as $key => $value) {
2552
            if ('extra_' !== substr($key, 0, 6) &&
2553
                '_extra_' !== substr($key, 0, 7)
2554
            ) {
2555
                continue;
2556
            }
2557
            if (!empty($value)) {
2558
                $fields[$key] = $value;
2559
            }
2560
        }
2561
2562
        $extraFieldsAll = $this->get_all(['visible_to_self = ? AND filter = ?' => [1, 1]], 'option_order');
2563
        $extraFieldsType = array_column($extraFieldsAll, 'field_type', 'variable');
2564
        $extraFields = array_column($extraFieldsAll, 'variable');
2565
        $filter = new stdClass();
2566
        $defaults = [];
2567
        foreach ($fields as $variable => $col) {
2568
            $variableNoExtra = str_replace('extra_', '', $variable);
2569
            if (isset($values[$variable]) && !empty($values[$variable]) &&
2570
                in_array($variableNoExtra, $extraFields)
2571
            ) {
2572
                $rule = new stdClass();
2573
                $rule->field = $variable;
2574
                $rule->op = 'in';
2575
                $data = $col;
2576
                if (is_array($data) && array_key_exists($variable, $data)) {
2577
                    $data = $col;
2578
                }
2579
                $rule->data = $data;
2580
                $filter->rules[] = $rule;
2581
                $filter->groupOp = 'AND';
2582
2583
                if (ExtraField::FIELD_TYPE_TAG == $extraFieldsType[$variableNoExtra]) {
2584
                    $tagElement = $form->getElement($variable);
2585
                    $tags = [];
2586
                    foreach ($values[$variable] as $tag) {
2587
                        $tag = Security::remove_XSS($tag);
2588
                        $tags[] = $tag;
2589
                        $tagElement->addOption(
2590
                            $tag,
2591
                            $tag
2592
                        );
2593
                    }
2594
                    $defaults[$variable] = $tags;
2595
                } else {
2596
                    if (is_array($data)) {
2597
                        $defaults[$variable] = array_map(['Security', 'remove_XSS'], $data);
2598
                    } else {
2599
                        $defaults[$variable] = Security::remove_XSS($data);
2600
                    }
2601
                }
2602
            }
2603
        }
2604
2605
        $result = $this->getExtraFieldRules($filter, 'extra_', $condition);
2606
        $conditionArray = $result['condition_array'];
2607
2608
        $whereCondition = '';
2609
        $extraCondition = '';
2610
        if (!empty($conditionArray)) {
2611
            $extraCondition = ' ( ';
2612
            $extraCondition .= implode(' AND ', $conditionArray);
2613
            $extraCondition .= ' ) ';
2614
        }
2615
        $whereCondition .= $extraCondition;
2616
        $conditions = $this->parseConditions(
2617
            [
2618
                'where' => $whereCondition,
2619
                'extra' => $result['extra_fields'],
2620
            ],
2621
            $alias
2622
        );
2623
2624
        return ['condition' => $conditions, 'fields' => $fields, 'defaults' => $defaults];
2625
    }
2626
2627
    /**
2628
     * @param $filters
2629
     * @param string $stringToSearch
2630
     *
2631
     * @return array
2632
     */
2633
    public function getExtraFieldRules($filters, $stringToSearch = 'extra_', $condition = 'OR')
2634
    {
2635
        $extraFields = [];
2636
        $conditionArray = [];
2637
2638
        // Getting double select if exists
2639
        $double_select = [];
2640
        if (is_object($filters) &&
2641
            property_exists($filters, 'rules') &&
2642
            is_array($filters->rules) &&
2643
            !empty($filters->rules)
2644
        ) {
2645
            foreach ($filters->rules as $rule) {
2646
                if (empty($rule)) {
2647
                    continue;
2648
                }
2649
                if (false === strpos($rule->field, '_second')) {
2650
                } else {
2651
                    $my_field = str_replace('_second', '', $rule->field);
2652
                    $double_select[$my_field] = $rule->data;
2653
                }
2654
            }
2655
2656
            foreach ($filters->rules as $rule) {
2657
                if (empty($rule)) {
2658
                    continue;
2659
                }
2660
                if (false === strpos($rule->field, $stringToSearch)) {
2661
                    // normal fields
2662
                    $field = $rule->field;
2663
                    if (isset($rule->data) && is_string($rule->data) && -1 != $rule->data) {
2664
                        $conditionArray[] = $this->get_where_clause($field, $rule->op, $rule->data);
2665
                    }
2666
                } else {
2667
                    // Extra fields
2668
                    $ruleField = Database::escapeField($rule->field);
2669
                    if (false === strpos($rule->field, '_second')) {
2670
                        //No _second
2671
                        $original_field = str_replace($stringToSearch, '', $rule->field);
2672
                        $field_option = $this->get_handler_field_info_by_field_variable($original_field);
2673
2674
                        switch ($field_option['field_type']) {
2675
                            case self::FIELD_TYPE_DOUBLE_SELECT:
2676
                            if (isset($double_select[$rule->field])) {
2677
                                $data = explode('#', $rule->data);
2678
                                $rule->data = $data[1].'::'.$double_select[$rule->field];
2679
                            } else {
2680
                                // only was sent 1 select
2681
                                if (is_string($rule->data)) {
2682
                                    $data = explode('#', $rule->data);
2683
                                    $rule->data = $data[1];
2684
                                }
2685
                            }
2686
2687
                            if (!isset($rule->data)) {
2688
                                $conditionArray[] = ' ('
2689
                                .$this->get_where_clause($rule->field, $rule->op, $rule->data)
2690
                                .') ';
2691
                                $extraFields[] = ['field' => $ruleField, 'id' => $field_option['id']];
2692
                            }
2693
                                break;
2694
                            case self::FIELD_TYPE_TAG:
2695
                            if (isset($rule->data)) {
2696
                                if (is_int($rule->data) && -1 == $rule->data) {
2697
                                    break;
2698
                                }
2699
2700
                                    // Where will be injected in the parseConditions()
2701
                                //$where = $this->get_where_clause($rule->field, $rule->op, $rule->data, 'OR');
2702
                                //$conditionArray[] = " ( $where ) ";
2703
                                $extraFields[] = [
2704
                                        'field' => $ruleField,
2705
                                'id' => $field_option['id'],
2706
                                'data' => $rule->data,
2707
                            ];
2708
                            }
2709
                                break;
2710
                            default:
2711
                                if (isset($rule->data)) {
2712
                                    if (is_int($rule->data) && -1 == $rule->data) {
2713
                                        break;
2714
                                    }
2715
                                    $where = $this->get_where_clause($rule->field, $rule->op, $rule->data, 'OR');
2716
                                    $conditionArray[] = " ( $where ) ";
2717
                                    $extraFields[] = [
2718
                                        'field' => $ruleField,
2719
                                        'id' => $field_option['id'],
2720
                                        'data' => $rule->data,
2721
                                    ];
2722
                                }
2723
                                break;
2724
                        }
2725
                    } else {
2726
                        $my_field = str_replace('_second', '', $rule->field);
2727
                        $original_field = str_replace($stringToSearch, '', $my_field);
2728
                        $field_option = $this->get_handler_field_info_by_field_variable($original_field);
2729
                        $extraFields[] = [
2730
                            'field' => $ruleField,
2731
                        'id' => $field_option['id'],
2732
                    ];
2733
                    }
2734
                }
2735
            }
2736
        }
2737
2738
        return ['extra_fields' => $extraFields, 'condition_array' => $conditionArray];
2739
    }
2740
2741
    /**
2742
     * @param $col
2743
     * @param $oper
2744
     * @param $val
2745
     * @param $conditionBetweenOptions
2746
     *
2747
     * @return string
2748
     */
2749
    public function get_where_clause($col, $oper, $val, $conditionBetweenOptions = 'OR')
2750
    {
2751
        $col = Database::escapeField($col);
2752
2753
        if (empty($col)) {
2754
            return '';
2755
        }
2756
        $conditionBetweenOptions = in_array($conditionBetweenOptions, ['OR', 'AND']) ? $conditionBetweenOptions : 'OR';
2757
        if ('bw' === $oper || 'bn' === $oper) {
2758
            $val .= '%';
2759
        }
2760
        if ('ew' === $oper || 'en' === $oper) {
2761
            $val = '%'.$val;
2762
        }
2763
        if ('cn' === $oper || 'nc' === $oper || 'in' === $oper || 'ni' === $oper) {
2764
            if (is_array($val)) {
2765
                $result = '"%'.implode(';', $val).'%"';
2766
                foreach ($val as $item) {
2767
                    $item = trim($item);
2768
                    $result .= ' '.$conditionBetweenOptions.' '.$col.' LIKE "%'.$item.'%"';
2769
                }
2770
                $val = $result;
2771
2772
                return " $col {$this->ops[$oper]} $val ";
2773
            } else {
2774
                if (is_string($val)) {
2775
                    $val = '%'.$val.'%';
2776
                } else {
2777
                    $val = '';
2778
                }
2779
            }
2780
        }
2781
        $val = \Database::escape_string($val);
2782
2783
        return " $col {$this->ops[$oper]} '$val' ";
2784
    }
2785
2786
    /**
2787
     * @param array  $options
2788
     * @param string $alias
2789
     *
2790
     * @return array
2791
     */
2792
    public function parseConditions($options, $alias = 's')
2793
    {
2794
        $inject_extra_fields = null;
2795
        $extraFieldOption = new ExtraFieldOption($this->type);
2796
        $double_fields = [];
2797
2798
        if (isset($options['extra'])) {
2799
            $extra_fields = $options['extra'];
2800
            if (!empty($extra_fields)) {
2801
                $counter = 1;
2802
                $extra_field_obj = new ExtraField($this->type);
2803
                foreach ($extra_fields as &$extra) {
2804
                    if (!isset($extra['id'])) {
2805
                        continue;
2806
                    }
2807
                    $extra_field_info = $extra_field_obj->get($extra['id']);
2808
                    if (empty($extra_field_info)) {
2809
                        continue;
2810
                    }
2811
                    $extra['extra_field_info'] = $extra_field_info;
2812
2813
                    switch ($extra_field_info['field_type']) {
2814
                        case self::FIELD_TYPE_SELECT:
2815
                        case self::FIELD_TYPE_DOUBLE_SELECT:
2816
                            $inject_extra_fields .= " fvo$counter.display_text as {$extra['field']}, ";
2817
                            break;
2818
                        case self::FIELD_TYPE_TAG:
2819
                            // If using OR
2820
                            // If using AND
2821
                            $newCounter = 1;
2822
                            $fields = [];
2823
                            $tagAlias = $extra['field'];
2824
                            foreach ($extra['data'] as $data) {
2825
                                $fields[] = "tag$counter$newCounter.tag";
2826
                                $newCounter++;
2827
                            }
2828
2829
                            if (!empty($fields)) {
2830
                                $tags = implode(' , " ", ', $fields);
2831
                                $inject_extra_fields .= " CONCAT($tags) as $tagAlias, ";
2832
                            }
2833
                            break;
2834
                        default:
2835
                            $inject_extra_fields .= " fv$counter.value as {$extra['field']}, ";
2836
                            break;
2837
                    }
2838
2839
                    if (isset($extra_fields_info[$extra['id']])) {
2840
                        $info = $extra_fields_info[$extra['id']];
2841
                    } else {
2842
                        $info = $this->get($extra['id']);
2843
                        $extra_fields_info[$extra['id']] = $info;
2844
                    }
2845
                    if (isset($info['field_type']) && self::FIELD_TYPE_DOUBLE_SELECT == $info['field_type']) {
2846
                        $double_fields[$info['id']] = $info;
2847
                    }
2848
                    $counter++;
2849
                }
2850
            }
2851
        }
2852
2853
        $options_by_double = [];
2854
        foreach ($double_fields as $double) {
2855
            $my_options = $extraFieldOption->get_field_options_by_field($double['id'], true);
2856
            $options_by_double['extra_'.$double['variable']] = $my_options;
2857
        }
2858
2859
        $field_value_to_join = [];
2860
        //filter can be all/any = and/or
2861
        $inject_joins = null;
2862
        $inject_where = null;
2863
        $where = null;
2864
2865
        // Removing double 1=1
2866
        if (!empty($options['extra']) && !empty($extra_fields)) {
2867
            // Removing double 1=1
2868
            if (empty($options['where'])) {
2869
                $options['where'] = ' 1 = 1 ';
2870
            }
2871
            $options['where'] = str_replace(' 1 = 1  AND', '', $options['where']);
2872
            // Always OR
2873
            $counter = 1;
2874
            foreach ($extra_fields as $extra_info) {
2875
                $extra_field_info = $extra_info['extra_field_info'];
2876
                $inject_joins .= " INNER JOIN $this->table_field_values fv$counter
2877
                                       ON ($alias.".$this->primaryKey." = fv$counter.".$this->handler_id.') ';
2878
                // Add options
2879
                switch ($extra_field_info['field_type']) {
2880
                        case self::FIELD_TYPE_SELECT:
2881
                        case self::FIELD_TYPE_DOUBLE_SELECT:
2882
                            $options['where'] = str_replace(
2883
                                $extra_info['field'],
2884
                                'fv'.$counter.'.field_id = '.$extra_info['id'].' AND fvo'.$counter.'.option_value',
2885
                                $options['where']
2886
                            );
2887
                            $inject_joins .= "
2888
                                 INNER JOIN $this->table_field_options fvo$counter
2889
                                 ON (
2890
                                    fv$counter.field_id = fvo$counter.field_id AND
2891
                                    fv$counter.value = fvo$counter.option_value
2892
                                 )
2893
                                ";
2894
                            break;
2895
                        case self::FIELD_TYPE_TAG:
2896
                            $newCounter = 1;
2897
                            if (isset($extra_info['data']) && !empty($extra_info['data'])) {
2898
                                $whereTag = [];
2899
                                foreach ($extra_info['data'] as $data) {
2900
                                    $data = Database::escape_string($data);
2901
                                    $key = $counter.$newCounter;
2902
                                    $whereTag[] = ' tag'.$key.'.tag LIKE "%'.$data.'%" ';
2903
                                    $inject_joins .= "
2904
                                        INNER JOIN $this->table_field_rel_tag tag_rel$key
2905
                                        ON (
2906
                                            tag_rel$key.field_id = ".$extra_info['id']." AND
2907
                                            tag_rel$key.item_id = $alias.".$this->primaryKey."
2908
                                        )
2909
                                        INNER JOIN $this->table_field_tag tag$key
2910
                                        ON (tag$key.id = tag_rel$key.tag_id)
2911
                                    ";
2912
                                    $newCounter++;
2913
                                }
2914
                                if (!empty($whereTag)) {
2915
                                    $options['where'] .= ' AND  ('.implode(' AND ', $whereTag).') ';
2916
                                }
2917
                            }
2918
                            break;
2919
                        default:
2920
                            // text, textarea, etc
2921
                            $options['where'] = str_replace(
2922
                                $extra_info['field'],
2923
                                'fv'.$counter.'.field_id = '.$extra_info['id'].' AND fv'.$counter.'.value',
2924
                                $options['where']
2925
                            );
2926
                            break;
2927
                    }
2928
                $field_value_to_join[] = " fv$counter.$this->handler_id ";
2929
                $counter++;
2930
            }
2931
        }
2932
2933
        if (!empty($options['where'])) {
2934
            $where .= ' AND '.$options['where'];
2935
        }
2936
2937
        $order = '';
2938
        if (!empty($options['order'])) {
2939
            $order = ' ORDER BY '.$options['order'];
2940
        }
2941
        $limit = '';
2942
        if (!empty($options['limit'])) {
2943
            $limit = ' LIMIT '.$options['limit'];
2944
        }
2945
2946
        return [
2947
            'order' => $order,
2948
            'limit' => $limit,
2949
            'where' => $where,
2950
            'inject_where' => $inject_where,
2951
            'inject_joins' => $inject_joins,
2952
            'field_value_to_join' => $field_value_to_join,
2953
            'inject_extra_fields' => $inject_extra_fields,
2954
        ];
2955
    }
2956
2957
    /**
2958
     * Get the extra fields and their formatted values.
2959
     *
2960
     * @param int|string $itemId   The item ID (It could be a session_id, course_id or user_id)
2961
     * @param bool       $filter
2962
     * @param array      $onlyShow (list of extra fields variables to show)
2963
     *
2964
     * @return array The extra fields data
2965
     */
2966
    public function getDataAndFormattedValues($itemId, $filter = false, $onlyShow = [])
2967
    {
2968
        $valuesData = [];
2969
        $fields = $this->get_all();
2970
        $em = Database::getManager();
2971
        $repoTag = $em->getRepository(ExtraFieldRelTag::class);
2972
2973
        foreach ($fields as $field) {
2974
            if ('1' != $field['visible_to_self']) {
2975
                continue;
2976
            }
2977
2978
            if ($filter && 1 != $field['filter']) {
2979
                continue;
2980
            }
2981
2982
            if (!empty($onlyShow) && !in_array($field['variable'], $onlyShow)) {
2983
                continue;
2984
            }
2985
2986
            $valueAsArray = [];
2987
            $fieldValue = new ExtraFieldValue($this->type);
2988
            $valueData = $fieldValue->get_values_by_handler_and_field_id($itemId, $field['id'], true);
2989
2990
            $fieldType = (int) $field['field_type'];
2991
            if (self::FIELD_TYPE_TAG === $fieldType) {
2992
                $tags = $repoTag->findBy(['field' => $field['id'], 'itemId' => $itemId]);
2993
                if ($tags) {
2994
                    $data = [];
2995
                    /** @var ExtraFieldRelTag $tag */
2996
                    foreach ($tags as $extraFieldTag) {
2997
                        $tag = $extraFieldTag->getTag();
2998
                        $data[] = $tag->getTag();
2999
                    }
3000
                    $valueData = implode(',', $data);
3001
                    $valueAsArray = $data;
3002
                }
3003
            }
3004
3005
            if (!$valueData) {
3006
                continue;
3007
            }
3008
            $displayedValue = get_lang('None');
3009
            switch ($fieldType) {
3010
                case self::FIELD_TYPE_CHECKBOX:
3011
                    $displayedValue = get_lang('No');
3012
                    if (false !== $valueData && '1' == $valueData['value']) {
3013
                        $displayedValue = get_lang('Yes');
3014
                    }
3015
                    break;
3016
                case self::FIELD_TYPE_DATE:
3017
                    if (false !== $valueData && !empty($valueData['value'])) {
3018
                        $displayedValue = api_format_date($valueData['value'], DATE_FORMAT_LONG_NO_DAY);
3019
                    }
3020
                    break;
3021
                case self::FIELD_TYPE_TAG:
3022
                    if (!empty($valueData)) {
3023
                        $displayedValue = $valueData;
3024
                    }
3025
                    break;
3026
                case self::FIELD_TYPE_FILE:
3027
                case self::FIELD_TYPE_FILE_IMAGE:
3028
                    if (false === $valueData || empty($valueData['asset_id'])) {
3029
                        break;
3030
                    }
3031
                    $assetId = $valueData['asset_id'];
3032
                    $assetRepo = Container::getAssetRepository();
3033
                    /** @var Asset|null $asset */
3034
                    $asset = $assetRepo->find($assetId);
3035
3036
                    if (null === $asset) {
3037
                        break;
3038
                    }
3039
3040
                    $url = $assetRepo->getAssetUrl($asset);
3041
3042
                    if (self::FIELD_TYPE_FILE_IMAGE === $fieldType) {
3043
                        $image = Display::img(
3044
                            $url,
3045
                            $field['display_text'],
3046
                            ['width' => '300'],
3047
                            false
3048
                        );
3049
                        $displayedValue = Display::url(
3050
                            $image,
3051
                            $url,
3052
                            ['target' => '_blank']
3053
                        );
3054
                    } else {
3055
                        $displayedValue = Display::url(
3056
                            get_lang('Download'),
3057
                            $url,
3058
                            [
3059
                                'title' => $field['display_text'],
3060
                                'target' => '_blank',
3061
                                'class' => 'download_extra_field',
3062
                            ]
3063
                        );
3064
                    }
3065
                    break;
3066
                default:
3067
                    $displayedValue = $valueData['value'];
3068
                    break;
3069
            }
3070
3071
            $valuesData[] = [
3072
                'variable' => $field['variable'],
3073
                'text' => $field['display_text'],
3074
                'value' => $displayedValue,
3075
                'value_as_array' => $valueAsArray,
3076
            ];
3077
        }
3078
3079
        return $valuesData;
3080
    }
3081
3082
    /**
3083
     * @param int    $fieldId
3084
     * @param string $tag
3085
     *
3086
     * @return array
3087
     */
3088
    public function getAllUserPerTag($fieldId, $tag)
3089
    {
3090
        $tagRelUserTable = Database::get_main_table(TABLE_MAIN_USER_REL_TAG);
3091
        $tag = Database::escape_string($tag);
3092
        $fieldId = (int) $fieldId;
3093
3094
        $sql = "SELECT user_id
3095
                FROM {$this->table_field_tag} f INNER JOIN $tagRelUserTable ft
3096
                ON tag_id = f.id
3097
                WHERE tag = '$tag' AND f.field_id = $fieldId;
3098
        ";
3099
3100
        $result = Database::query($sql);
3101
3102
        return Database::store_result($result, 'ASSOC');
3103
    }
3104
3105
    /**
3106
     * @param int $fieldId
3107
     * @param int $tagId
3108
     *
3109
     * @return array
3110
     */
3111
    public function getAllSkillPerTag($fieldId, $tagId)
3112
    {
3113
        $skillTable = Database::get_main_table(TABLE_MAIN_SKILL);
3114
        $tagRelExtraTable = Database::get_main_table(TABLE_MAIN_EXTRA_FIELD_REL_TAG);
3115
        $fieldId = (int) $fieldId;
3116
        $tagId = (int) $tagId;
3117
3118
        $sql = "SELECT s.id
3119
                FROM $skillTable s INNER JOIN $tagRelExtraTable t
3120
                ON t.item_id = s.id
3121
                WHERE tag_id = $tagId AND t.field_id = $fieldId;
3122
        ";
3123
3124
        $result = Database::query($sql);
3125
        $result = Database::store_result($result, 'ASSOC');
3126
3127
        $skillList = [];
3128
        foreach ($result as $index => $value) {
3129
            $skillList[$value['id']] = $value['id'];
3130
        }
3131
3132
        return $skillList;
3133
    }
3134
3135
    /**
3136
     * @param string $from
3137
     * @param string $search
3138
     * @param array  $options
3139
     *
3140
     * @return array
3141
     */
3142
    public function searchOptionsFromTags($from, $search, $options)
3143
    {
3144
        $extraFieldInfo = $this->get_handler_field_info_by_field_variable(str_replace('extra_', '', $from));
3145
        $extraFieldInfoTag = $this->get_handler_field_info_by_field_variable(str_replace('extra_', '', $search));
3146
        if (empty($extraFieldInfo) || empty($extraFieldInfoTag)) {
3147
            return [];
3148
        }
3149
3150
        $id = $extraFieldInfo['id'];
3151
        $tagId = $extraFieldInfoTag['id'];
3152
3153
        $table = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
3154
        $tagRelExtraTable = Database::get_main_table(TABLE_MAIN_EXTRA_FIELD_REL_TAG);
3155
        $tagTable = Database::get_main_table(TABLE_MAIN_TAG);
3156
        $optionsTable = Database::get_main_table(TABLE_EXTRA_FIELD_OPTIONS);
3157
        $cleanOptions = [];
3158
        foreach ($options as $option) {
3159
            $cleanOptions[] = Database::escape_string($option);
3160
        }
3161
        $cleanOptions = array_filter($cleanOptions);
3162
3163
        if (empty($cleanOptions)) {
3164
            return [];
3165
        }
3166
3167
        $value = implode("','", $cleanOptions);
3168
3169
        $sql = "SELECT DISTINCT t.*, v.value, o.display_text
3170
                FROM $tagRelExtraTable te
3171
                INNER JOIN $tagTable t
3172
                ON (t.id = te.tag_id AND te.field_id = t.field_id AND te.field_id = $tagId)
3173
                INNER JOIN $table v
3174
                ON (te.item_id = v.item_id AND v.field_id = $id)
3175
                INNER JOIN $optionsTable o
3176
                ON (o.option_value = v.value)
3177
                WHERE v.value IN ('".$value."')
3178
                ORDER BY o.option_order, t.tag
3179
               ";
3180
        $result = Database::query($sql);
3181
3182
        return Database::store_result($result);
3183
    }
3184
3185
    public static function getExtraFieldTypesWithFiles(): array
3186
    {
3187
        return [self::FIELD_TYPE_FILE_IMAGE, self::FIELD_TYPE_FILE];
3188
    }
3189
3190
    /**
3191
     * @param \FormValidator $form
3192
     * @param int            $defaultValueId
3193
     * @param bool           $freezeElement
3194
     */
3195
    private function addSelectElement(FormValidator $form, array $fieldDetails, $defaultValueId, $freezeElement = false)
3196
    {
3197
        $get_lang_variables = false;
3198
        if (in_array(
3199
            $fieldDetails['variable'],
3200
            ['mail_notify_message', 'mail_notify_invitation', 'mail_notify_group_message']
3201
        )) {
3202
            $get_lang_variables = true;
3203
        }
3204
3205
        // Get extra field workflow
3206
        $addOptions = [];
3207
        $optionsExists = false;
3208
        $options = [];
3209
3210
        $optionList = [];
3211
        if (!empty($fieldDetails['options'])) {
3212
            foreach ($fieldDetails['options'] as $option_details) {
3213
                $optionList[$option_details['id']] = $option_details;
3214
                if ($get_lang_variables) {
3215
                    $options[$option_details['option_value']] = $option_details['display_text'];
3216
                } else {
3217
                    if ($optionsExists) {
3218
                        // Adding always the default value
3219
                        if ($option_details['id'] == $defaultValueId) {
3220
                            $options[$option_details['option_value']] = $option_details['display_text'];
3221
                        } else {
3222
                            if (isset($addOptions) && !empty($addOptions)) {
3223
                                // Parsing filters
3224
                                if (in_array($option_details['id'], $addOptions)) {
3225
                                    $options[$option_details['option_value']] = $option_details['display_text'];
3226
                                }
3227
                            }
3228
                        }
3229
                    } else {
3230
                        // Normal behaviour
3231
                        $options[$option_details['option_value']] = $option_details['display_text'];
3232
                    }
3233
                }
3234
            }
3235
3236
            // Setting priority message
3237
            if (isset($optionList[$defaultValueId])
3238
                && isset($optionList[$defaultValueId]['priority'])
3239
            ) {
3240
                if (!empty($optionList[$defaultValueId]['priority'])) {
3241
                    $priorityId = $optionList[$defaultValueId]['priority'];
3242
                    $option = new ExtraFieldOption($this->type);
3243
                    $messageType = $option->getPriorityMessageType($priorityId);
3244
                    $form->addElement(
3245
                        'label',
3246
                        null,
3247
                        Display::return_message(
3248
                            $optionList[$defaultValueId]['priority_message'],
3249
                            $messageType
3250
                        )
3251
                    );
3252
                }
3253
            }
3254
        }
3255
3256
        $select = $form->addSelect(
3257
            'extra_'.$fieldDetails['variable'],
3258
            $fieldDetails['display_text'],
3259
            [],
3260
            ['id' => 'extra_'.$fieldDetails['variable']]
3261
        );
3262
3263
        if (empty($defaultValueId)) {
3264
            $select->addOption(get_lang('Please select an option'), '');
3265
        }
3266
3267
        foreach ($options as $value => $text) {
3268
            if (empty($value)) {
3269
                $select->addOption($text, $value);
3270
                continue;
3271
            }
3272
3273
            $valueParts = explode('#', $text);
3274
            $dataValue = count($valueParts) > 1 ? array_shift($valueParts) : '';
3275
3276
            $select->addOption(implode('', $valueParts), $value, ['data-value' => $dataValue]);
3277
        }
3278
3279
        if ($freezeElement) {
3280
            $form->freeze('extra_'.$fieldDetails['variable']);
3281
        }
3282
    }
3283
3284
    /**
3285
     * @param \FormValidator $form
3286
     * @param array          $fieldDetails
3287
     * @param array          $extraData
3288
     * @param bool           $freezeElement
3289
     *
3290
     * @return string JavaScript code
3291
     */
3292
    private function addDoubleSelectElement(FormValidator $form, $fieldDetails, $extraData, $freezeElement = false)
3293
    {
3294
        $firstSelectId = 'first_extra_'.$fieldDetails['variable'];
3295
        $secondSelectId = 'second_extra_'.$fieldDetails['variable'];
3296
3297
        $jqueryReadyContent = "
3298
            $('#$firstSelectId').on('change', function() {
3299
                var id = $(this).val();
3300
3301
                if (!id) {
3302
                    $('#$secondSelectId').empty().selectpicker('refresh');
3303
3304
                    return;
3305
                }
3306
3307
                $.getJSON(_p.web_ajax + 'extra_field.ajax.php?1=1&a=get_second_select_options', {
3308
                    'type': '{$this->type}',
3309
                    'field_id': {$fieldDetails['id']},
3310
                    'option_value_id': id
3311
                })
3312
                    .done(function(data) {
3313
                        $('#$secondSelectId').empty();
3314
                        $.each(data, function(index, value) {
3315
                            $('#second_extra_{$fieldDetails['variable']}').append(
3316
                                $('<option>', {value: index, text: value})
3317
                            );
3318
                        });
3319
                        $('#$secondSelectId').selectpicker('refresh');
3320
                    });
3321
            });
3322
        ";
3323
3324
        $firstId = null;
3325
        if (!empty($extraData)) {
3326
            if (isset($extraData['extra_'.$fieldDetails['variable']])) {
3327
                $firstId = $extraData['extra_'.$fieldDetails['variable']]['extra_'.$fieldDetails['variable']];
3328
            }
3329
        }
3330
3331
        $options = $this->extra_field_double_select_convert_array_to_ordered_array($fieldDetails['options']);
3332
        $values = ['' => get_lang('Select')];
3333
3334
        $second_values = [];
3335
        if (!empty($options)) {
3336
            foreach ($options as $option) {
3337
                foreach ($option as $sub_option) {
3338
                    if ('0' == $sub_option['option_value']) {
3339
                        $values[$sub_option['id']] = $sub_option['display_text'];
3340
3341
                        continue;
3342
                    }
3343
3344
                    if ($firstId === $sub_option['option_value']) {
3345
                        $second_values[$sub_option['id']] = $sub_option['display_text'];
3346
                    }
3347
                }
3348
            }
3349
        }
3350
3351
        $form
3352
            ->defaultRenderer()
3353
            ->setGroupElementTemplate('<p>{element}</p>', 'extra_'.$fieldDetails['variable']);
3354
        $group = [];
3355
        $group[] = $form->createElement(
3356
            'select',
3357
            'extra_'.$fieldDetails['variable'],
3358
            null,
3359
            $values,
3360
            ['id' => $firstSelectId]
3361
        );
3362
        $group[] = $form->createElement(
3363
            'select',
3364
            'extra_'.$fieldDetails['variable'].'_second',
3365
            null,
3366
            $second_values,
3367
            ['id' => $secondSelectId]
3368
        );
3369
        $form->addGroup(
3370
            $group,
3371
            'extra_'.$fieldDetails['variable'],
3372
            $fieldDetails['display_text']
3373
        );
3374
3375
        if ($freezeElement) {
3376
            $form->freeze('extra_'.$fieldDetails['variable']);
3377
        }
3378
3379
        return $jqueryReadyContent;
3380
    }
3381
3382
    /**
3383
     * @param \FormValidator $form
3384
     * @param bool           $freezeElement Optional
3385
     *
3386
     * @return string JavaScript code
3387
     */
3388
    private function addSelectWithTextFieldElement(
3389
        FormValidator $form,
3390
        array $fieldDetails,
3391
        $freezeElement = false
3392
    ) {
3393
        $firstSelectId = 'slct_extra_'.$fieldDetails['variable'];
3394
        $txtSelectId = 'txt_extra_'.$fieldDetails['variable'];
3395
3396
        $jqueryReadyContent = "
3397
            $('#$firstSelectId').on('change', function() {
3398
                var id = $(this).val();
3399
3400
                if (!id) {
3401
                    $('#$txtSelectId').val('');
3402
                }
3403
            });
3404
        ";
3405
3406
        $options = $this->extra_field_double_select_convert_array_to_ordered_array($fieldDetails['options']);
3407
        $values = ['' => get_lang('Select')];
3408
3409
        if (!empty($options)) {
3410
            foreach ($options as $option) {
3411
                foreach ($option as $sub_option) {
3412
                    if ('0' != $sub_option['option_value']) {
3413
                        continue;
3414
                    }
3415
3416
                    $values[$sub_option['id']] = $sub_option['display_text'];
3417
                }
3418
            }
3419
        }
3420
3421
        $form
3422
            ->defaultRenderer()
3423
            ->setGroupElementTemplate('<p>{element}</p>', 'extra_'.$fieldDetails['variable']);
3424
        $group = [];
3425
        $group[] = $form->createElement(
3426
            'select',
3427
            'extra_'.$fieldDetails['variable'],
3428
            null,
3429
            $values,
3430
            ['id' => $firstSelectId]
3431
        );
3432
        $group[] = $form->createElement(
3433
            'text',
3434
            'extra_'.$fieldDetails['variable'].'_second',
3435
            null,
3436
            ['id' => $txtSelectId]
3437
        );
3438
        $form->addGroup(
3439
            $group,
3440
            'extra_'.$fieldDetails['variable'],
3441
            $fieldDetails['display_text']
3442
        );
3443
3444
        if ($freezeElement) {
3445
            $form->freeze('extra_'.$fieldDetails['variable']);
3446
        }
3447
3448
        return $jqueryReadyContent;
3449
    }
3450
3451
    /**
3452
     * @param \FormValidator $form
3453
     * @param bool           $freezeElement
3454
     *
3455
     * @return string
3456
     */
3457
    private function addTripleSelectElement(
3458
        FormValidator $form,
3459
        array $fieldDetails,
3460
        array $extraData,
3461
        $freezeElement
3462
    ) {
3463
        $variable = $fieldDetails['variable'];
3464
        $id = $fieldDetails['id'];
3465
        $slctFirstId = "first_extra$variable";
3466
        $slctSecondId = "second_extra$variable";
3467
        $slctThirdId = "third_extra$variable";
3468
        $langSelect = get_lang('Select');
3469
3470
        $js = "
3471
            (function () {
3472
                var slctFirst = $('#$slctFirstId'),
3473
                    slctSecond = $('#$slctSecondId'),
3474
                    slctThird = $('#$slctThirdId');
3475
3476
                slctFirst.on('change', function () {
3477
                    slctSecond.empty().selectpicker('refresh');
3478
                    slctThird.empty().selectpicker('refresh');
3479
3480
                    var level = $(this).val();
3481
3482
                    if (!level) {
3483
                        return;
3484
                    }
3485
3486
                    $.getJSON(_p.web_ajax + 'extra_field.ajax.php', {
3487
                        'a': 'get_second_select_options',
3488
                        'type': '$this->type',
3489
                        'field_id': $id,
3490
                        'option_value_id': level
3491
                    })
3492
                        .done(function (data) {
3493
                            slctSecond.append(
3494
                                $('<option>', {value: '', text: '$langSelect'})
3495
                            );
3496
3497
                            $.each(data, function (index, value) {
3498
                                var valueParts = value.split('#'),
3499
                                    dataValue = valueParts.length > 1 ? valueParts.shift() : '';
3500
3501
                                slctSecond.append(
3502
                                    $('<option>', {value: index, text: valueParts.join(''), 'data-value': dataValue})
3503
                                );
3504
                            });
3505
3506
                            slctSecond.selectpicker('refresh');
3507
                        });
3508
                });
3509
                slctSecond.on('change', function () {
3510
                    slctThird.empty().selectpicker('refresh');
3511
3512
                    var level = $(this).val();
3513
3514
                    if (!level) {
3515
                        return;
3516
                    }
3517
3518
                    $.getJSON(_p.web_ajax + 'extra_field.ajax.php', {
3519
                        'a': 'get_second_select_options',
3520
                        'type': '$this->type',
3521
                        'field_id': $id,
3522
                        'option_value_id': level
3523
                    })
3524
                        .done(function (data) {
3525
                            slctThird.append(
3526
                                $('<option>', {value: '', text: '$langSelect'})
3527
                            );
3528
3529
                            $.each(data, function (index, value) {
3530
                                var valueParts = value.split('#'),
3531
                                    dataValue = valueParts.length > 1 ? valueParts.shift() : '';
3532
3533
                                slctThird.append(
3534
                                    $('<option>', {value: index, text: valueParts.join(''), 'data-value': dataValue})
3535
                                );
3536
                            });
3537
3538
                            slctThird.selectpicker('refresh');
3539
                        });
3540
                });
3541
            })();
3542
        ";
3543
3544
        $firstId = isset($extraData["extra_$variable"]["extra_$variable"])
3545
            ? $extraData["extra_$variable"]["extra_$variable"]
3546
            : '';
3547
        $secondId = isset($extraData["extra_$variable"]["extra_{$variable}_second"])
3548
            ? $extraData["extra_$variable"]["extra_{$variable}_second"]
3549
            : '';
3550
3551
        $options = $this->tripleSelectConvertArrayToOrderedArray($fieldDetails['options']);
3552
        $values1 = ['' => $langSelect];
3553
        $values2 = ['' => $langSelect];
3554
        $values3 = ['' => $langSelect];
3555
        $level1 = $this->getOptionsFromTripleSelect($options['level1'], 0);
3556
        $level2 = $this->getOptionsFromTripleSelect($options['level2'], $firstId);
3557
        $level3 = $this->getOptionsFromTripleSelect($options['level3'], $secondId);
3558
        /** @var \HTML_QuickForm_select $slctFirst */
3559
        $slctFirst = $form->createElement('select', "extra_$variable", null, $values1, ['id' => $slctFirstId]);
3560
        /** @var \HTML_QuickForm_select $slctSecond */
3561
        $slctSecond = $form->createElement(
3562
            'select',
3563
            "extra_{$variable}_second",
3564
            null,
3565
            $values2,
3566
            ['id' => $slctSecondId]
3567
        );
3568
        /** @var \HTML_QuickForm_select $slctThird */
3569
        $slctThird = $form->createElement('select', "extra_{$variable}_third", null, $values3, ['id' => $slctThirdId]);
3570
3571
        foreach ($level1 as $item1) {
3572
            $valueParts = explode('#', $item1['display_text']);
3573
            $dataValue = count($valueParts) > 1 ? array_shift($valueParts) : '';
3574
            $slctFirst->addOption(implode('', $valueParts), $item1['id'], ['data-value' => $dataValue]);
3575
        }
3576
3577
        foreach ($level2 as $item2) {
3578
            $valueParts = explode('#', $item2['display_text']);
3579
            $dataValue = count($valueParts) > 1 ? array_shift($valueParts) : '';
3580
            $slctSecond->addOption(implode('', $valueParts), $item2['id'], ['data-value' => $dataValue]);
3581
        }
3582
3583
        foreach ($level3 as $item3) {
3584
            $valueParts = explode('#', $item3['display_text']);
3585
            $dataValue = count($valueParts) > 1 ? array_shift($valueParts) : '';
3586
            $slctThird->addOption(implode('', $valueParts), $item3['id'], ['data-value' => $dataValue]);
3587
        }
3588
3589
        $form
3590
            ->defaultRenderer()
3591
            ->setGroupElementTemplate('<p>{element}</p>', "extra_$variable");
3592
        $form->addGroup([$slctFirst, $slctSecond, $slctThird], "extra_$variable", $fieldDetails['display_text']);
3593
3594
        if ($freezeElement) {
3595
            $form->freeze('extra_'.$fieldDetails['variable']);
3596
        }
3597
3598
        return $js;
3599
    }
3600
3601
    /**
3602
     * @param int $parentId
3603
     *
3604
     * @return array
3605
     */
3606
    private static function getOptionsFromTripleSelect(array $options, $parentId)
3607
    {
3608
        return array_filter(
3609
            $options,
3610
            function ($option) use ($parentId) {
3611
                return $option['option_value'] == $parentId;
3612
            }
3613
        );
3614
    }
3615
}
3616