ExtraField   F
last analyzed

Complexity

Total Complexity 464

Size/Duplication

Total Lines 3693
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 2005
dl 0
loc 3693
rs 0.8
c 0
b 0
f 0
wmc 464

56 Methods

Rating   Name   Duplication   Size   Complexity  
B extra_field_double_select_convert_array_to_string() 0 26 7
A extraFieldSelectWithTextConvertArrayToString() 0 16 3
A tripleSelectConvertStringToArray() 0 33 6
A getLocalizationJavascript() 0 145 1
A tripleSelectConvertArrayToString() 0 19 3
A extra_field_double_select_convert_string_to_array() 0 19 4
C return_form() 0 159 9
A __construct() 0 25 5
A getExtraFieldTypeFromString() 0 3 1
A getExtraFieldTypeFromInt() 0 5 1
A getFieldInfoByFieldId() 0 23 3
A get_count() 0 9 1
B getAllGrid() 0 38 9
A getLocalizationInput() 0 31 2
B addElements() 0 78 10
D get_handler_extra_data() 0 85 18
A get_handler_field_info_by_tags() 0 29 3
A getItemType() 0 3 1
A get_all() 0 41 5
C getExtraFieldsData() 0 63 14
A getValidExtraFieldTypes() 0 34 2
A getTypeList() 0 27 1
A display() 0 11 1
A save() 0 17 3
A get_all_extra_field_by_type() 0 16 2
A getJqgridColumnNames() 0 19 2
C get_where_clause() 0 35 14
A setupBreadcrumb() 0 10 3
C getRules() 0 105 10
A clean_parameters() 0 16 4
A get_extra_fields_by_handler() 0 40 5
F parseConditions() 0 162 29
C processExtraFieldSearch() 0 78 15
D getExtraFieldRules() 0 106 26
A delete() 0 17 3
A update() 0 13 3
A getJqgridActionLinks() 0 25 1
A extra_field_double_select_convert_array_to_ordered_array() 0 14 4
A get_field_types() 0 3 1
A get_max_field_order() 0 15 2
A tripleSelectConvertArrayToOrderedArray() 0 15 3
A get_field_type_by_id() 0 8 2
F set_extra_fields_in_form() 0 863 139
A get() 0 3 1
A get_handler_field_info_by_field_variable() 0 31 4
A getJqgridColumnModel() 0 71 2
A getAllSkillPerTag() 0 22 2
A getAllUserPerTag() 0 15 1
B addDoubleSelectElement() 0 88 9
C addSelectElement() 0 86 14
A getOptionsFromTripleSelect() 0 6 1
A searchOptionsFromTags() 0 41 5
C addTripleSelectElement() 0 142 10
A getExtraFieldTypesWithFiles() 0 3 1
B addSelectWithTextFieldElement() 0 61 6
D getDataAndFormattedValues() 0 118 27

How to fix   Complexity   

Complex Class

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

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

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

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

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

2035
        /** @scrutinizer ignore-call */ 
2036
        $fieldInfo = self::get_handler_field_info_by_field_variable($params['variable']);
Loading history...
2036
        $params = $this->clean_parameters($params);
2037
        $params['item_type'] = $this->itemType;
2038
2039
        if ($fieldInfo) {
2040
            return $fieldInfo['id'];
2041
        } else {
2042
            $id = parent::save($params, $showQuery);
2043
            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...
2044
                $fieldOption = new ExtraFieldOption($this->type);
2045
                $params['field_id'] = $id;
2046
                $fieldOption->save($params);
2047
            }
2048
2049
            return $id;
2050
        }
2051
    }
2052
2053
    /**
2054
     * @param string $variable
2055
     *
2056
     * @return array|bool
2057
     */
2058
    public function get_handler_field_info_by_field_variable($variable)
2059
    {
2060
        $variable = Database::escape_string($variable);
2061
        $sql = "SELECT * FROM {$this->table}
2062
                WHERE
2063
                    variable = '$variable' AND
2064
                    item_type = $this->itemType";
2065
        $result = Database::query($sql);
2066
        if (Database::num_rows($result)) {
2067
            $extraFieldRepo = Container::getExtraFieldRepository();
2068
            $row = Database::fetch_assoc($result);
2069
            if ($row) {
2070
                $extraFieldId = $row['id'];
2071
                /** @var EntityExtraField $extraField */
2072
                $field = $extraFieldRepo->find($extraFieldId);
2073
                $row['display_text'] = $field->getDisplayText();
2074
2075
                // All the options of the field
2076
                $sql = "SELECT * FROM $this->table_field_options
2077
                        WHERE field_id='".$extraFieldId."'
2078
                        ORDER BY option_order ASC";
2079
                $result = Database::query($sql);
2080
                while ($option = Database::fetch_array($result)) {
2081
                    $row['options'][$option['id']] = $option;
2082
                }
2083
2084
                return $row;
2085
            }
2086
        }
2087
2088
        return false;
2089
    }
