Passed
Push — master ( 1c618d...c1c6b0 )
by Yannick
10:36 queued 02:52
created

ExtraField::set_extra_fields_in_form()   F

Complexity

Conditions 139
Paths 3

Size

Total Lines 859
Code Lines 537

Duplication

Lines 0
Ratio 0 %

Importance

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

How to fix   Long Method    Complexity    Many Parameters   

Long Method

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

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

Commonly applied refactorings include:

Many Parameters

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

There are several approaches to avoid long parameter lists:

1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
use Chamilo\CoreBundle\Entity\Asset;
6
use Chamilo\CoreBundle\Entity\ExtraField as EntityExtraField;
7
use Chamilo\CoreBundle\Entity\ExtraFieldRelTag;
8
use Chamilo\CoreBundle\Entity\Tag;
9
use Chamilo\CoreBundle\Framework\Container;
10
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
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->select('e.id', 'e.itemType', 'e.valueType', 'e.variable', 'e.displayText', 'e.autoRemove', 'e.changeable', 'e.visibleToOthers', 'e.filter', 'e.visibleToSelf')
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()->getArrayResult();
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 \Chamilo\CoreBundle\Entity\ExtraField $extraField */
641
            $extraField = $extraFieldRepo->find($extraFieldId);
642
            $row['display_text'] = ExtraField::translateDisplayName($row['variable'],$row['display_text']);
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
     * Translate the display text for a extra field.
800
     *
801
     * @param string $variable
802
     * @param string $defaultDisplayText
803
     *
804
     * @return string
805
     */
806
    public static function translateDisplayName($variable, $defaultDisplayText): string
807
    {
808
        // 1st priority variable.
809
        $translatedVariable = get_lang(api_underscore_to_camel_case($variable));
810
        if (api_underscore_to_camel_case($variable) !== $translatedVariable) {
811
            return $translatedVariable;
812
        }
813
814
        // 2nd priority display text.
815
        $translatedDisplayText = get_lang($defaultDisplayText);
816
        if ($defaultDisplayText !== $translatedDisplayText) {
817
            return $translatedDisplayText;
818
        }
819
        return $defaultDisplayText;
820
    }
821
822
    /**
823
     * Return an array of all the extra fields available for this item.
824
     *
825
     * @param int $itemId (session_id, question_id, course id)
826
     *
827
     * @return array
828
     */
829
    public function get_handler_extra_data($itemId)
830
    {
831
        if (empty($itemId)) {
832
            return [];
833
        }
834
835
        $extra_data = [];
836
        $fields = $this->get_all();
837
        $field_values = new ExtraFieldValue($this->type);
838
839
        if (!empty($fields)) {
840
            foreach ($fields as $field) {
841
                $field_value = $fieldValueArray = $field_values->get_values_by_handler_and_field_id(
842
                    $itemId,
843
                    $field['id']
844
                );
845
846
                if (self::FIELD_TYPE_TAG == $field['value_type']) {
847
                    $tags = UserManager::get_user_tags_to_string(
848
                        $itemId,
849
                        $field['id'],
850
                        false
851
                    );
852
                    $extra_data['extra_'.$field['variable']] = $tags;
853
854
                    continue;
855
                }
856
857
                if ($field_value) {
858
                    $variable = $field['variable'];
859
                    $field_value = $field_value['field_value'];
860
                    switch ($field['value_type']) {
861
                        case self::FIELD_TYPE_FILE_IMAGE:
862
                        case self::FIELD_TYPE_FILE:
863
                            // Get asset id
864
                            $extra_data['extra_'.$field['variable']] = $fieldValueArray['asset_id'] ?? 0;
865
                            break;
866
                        case self::FIELD_TYPE_TAG:
867
                            $tags = UserManager::get_user_tags_to_string(
868
                                $itemId,
869
                                $field['id'],
870
                                false
871
                            );
872
873
                            $extra_data['extra_'.$field['variable']] = $tags;
874
                            break;
875
                        case self::FIELD_TYPE_DOUBLE_SELECT:
876
                        case self::FIELD_TYPE_SELECT_WITH_TEXT_FIELD:
877
                            $selected_options = explode('::', $field_value);
878
                            $firstOption = isset($selected_options[0]) ? $selected_options[0] : '';
879
                            $secondOption = isset($selected_options[1]) ? $selected_options[1] : '';
880
                            $extra_data['extra_'.$field['variable']]['extra_'.$field['variable']] = $firstOption;
881
                            $extra_data['extra_'.$field['variable']]['extra_'.$field['variable'].'_second'] = $secondOption;
882
883
                            break;
884
                        case self::FIELD_TYPE_SELECT_MULTIPLE:
885
                            $field_value = explode(';', $field_value);
886
                            $extra_data['extra_'.$field['variable']] = $field_value;
887
                            break;
888
                        case self::FIELD_TYPE_RADIO:
889
                            $extra_data['extra_'.$field['variable']]['extra_'.$field['variable']] = $field_value;
890
                            break;
891
                        case self::FIELD_TYPE_TRIPLE_SELECT:
892
                            [$level1, $level2, $level3] = explode(';', $field_value);
893
894
                            $extra_data["extra_$variable"]["extra_$variable"] = $level1;
895
                            $extra_data["extra_$variable"]["extra_{$variable}_second"] = $level2;
896
                            $extra_data["extra_$variable"]["extra_{$variable}_third"] = $level3;
897
                            break;
898
                        default:
899
                            $extra_data['extra_'.$field['variable']] = $field_value;
900
                            break;
901
                    }
902
                } else {
903
                    // Set default values
904
                    if (isset($field['field_default_value']) &&
905
                        !empty($field['field_default_value'])
906
                    ) {
907
                        $extra_data['extra_'.$field['variable']] = $field['field_default_value'];
908
                    }
909
                }
910
            }
911
        }
912
913
        return $extra_data;
914
    }