2090
2091
    /**
2092
     * @param array $params
2093
     *
2094
     * @return array
2095
     */
2096
    public function clean_parameters($params)
2097
    {
2098
        if (!isset($params['variable']) || empty($params['variable'])) {
2099
            $params['variable'] = $params['display_text'];
2100
        }
2101
2102
        $params['variable'] = trim(strtolower(str_replace(' ', '_', $params['variable'])));
2103
2104
        if (!isset($params['field_order'])) {
2105
            $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

2105
            /** @scrutinizer ignore-call */ 
2106
            $max_order = self::get_max_field_order();
Loading history...
2106
            $params['field_order'] = $max_order;
2107
        } else {
2108
            $params['field_order'] = (int) $params['field_order'];
2109
        }
2110
2111
        return $params;
2112
    }
2113
2114
    /**
2115
     * @return int
2116
     */
2117
    public function get_max_field_order()
2118
    {
2119
        $sql = "SELECT MAX(field_order)
2120
                FROM {$this->table}
2121
                WHERE
2122
                    item_type = '.$this->itemType.'";
2123
        $res = Database::query($sql);
2124
2125
        $order = 0;
2126
        if (Database::num_rows($res) > 0) {
2127
            $row = Database::fetch_row($res);
2128
            $order = $row[0] + 1;
2129
        }
2130
2131
        return $order;
2132
    }
2133
2134
    /**
2135
     * {@inheritdoc}
2136
     */
2137
    public function update($params, $showQuery = false)
2138
    {
2139
        $params = $this->clean_parameters($params);
2140
        if (isset($params['id'])) {
2141
            $fieldOption = new ExtraFieldOption($this->type);
2142
            $params['field_id'] = $params['id'];
2143
            if (empty($params['value_type'])) {
2144
                $params['value_type'] = $this->type;
2145
            }
2146
            $fieldOption->save($params, $showQuery);
2147
        }
2148
2149
        return parent::update($params, $showQuery);
2150
    }
2151
2152
    /**
2153
     * @param $id
2154
     *
2155
     * @return bool
2156
     */
2157
    public function delete($id)
2158
    {
2159
        $em = Database::getManager();
2160
        $items = $em->getRepository(\Chamilo\CoreBundle\Entity\ExtraFieldSavedSearch::class)->findBy(['field' => $id]);
2161
        if ($items) {
2162
            foreach ($items as $item) {
2163
                $em->remove($item);
2164
            }
2165
            $em->flush();
2166
        }
2167
        $field_option = new ExtraFieldOption($this->type);
2168
        $field_option->delete_all_options_by_field_id($id);
2169
2170
        $session_field_values = new ExtraFieldValue($this->type);
2171
        $session_field_values->delete_all_values_by_field_id($id);
2172
2173
        return parent::delete($id);
2174
    }
2175
2176
    /**
2177
     * @param $breadcrumb
2178
     * @param $action
2179
     */
2180
    public function setupBreadcrumb(&$breadcrumb, $action)
2181
    {
2182
        if ('add' === $action) {
2183
            $breadcrumb[] = ['url' => $this->pageUrl, 'name' => $this->pageName];
2184
            $breadcrumb[] = ['url' => '#', 'name' => get_lang('Add')];
2185
        } elseif ('edit' === $action) {
2186
            $breadcrumb[] = ['url' => $this->pageUrl, 'name' => $this->pageName];
2187
            $breadcrumb[] = ['url' => '#', 'name' => get_lang('Edit')];
2188
        } else {
2189
            $breadcrumb[] = ['url' => '#', 'name' => $this->pageName];
2190
        }
2191
    }
2192
2193
    /**
2194
     * Displays the title + grid.
2195
     */
2196
    public function display()