915
916
    /**
917
     * Get an array of all the values from the extra_field and extra_field_options tables
918
     * based on the current object's type.
919
     */
920
    public function get_all(array $options = []): array
921
    {
922
        $order_field_options_by = null;
923
924
        if (func_num_args() > 1) {
925
            $order_field_options_by = func_get_arg(1);
926
        }
927
928
        $options = Database::parse_conditions(['where' => $options]);
929
930
        if (empty($options)) {
931
            $options .= ' WHERE item_type = '.$this->itemType;
932
        } else {
933
            $options .= ' AND item_type = '.$this->itemType;
934
        }
935
936
        $sql = "SELECT * FROM $this->table
937
                $options
938
                ORDER BY field_order ASC
939
        ";
940
941
        $result = Database::query($sql);
942
        $extraFields = Database::store_result($result, 'ASSOC');
943
944
        $extraFieldRepo = Container::getExtraFieldRepository();
945
        $option = new ExtraFieldOption($this->type);
946
        if (!empty($extraFields)) {
947
            foreach ($extraFields as &$extraField) {
948
                $extraFieldId = $extraField['id'];
949
                /** @var \Chamilo\CoreBundle\Entity\ExtraField $field */
950
                $field = $extraFieldRepo->find($extraFieldId);
951
                $extraField['display_text'] = self::translateDisplayName($extraField['variable'], $extraField['display_text']);
952
                $extraField['options'] = $option->get_field_options_by_field(
953
                    $extraField['id'],
954
                    false,
955
                    $order_field_options_by
956
                );
957
            }
958
        }
959
960
        return $extraFields;
961
    }
962
963
    /**
964
     * Fetches extra field data with various display and permission checks.
965
     *
966
     * This function retrieves the data for extra fields, applies various filters
967
     * and checks to determine if each field should be displayed based on
968
     * admin permissions, visibility settings, and specific field inclusion or
969
     * exclusion lists. It also handles ordering of fields if an order list is provided.
970
     */
971
    public function getExtraFieldsData(
972
        array $extraData,
973
        bool $adminPermissions = false,
974
        array $extra = [],
975
        array $exclude = [],
976
        array $showOnlyTheseFields = [],
977
        array $orderFields = []
978
    ): array {
979
        $fieldsData = [];
980
981
        if (!empty($extra)) {
982
            $orderedExtraFields = [];
983
            if (!empty($orderFields)) {
984
                foreach ($orderFields as $order) {
985
                    foreach ($extra as $fieldDetails) {
986
                        if ($order == $fieldDetails['variable']) {
987
                            $orderedExtraFields[] = $fieldDetails;
988
                        }
989
                    }
990
                }
991
                $extra = $orderedExtraFields;
992
            }
993
994
            foreach ($extra as $fieldDetails) {
995
                $variable = $fieldDetails['variable'];
996
997
                if (!empty($showOnlyTheseFields) && !in_array($variable, $showOnlyTheseFields)) {
998
                    continue;
999
                }
1000
1001
                if (!$adminPermissions && 0 == $fieldDetails['visible_to_self']) {
1002
                    continue;
1003
                }
1004
1005
                if (in_array($variable, $exclude)) {
1006
                    continue;
1007
                }
1008
1009
                $fieldData = [
1010
                    'type' => $fieldDetails['value_type'],
1011
                    'variable' => $variable,
1012
                    'title' => get_lang($fieldDetails['display_text']),
1013
                    'defaultValue' => $fieldDetails['field_default_value'] ?? '',
1014
                ];
1015
1016
                if (!empty($fieldDetails['options'])) {
1017
                    $fieldData['options'] = array_map(function ($option) {
1018
                        return [
1019
                            'value' => $option['option_value'],
1020
                            'label' => $option['display_text'],
1021
                        ];
1022
                    }, $fieldDetails['options']);
1023
                }
1024
1025
                if (isset($extraData['extra_' . $variable])) {
1026
                    $fieldData['value'] = $extraData['extra_' . $variable];
1027
                }
1028
1029
                $fieldsData[] = $fieldData;
1030
            }
1031
        }
1032
1033
        return $fieldsData;
1034
    }
1035
1036
    /**
1037
     * Add an element that matches the given extra field to the given $form object.
1038
     *
1039
     * @param FormValidator $form                The form these fields are to be attached to
1040
     * @param array         $extraData
1041
     * @param bool          $adminPermissions    Whether the display is considered without edition limits (true) or not
1042
     *                                           (false)
1043
     * @param array         $extra
1044
     * @param int           $itemId              The item (course, user, session, etc) this extra_field is attached to
1045
     * @param array         $exclude             Extra fields to be skipped, by textual ID
1046
     * @param bool          $useTagAsSelect      Whether to show tag fields as select drop-down or not
1047
     * @param array         $showOnlyTheseFields Limit the extra fields shown to just the list given here
1048
     * @param array         $orderFields         An array containing the names of the fields shown, in the right order
1049
     *
1050
     * @throws Exception
1051
     *
1052
     * @return array If relevant, returns a one-element array with JS code to be added to the page HTML headers
1053
     */