2197
    {
2198
        $actions = '<a href="../admin/index.php">';
2199
        $actions .= Display::getMdiIcon(ActionIcon::BACK, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Back to').' '.get_lang('Administration'));
2200
        $actions .= '</a>';
2201
        $actions .= '<a href="'.api_get_self().'?action=add&type='.$this->type.'">';
2202
        $actions .= Display::getMdiIcon(ActionIcon::ADD, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Add'));
2203
        $actions .= '</a>';
2204
2205
        echo Display::toolbarAction('toolbar', [$actions]);
2206
        echo Display::grid_html($this->type.'_fields');
2207
    }
2208
2209
    /**
2210
     * @return array
2211
     */
2212
    public function getJqgridColumnNames()
2213
    {
2214
        $columns = [
2215
            get_lang('Name'),
2216
            get_lang('Field label'),
2217
            get_lang('Type'),
2218
            get_lang('Can change'),
2219
            get_lang('Visible to self'),
2220
            get_lang('Visible to others'),
2221
            get_lang('Filter'),
2222
            get_lang('Order'),
2223
            get_lang('Detail'),
2224
        ];
2225
2226
        if ($this->type === 'user') {
2227
            array_splice($columns, -1, 0, get_lang('Auto remove'));
2228
        }
2229
2230
        return $columns;
2231
    }
2232
2233
    /**
2234
     * @return array
2235
     */
2236
    public function getJqgridColumnModel()
2237
    {
2238
        $columnModel = [
2239
            [
2240
                'name' => 'display_text',
2241
                'index' => 'display_text',
2242
                'align' => 'left',
2243
            ],
2244
            [
2245
                'name' => 'variable',
2246
                'index' => 'variable',
2247
                'align' => 'left',
2248
                'sortable' => 'true',
2249
            ],
2250
            [
2251
                'name' => 'value_type',
2252
                'index' => 'value_type',
2253
                'align' => 'left',
2254
                'sortable' => 'true',
2255
            ],
2256
            [
2257
                'name' => 'changeable',
2258
                'index' => 'changeable',
2259
                'align' => 'center',
2260
                'sortable' => 'true',
2261
            ],
2262
            [
2263
                'name' => 'visible_to_self',
2264
                'index' => 'visible_to_self',
2265
                'align' => 'center',
2266
                'sortable' => 'true',
2267
            ],
2268
            [
2269
                'name' => 'visible_to_others',
2270
                'index' => 'visible_to_others',
2271
                'align' => 'center',
2272
                'sortable' => 'true',
2273
            ],
2274
            [
2275
                'name' => 'filter',
2276
                'index' => 'filter',
2277
                'align' => 'center',
2278
                'sortable' => 'true',
2279
            ],
2280
            [
2281
                'name' => 'field_order',
2282
                'index' => 'field_order',
2283
                'align' => 'center',
2284
                'sortable' => 'true',
2285
            ],
2286
            [
2287
                'name' => 'actions',
2288
                'index' => 'actions',
2289
                'align' => 'center',
2290
                'formatter' => 'action_formatter',
2291
                'sortable' => 'false',
2292
            ],
2293
        ];
2294
2295
        if ($this->type === 'user') {
2296
            $autoRemoveColumnModel = [
2297
                'name' => 'auto_remove',
2298
                'index' => 'auto_remove',
2299
                'align' => 'center',
2300
                'sortable' => 'true',
2301
            ];
2302
2303
            array_splice($columnModel, -1, 0, [$autoRemoveColumnModel]);
2304
        }
2305
2306
        return $columnModel;
2307
    }
2308
2309
    /**
2310
     * @param string $url
2311
     * @param string $action
2312
     *
2313
     * @return FormValidator
2314
     */
2315
    public function return_form($url, $action)
2316
    {
2317
        $form = new FormValidator($this->type.'_field', 'post', $url);
2318
2319
        $form->addHidden('type', $this->type);
2320
        $id = isset($_GET['id']) ? (int) $_GET['id'] : null;
2321
        $form->addHidden('id', $id);
2322
2323
        // Setting the form elements
2324
        $header = get_lang('Add');
2325
        $defaults = [];
2326
2327
        if ('edit' === $action) {
2328
            $header = get_lang('Edit');
2329
            // Setting the defaults
2330
            $defaults = $this->get($id);
2331
        }
2332
2333
        $form->addHeader($header);
2334
2335
        if ('edit' === $action) {
2336
            $translateUrl = Container::getRouter()->generate(
2337
                'legacy_main',
2338
                ['name' => 'extrafield/translate.php', 'extra_field' => $id]
2339
            );
2340
            $translateButton = Display::toolbarButton(
2341
                get_lang('Translate this term'),
2342
                $translateUrl,
2343
                'language',
2344
                'plain'
2345
            );
2346
2347
            $form->addElement('text', 'display_text', [get_lang('Name'), $translateButton]);
2348
        } else {
2349
            $form->addText('display_text', get_lang('Name'));
2350
        }
2351
2352
        $form->addHtmlEditor('description', get_lang('Description'), false);
2353
2354
        // Field type
2355
        $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

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