1054
    public function set_extra_fields_in_form(
1055
        $form,
1056
        $extraData,
1057
        $adminPermissions = false,
1058
        $extra = [],
1059
        $itemId = null,
1060
        $exclude = [],
1061
        $useTagAsSelect = false,
1062
        $showOnlyTheseFields = [],
1063
        $orderFields = [],
1064
        $orderDependingDefaults = false,
1065
        $separateExtraMultipleSelect = [],
1066
        $customLabelsExtraMultipleSelect = [],
1067
        $addEmptyOptionSelects = false,
1068
        $introductionTextList = [],
1069
        $hideGeoLocalizationDetails = false,
1070
        $help = false
1071
    ) {
1072
        $jquery_ready_content = null;
1073
1074
        $assetRepo = Container::getAssetRepository();
1075
        $extraFieldRepo = Container::getExtraFieldRepository();
1076
1077
        if (!empty($extra)) {
1078
            $newOrder = [];
1079
            if (!empty($orderFields)) {
1080
                foreach ($orderFields as $order) {
1081
                    foreach ($extra as $field_details) {
1082
                        if ($order == $field_details['variable']) {
1083
                            $newOrder[] = $field_details;
1084
                        }
1085
                    }
1086
                }
1087
                $extra = $newOrder;
1088
            }
1089
1090
            foreach ($extra as $field_details) {
1091
                $variable = $field_details['variable'];
1092
                if (!empty($showOnlyTheseFields)) {
1093
                    if (!in_array($variable, $showOnlyTheseFields)) {
1094
                        continue;
1095
                    }
1096
                }
1097
1098
                // Getting default value id if is set
1099
                $defaultValueId = null;
1100
                if (isset($field_details['options']) && !empty($field_details['options'])) {
1101
                    $valueToFind = null;
1102
                    if (isset($field_details['field_default_value'])) {
1103
                        $valueToFind = $field_details['field_default_value'];
1104
                    }
1105
                    // If a value is found we override the default value
1106
                    if (isset($extraData['extra_'.$variable])) {
1107
                        $valueToFind = $extraData['extra_'.$variable];
1108
                    }
1109
1110
                    foreach ($field_details['options'] as $option) {
1111
                        if ($option['option_value'] == $valueToFind) {
1112
                            $defaultValueId = $option['id'];
1113
                        }
1114
                    }
1115
                }
1116
1117
                if (!$adminPermissions) {
1118
                    if (0 == $field_details['visible_to_self']) {
1119
                        continue;
1120
                    }
1121
1122
                    if (in_array($variable, $exclude)) {
1123
                        continue;
1124
                    }
1125
                }
1126
1127
                if (!empty($introductionTextList) &&
1128
                    in_array($variable, array_keys($introductionTextList))
1129
                ) {
1130
                    $form->addHtml($introductionTextList[$variable]);
1131
                }
1132
1133
                $freezeElement = false;
1134
                if (!$adminPermissions) {
1135
                    $freezeElement = 0 == $field_details['visible_to_self'] || 0 == $field_details['changeable'];
1136
                }
1137
1138
                //$translatedDisplayText = $field_details['display_text'];
1139
                /** @var \Chamilo\CoreBundle\Entity\ExtraField $extraField */
1140
                $extraField = $extraFieldRepo->find($field_details['id']);
1141
                $translatedDisplayText = ExtraField::translateDisplayName($field_details['variable'],$field_details['display_text']);
1142
1143
                $translatedDisplayHelpText = '';
1144
                if ($help) {
1145
                    $translatedDisplayHelpText .= get_lang($field_details['display_text'].'Help');
1146
                }
1147
1148
                if (!empty($translatedDisplayText)) {
1149
                    if (!empty($translatedDisplayHelpText)) {
1150
                        // In this case, exceptionally, display_text is an array
1151
                        // which is then treated by display_form()
1152
                        $field_details['display_text'] = [$translatedDisplayText, $translatedDisplayHelpText];
1153
                    } else {
1154
                        // We have an helper text, use it
1155
                        $field_details['display_text'] = $translatedDisplayText;
1156
                    }
1157
                }
1158
1159
                switch ($field_details['value_type']) {
1160
                    case self::FIELD_TYPE_TEXT:
1161
                        $form->addElement(
1162
                            'text',
1163
                            'extra_'.$variable,
1164
                            $field_details['display_text'],
1165
                            [
1166
                                'id' => 'extra_'.$variable,
1167
                            ]
1168
                        );
1169
                        $form->applyFilter(
1170
                            'extra_'.$variable,
1171
                            'stripslashes'
1172
                        );
1173
                        $form->applyFilter(
1174
                            'extra_'.$variable,
1175
                            'trim'
1176
                        );
1177
                        if ($freezeElement) {
1178
                            $form->freeze('extra_'.$variable);
1179
                        }
1180
                        break;
1181
                    case self::FIELD_TYPE_TEXTAREA:
1182
                        $form->addHtmlEditor(
1183
                            'extra_'.$variable,
1184
                            $field_details['display_text'],
1185
                            false,
1186
                            false,
1187
                            [
1188
                                'ToolbarSet' => 'Profile',
1189
                                'Width' => '100%',
1190
                                'Height' => '130',
1191
                                'id' => 'extra_'.$variable,
1192
                            ]
1193
                        );
1194
                        $form->applyFilter('extra_'.$variable, 'stripslashes');
1195
                        $form->applyFilter('extra_'.$variable, 'trim');
1196
                        if ($freezeElement) {
1197
                            $form->freeze('extra_'.$variable);
1198
                        }
1199
                        break;
1200
                    case self::FIELD_TYPE_RADIO:
1201
                        $group = [];
1202
                        if (isset($field_details['options']) &&
1203
                            !empty($field_details['options'])
1204
                        ) {
1205
                            foreach ($field_details['options'] as $option_details) {
1206
                                $options[$option_details['option_value']] = $option_details['display_text'];
1207
                                $group[] = $form->createElement(
1208
                                    'radio',
1209
                                    'extra_'.$variable,
1210
                                    $option_details['option_value'],
1211
                                    get_lang($option_details['display_text']).'<br />',
1212
                                    $option_details['option_value']
1213
                                );
1214
                            }
1215
                        }
1216
                        $form->addGroup(
1217
                            $group,
1218
                            'extra_'.$variable,
1219
                            $field_details['display_text']
1220
                        );
1221
                        if ($freezeElement) {
1222
                            $form->freeze('extra_'.$variable);
1223
                        }
1224
                        break;
1225
                    case self::FIELD_TYPE_CHECKBOX:
1226
                        $group = [];
1227
                        if (isset($field_details['options']) &&
1228
                            !empty($field_details['options'])
1229
                        ) {
1230
                            foreach ($field_details['options'] as $option_details) {
1231
                                $options[$option_details['option_value']] = $option_details['display_text'];
1232
                                $group[] = $form->createElement(
1233
                                    'checkbox',
1234
                                    'extra_'.$variable,
1235
                                    $option_details['option_value'],
1236
                                    get_lang($option_details['display_text']).'<br />',
1237
                                    $option_details['option_value']
1238
                                );
1239
                            }
1240
                        } else {
1241
                            $fieldVariable = "extra_$variable";
1242
                            $checkboxAttributes = [];
1243
                            if (is_array($extraData) &&
1244
                                array_key_exists($fieldVariable, $extraData)
1245
                            ) {
1246
                                if (!empty($extraData[$fieldVariable])) {
1247
                                    $checkboxAttributes['checked'] = 1;
1248
                                }
1249
                            }
1250
1251
                            if (empty($checkboxAttributes) &&
1252
                                isset($field_details['default_value']) && empty($extraData)) {
1253
                                if (1 == $field_details['default_value']) {
1254
                                    $checkboxAttributes['checked'] = 1;
1255
                                }
1256
                            }
1257
1258
                            // We assume that is a switch on/off with 1 and 0 as values
1259
                            $group[] = $form->createElement(
1260
                                'checkbox',
1261
                                'extra_'.$variable,
1262
                                null,
1263
                                get_lang('Yes'),
1264
                                $checkboxAttributes
1265
                            );
1266
                        }
1267
1268
                        $form->addGroup(
1269
                            $group,
1270
                            'extra_'.$variable,
1271
                            $field_details['display_text']
1272
                        );
1273
                        if ($freezeElement) {
1274
                            $form->freeze('extra_'.$variable);
1275
                        }
1276
                        break;
1277
                    case self::FIELD_TYPE_SELECT:
1278
                        $this->addSelectElement($form, $field_details, $defaultValueId, $freezeElement);
1279
                        break;
1280
                    case self::FIELD_TYPE_SELECT_MULTIPLE:
1281
                        $options = [];
1282
                        if (empty($defaultValueId)) {
1283
                            $options[''] = get_lang('Please select an option');
1284
                        }
1285
                        if (isset($field_details['options']) && !empty($field_details['options'])) {
1286
                            foreach ($field_details['options'] as $optionDetails) {
1287
                                $options[$optionDetails['option_value']] = get_lang($optionDetails['display_text']);
1288
                            }
1289
                        }
1290
1291
                        if ($orderDependingDefaults) {
1292
                            if (isset($extraData['extra_'.$variable])) {
1293
                                $defaultOptions = $extraData['extra_'.$variable];
1294
                                $firstList = [];
1295
                                if ($addEmptyOptionSelects) {
1296
                                    $firstList[] = '';
1297
                                }
1298
                                foreach ($defaultOptions as $key) {
1299
                                    if (isset($options[$key])) {
1300
                                        $firstList[$key] = $options[$key];
1301
                                    }
1302
                                }
1303
                                if (!empty($firstList)) {
1304
                                    $options = array_merge($firstList, $options);
1305
                                }
1306
                            } else {
1307
                                $firstList = [];
1308
                                if ($addEmptyOptionSelects) {
1309
                                    $firstList[] = '&nbsp;';
1310
                                    $options = array_merge($firstList, $options);
1311
                                }
1312
                            }
1313
                        }
1314
                        // OFAJ
1315
                        $separateValue = 0;
1316
                        if (isset($separateExtraMultipleSelect[$variable])) {
1317
                            $separateValue = $separateExtraMultipleSelect[$variable];
1318
                        }
1319
1320
                        if ($separateValue > 0) {
1321
                            for ($i = 0; $i < $separateValue; $i++) {
1322
                                $form->addSelect(
1323
                                    'extra_'.$variable.'['.$i.']',
1324
                                    $customLabelsExtraMultipleSelect[$variable][$i],
1325
                                    $options,
1326
                                    ['id' => 'extra_'.$variable.'_'.$i]
1327
                                );
1328
                            }
1329
                        } else {
1330
                            // Ofaj
1331
                            $attributes = ['multiple' => 'multiple', 'id' => 'extra_'.$variable];
1332
                            $chosenSelect = [
1333
                                'ecouter',
1334
                                'lire',
1335
                                'participer_a_une_conversation',
1336
                                's_exprimer_oralement_en_continu',
1337
                                'ecrire',
1338
                            ];
1339
1340
                            if (in_array($variable, $chosenSelect)) {
1341
                                $attributes['select_chosen'] = true;
1342
                            }
1343
1344
                            // default behaviour
1345
                            $form->addSelect(
1346
                                'extra_'.$variable,
1347
                                $field_details['display_text'],
1348
                                $options,
1349
                                $attributes,
1350
                            );
1351
1352
                        }
1353
1354
                        if ($freezeElement) {
1355
                            $form->freeze('extra_'.$variable);
1356
                        }
1357
                        /*$form->addSelect(
1358
                            'extra_'.$variable,
1359
                            $field_details['display_text'],
1360
                            $options,
1361
                            [
1362
                                'multiple' => 'multiple',
1363
                                'id' => 'extra_'.$variable,
1364
                            ]
1365
                        );
1366
                        if ($freezeElement) {
1367
                            $form->freeze('extra_'.$variable);
1368
                        }*/
1369
                        break;
1370
                    case self::FIELD_TYPE_DATE:
1371
                        $form->addDatePicker('extra_'.$variable, $field_details['display_text']);
1372
                        if ($freezeElement) {
1373
                            $form->freeze('extra_'.$variable);
1374
                        }
1375
                        break;
1376
                    case self::FIELD_TYPE_DATETIME:
1377
                        $form->addDateTimePicker(
1378
                            'extra_'.$variable,
1379
                            $field_details['display_text']
1380
                        );
1381
1382
                        $defaults['extra_'.$variable] = api_get_local_time();
1383
                        if (!isset($form->_defaultValues['extra_'.$variable])) {
1384
                            $form->setDefaults($defaults);
1385
                        }
1386
                        if ($freezeElement) {
1387
                            $form->freeze('extra_'.$variable);
1388
                        }
1389
                        break;
1390
                    case self::FIELD_TYPE_DOUBLE_SELECT:
1391
                        $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

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

2055
        /** @scrutinizer ignore-call */ 
2056
        $fieldInfo = self::get_handler_field_info_by_field_variable($params['variable']);
Loading history...
2056
        $params = $this->clean_parameters($params);
2057
        $params['item_type'] = $this->itemType;
2058
2059
        if ($fieldInfo) {
2060
            return $fieldInfo['id'];
2061
        } else {
2062
            $id = parent::save($params, $showQuery);
2063
            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...
2064
                $fieldOption = new ExtraFieldOption($this->type);
2065
                $params['field_id'] = $id;
2066
                $fieldOption->save($params);
2067
            }
2068
2069
            return $id;
2070
        }
2071
    }
2072
2073
    /**
2074
     * @param string $variable
2075
     *
2076
     * @return array|bool
2077
     */
2078
    public function get_handler_field_info_by_field_variable($variable)
2079
    {
2080
        $variable = Database::escape_string($variable);
2081
        $sql = "SELECT * FROM {$this->table}
2082
                WHERE
2083
                    variable = '$variable' AND
2084
                    item_type = $this->itemType";
2085
        $result = Database::query($sql);
2086
        if (Database::num_rows($result)) {
2087
            $extraFieldRepo = Container::getExtraFieldRepository();
2088
            $row = Database::fetch_assoc($result);
2089
            if ($row) {
2090
                $extraFieldId = $row['id'];
2091
                /** @var \Chamilo\CoreBundle\Entity\ExtraField $extraField */
2092
                $field = $extraFieldRepo->find($extraFieldId);
2093
                $row['display_text'] = $this->translateDisplayName($row['variable'], $row['display_text']);
2094
2095
                // All the options of the field
2096
                $sql = "SELECT * FROM $this->table_field_options
2097
                        WHERE field_id='".$extraFieldId."'
2098
                        ORDER BY option_order ASC";
2099
                $result = Database::query($sql);
2100
                while ($option = Database::fetch_array($result)) {
2101
                    $row['options'][$option['id']] = $option;
2102
                }
2103
2104
                return $row;
2105
            }
2106
        }
2107
2108
        return false;
2109
    }
2110
2111
    /**
2112
     * @param array $params
2113
     *
2114
     * @return array
2115
     */
2116
    public function clean_parameters($params)
2117
    {
2118
        if (!isset($params['variable']) || empty($params['variable'])) {
2119
            $params['variable'] = $params['display_text'];
2120
        }
2121
2122
        $params['variable'] = trim(strtolower(str_replace(' ', '_', $params['variable'])));
2123
2124
        if (!isset($params['field_order'])) {
2125
            $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

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

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