ExtraField::getLocalizationJavascript()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 145
Code Lines 34

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 34
nc 1
nop 2
dl 0
loc 145
rs 9.376
c 0
b 0
f 0

How to fix   Long Method   

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:

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\Enums\ActionIcon;
9
use Chamilo\CoreBundle\Framework\Container;
10
11
class ExtraField extends Model
12
{
13
    public const FIELD_TYPE_TEXT = 1;
14
    public const FIELD_TYPE_TEXTAREA = 2;
15
    public const FIELD_TYPE_RADIO = 3;
16
    public const FIELD_TYPE_SELECT = 4;
17
    public const FIELD_TYPE_SELECT_MULTIPLE = 5;
18
    public const FIELD_TYPE_DATE = 6;
19
    public const FIELD_TYPE_DATETIME = 7;
20
    public const FIELD_TYPE_DOUBLE_SELECT = 8;
21
    public const FIELD_TYPE_DIVIDER = 9;
22
    public const FIELD_TYPE_TAG = 10;
23
    public const FIELD_TYPE_TIMEZONE = 11;
24
    public const FIELD_TYPE_SOCIAL_PROFILE = 12;
25
    public const FIELD_TYPE_CHECKBOX = 13;
26
    public const FIELD_TYPE_MOBILE_PHONE_NUMBER = 14;
27
    public const FIELD_TYPE_INTEGER = 15;
28
    public const FIELD_TYPE_FILE_IMAGE = 16;
29
    public const FIELD_TYPE_FLOAT = 17;
30
    public const FIELD_TYPE_FILE = 18;
31
    public const FIELD_TYPE_VIDEO_URL = 19;
32
    public const FIELD_TYPE_LETTERS_ONLY = 20;
33
    public const FIELD_TYPE_ALPHANUMERIC = 21;
34
    public const FIELD_TYPE_LETTERS_SPACE = 22;
35
    public const FIELD_TYPE_ALPHANUMERIC_SPACE = 23;
36
    public const FIELD_TYPE_GEOLOCALIZATION = 24;
37
    public const FIELD_TYPE_GEOLOCALIZATION_COORDINATES = 25;
38
    public const FIELD_TYPE_SELECT_WITH_TEXT_FIELD = 26;
39
    public const FIELD_TYPE_TRIPLE_SELECT = 27;
40
    public const FIELD_TYPE_DURATION = 28;
41
42
    public $columns = [
43
        'id',
44
        'value_type',
45
        'variable',
46
        'description',
47
        'display_text',
48
        'default_value',
49
        'field_order',
50
        'visible_to_self',
51
        'visible_to_others',
52
        'changeable',
53
        'filter',
54
        'item_type',
55
        //Enable this when field_loggeable is introduced as a table field (2.0)
56
        //'field_loggeable',
57
        'created_at',
58
        'auto_remove',
59
    ];
60
61
    public $ops = [
62
        'eq' => '=', //equal
63
        'ne' => '<>', //not equal
64
        'lt' => '<', //less than
65
        'le' => '<=', //less than or equal
66
        'gt' => '>', //greater than
67
        'ge' => '>=', //greater than or equal
68
        'bw' => 'LIKE', //begins with
69
        'bn' => 'NOT LIKE', //doesn't begin with
70
        'in' => 'LIKE', //is in
71
        'ni' => 'NOT LIKE', //is not in
72
        'ew' => 'LIKE', //ends with
73
        'en' => 'NOT LIKE', //doesn't end with
74
        'cn' => 'LIKE', //contains
75
        'nc' => 'NOT LIKE',  //doesn't contain
76
    ];
77
78
    public $type = 'user';
79
    public $pageName;
80
    public $pageUrl;
81
    public $itemType = 0;
82
    public $table_field_options;
83
    public $table_field_values;
84
    public $table_field_tag;
85
    public $table_field_rel_tag;
86
    public $handler_id;
87
    public $primaryKey;
88
89
    /**
90
     * @param string $type
91
     */
92
    public function __construct($type)
93
    {
94
        parent::__construct();
95
96
        $this->type = $type;
97
        $this->table = Database::get_main_table(TABLE_EXTRA_FIELD);
98
        $this->table_field_options = Database::get_main_table(TABLE_EXTRA_FIELD_OPTIONS);
99
        $this->table_field_values = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
100
        $this->table_field_tag = Database::get_main_table(TABLE_MAIN_TAG);
101
        $this->table_field_rel_tag = Database::get_main_table(TABLE_MAIN_EXTRA_FIELD_REL_TAG);
102
        $this->handler_id = 'item_id';
103
        $this->itemType = self::getExtraFieldTypeFromString($this->type);
104
105
        switch ($this->type) {
106
            case 'session':
107
            case 'user':
108
            case 'calendar_event':
109
            case 'course':
110
                $this->primaryKey = 'id';
111
                break;
112
        }
113
114
        $this->pageUrl = 'extra_fields.php?type='.$this->type;
115
        // Example QuestionFields
116
        $this->pageName = ucwords($this->type).'Fields';
117
    }
118
119
    public static function getTypeList(): array
120
    {
121
        return [
122
            'calendar_event' => EntityExtraField::CALENDAR_FIELD_TYPE,
123
            'course' => EntityExtraField::COURSE_FIELD_TYPE,
124
            'user' => EntityExtraField::USER_FIELD_TYPE,
125
            'session' => EntityExtraField::SESSION_FIELD_TYPE,
126
            'exercise' => EntityExtraField::EXERCISE_FIELD_TYPE,
127
            'question' => EntityExtraField::QUESTION_FIELD_TYPE,
128
            'lp' => EntityExtraField::LP_FIELD_TYPE,
129
            'lp_item' => EntityExtraField::LP_ITEM_FIELD_TYPE,
130
            'skill' => EntityExtraField::SKILL_FIELD_TYPE,
131
            'work' => EntityExtraField::WORK_FIELD_TYPE,
132
            'career' => EntityExtraField::CAREER_FIELD_TYPE,
133
            'user_certificate' => EntityExtraField::USER_CERTIFICATE,
134
            'survey' => EntityExtraField::SURVEY_FIELD_TYPE,
135
            'scheduled_announcement' => EntityExtraField::SCHEDULED_ANNOUNCEMENT,
136
            'terms_and_condition' => EntityExtraField::TERMS_AND_CONDITION_TYPE,
137
            'forum_category' => EntityExtraField::FORUM_CATEGORY_TYPE,
138
            'forum_post' => EntityExtraField::FORUM_POST_TYPE,
139
            'track_exercise' => EntityExtraField::TRACK_EXERCISE_FIELD_TYPE,
140
            'portfolio' => EntityExtraField::PORTFOLIO_TYPE,
141
            'lp_view' => EntityExtraField::LP_VIEW_TYPE,
142
            'course_announcement' => EntityExtraField::COURSE_ANNOUNCEMENT,
143
            'message' =>  EntityExtraField::MESSAGE_TYPE,
144
            'document' => EntityExtraField::DOCUMENT_TYPE,
145
            'attendance_calendar' => EntityExtraField::ATTENDANCE_CALENDAR_TYPE,
146
        ];
147
    }
148
149
    public static function getExtraFieldTypeFromString($extraFieldTypeInString): string
150
    {
151
        return self::getTypeList()[$extraFieldTypeInString];
152
    }
153
154
    public static function getExtraFieldTypeFromInt($extraFieldTypeInt)
155
    {
156
        $reversed = array_flip(self::getTypeList());
157
158
        return $reversed[$extraFieldTypeInt];
159
    }
160
161
    /**
162
     * @return array
163
     */
164
    public static function getValidExtraFieldTypes()
165
    {
166
        $result = [
167
            'user',
168
            'course',
169
            'session',
170
            'question',
171
            'lp',
172
            'calendar_event',
173
            'lp_item',
174
            'skill',
175
            'work',
176
            'career',
177
            'user_certificate',
178
            'survey',
179
            'terms_and_condition',
180
            'forum_category',
181
            'forum_post',
182
            'exercise',
183
            'track_exercise',
184
            'lp_view',
185
            'course_announcement',
186
            'message',
187
            'document',
188
            'attendance_calendar',
189
        ];
190
191
        if ('true' === api_get_setting('announcement.allow_scheduled_announcements')) {
192
            $result[] = 'scheduled_announcement';
193
        }
194
        $result[] = 'portfolio';
195
        sort($result);
196
197
        return $result;
198
    }
199
200
    /**
201
     * Converts a string like this:
202
     * France:Paris;Bretagne;Marseille;Lyon|Belgique:Bruxelles;Namur;Liège;Bruges|Peru:Lima;Piura;
203
     * into
204
     * array(
205
     *   'France' =>
206
     *      array('Paris', 'Bretagne', 'Marseille'),
207
     *   'Belgique' =>
208
     *      array('Namur', 'Liège')
209
     * ), etc.
210
     *
211
     * @param string $string
212
     *
213
     * @return array
214
     */
215
    public static function extra_field_double_select_convert_string_to_array($string)
216
    {
217
        $options = explode('|', $string);
218
        $options_parsed = [];
219
        $id = 0;
220
221
        if (!empty($options)) {
222
            foreach ($options as $sub_options) {
223
                $options = explode(':', $sub_options);
224
                $sub_sub_options = isset($options[1]) ? explode(';', $options[1]) : [];
225
                $options_parsed[$id] = [
226
                    'label' => $options[0],
227
                    'options' => $sub_sub_options,
228
                ];
229
                $id++;
230
            }
231
        }
232
233
        return $options_parsed;
234
    }
235
236
    /**
237
     * @param $string
238
     *
239
     * @return array
240
     */
241
    public static function tripleSelectConvertStringToArray($string)
242
    {
243
        $options = [];
244
        foreach (explode('|', $string) as $i => $item0) {
245
            $level1 = explode('\\', $item0);
246
247
            foreach ($level1 as $j => $item1) {
248
                if (0 === $j) {
249
                    $options[] = ['label' => $item1, 'options' => []];
250
251
                    continue;
252
                }
253
254
                foreach (explode(':', $item1) as $k => $item2) {
255
                    if (0 === $k) {
256
                        $options[$i]['options'][] = ['label' => $item2, 'options' => []];
257
258
                        continue;
259
                    }
260
261
                    $options[$i]['options'][$j - 1]['options'][] = explode(';', $item2);
262
                }
263
            }
264
        }
265
266
        array_walk_recursive(
267
            $options,
268
            function (&$item) {
269
                $item = trim($item);
270
            }
271
        );
272
273
        return $options;
274
    }
275
276
    /**
277
     * @param array $options the result of the get_field_options_by_field() array
278
     *
279
     * @return string
280
     */
281
    public static function extra_field_double_select_convert_array_to_string($options)
282
    {
283
        $string = null;
284
        $optionsParsed = self::extra_field_double_select_convert_array_to_ordered_array($options);
285
286
        if (!empty($optionsParsed)) {
287
            foreach ($optionsParsed as $option) {
288
                foreach ($option as $key => $item) {
289
                    $string .= $item['display_text'];
290
                    if (0 == $key) {
291
                        $string .= ':';
292
                    } else {
293
                        if (isset($option[$key + 1])) {
294
                            $string .= ';';
295
                        }
296
                    }
297
                }
298
                $string .= '|';
299
            }
300
        }
301
302
        if (!empty($string)) {
303
            $string = substr($string, 0, strlen($string) - 1);
304
        }
305
306
        return $string;
307
    }
308
309
    /**
310
     * @param array $options The result of the get_field_options_by_field() array
311
     *
312
     * @return string
313
     */
314
    public static function extraFieldSelectWithTextConvertArrayToString(array $options)
315
    {
316
        $parsedOptions = self::extra_field_double_select_convert_array_to_ordered_array($options);
317
318
        if (empty($parsedOptions)) {
319
            return '';
320
        }
321
322
        $string = '';
323
        foreach ($parsedOptions as $options) {
324
            $option = current($options);
325
            $string .= $option['display_text'];
326
            $string .= '|';
327
        }
328
329
        return rtrim($string, '|');
330
    }
331
332
    /**
333
     * @return string
334
     */
335
    public static function tripleSelectConvertArrayToString(array $options)
336
    {
337
        $parsedOptions = self::tripleSelectConvertArrayToOrderedArray($options);
338
        $string = '';
339
        foreach ($parsedOptions['level1'] as $item1) {
340
            $string .= $item1['display_text'];
341
            $level2 = self::getOptionsFromTripleSelect($parsedOptions['level2'], $item1['id']);
342
343
            foreach ($level2 as $item2) {
344
                $string .= '\\'.$item2['display_text'].':';
345
                $level3 = self::getOptionsFromTripleSelect($parsedOptions['level3'], $item2['id']);
346
347
                $string .= implode(';', array_column($level3, 'display_text'));
348
            }
349
350
            $string .= '|';
351
        }
352
353
        return trim($string, '\\|;');
354
    }
355
356
    /**
357
     * @param string $variable
358
     * @param string $dataValue
359
     *
360
     * @return string
361
     */
362
    public static function getLocalizationJavascript($variable, $dataValue)
363
    {
364
        $dataValue = addslashes($dataValue);
365
        $html = "<script>
366
            $(function() {
367
                if (typeof google === 'object') {
368
                    var address = '$dataValue';
369
                    initializeGeo{$variable}(address, false);
370
371
                    $('#geolocalization_extra_{$variable}').on('click', function() {
372
                        var address = $('#{$variable}').val();
373
                        initializeGeo{$variable}(address, false);
374
                        return false;
375
                    });
376
377
                    $('#myLocation_extra_{$variable}').on('click', function() {
378
                        myLocation{$variable}();
379
                        return false;
380
                    });
381
382
                    // When clicking enter
383
                    $('#{$variable}').keypress(function(event) {
384
                        if (event.which == 13) {
385
                            $('#geolocalization_extra_{$variable}').click();
386
                            return false;
387
                        }
388
                    });
389
390
                    // On focus out update city
391
                    $('#{$variable}').focusout(function() {
392
                        $('#geolocalization_extra_{$variable}').click();
393
                        return false;
394
                    });
395
396
                    return;
397
                }
398
399
                $('#map_extra_{$variable}')
400
                    .html('<div class=\"alert alert-info\">"
401
            .addslashes(get_lang('You need to activate the GoogleMaps plugin in adminPlatform to see the Map'))
402
            ."</div>');
403
            });
404
405
            function myLocation{$variable}()
406
            {
407
                if (navigator.geolocation) {
408
                    var geoPosition = function(position) {
409
                        var lat = position.coords.latitude;
410
                        var lng = position.coords.longitude;
411
                        var latLng = new google.maps.LatLng(lat, lng);
412
                        initializeGeo{$variable}(false, latLng);
413
                    };
414
415
                    var geoError = function(error) {
416
                        alert('Geocode ".get_lang('Error').": ' + error);
417
                    };
418
419
                    var geoOptions = {
420
                        enableHighAccuracy: true
421
                    };
422
                    navigator.geolocation.getCurrentPosition(geoPosition, geoError, geoOptions);
423
                }
424
            }
425
426
            function initializeGeo{$variable}(address, latLng)
427
            {
428
                var geocoder = new google.maps.Geocoder();
429
                var latlng = new google.maps.LatLng(-34.397, 150.644);
430
                var myOptions = {
431
                    zoom: 15,
432
                    center: latlng,
433
                    mapTypeControl: true,
434
                    mapTypeControlOptions: {
435
                        style: google.maps.MapTypeControlStyle.DROPDOWN_MENU
436
                    },
437
                    navigationControl: true,
438
                    mapTypeId: google.maps.MapTypeId.ROADMAP
439
                };
440
441
                map_{$variable} = new google.maps.Map(
442
                    document.getElementById('map_extra_{$variable}'),
443
                    myOptions
444
                );
445
446
                var parameter = address ? {'address': address} : latLng ? {'latLng': latLng} : false;
447
448
                if (geocoder && parameter) {
449
                    geocoder.geocode(parameter, function(results, status) {
450
                        if (status == google.maps.GeocoderStatus.OK) {
451
                            if (status != google.maps.GeocoderStatus.ZERO_RESULTS) {
452
                                map_{$variable}.setCenter(results[0].geometry.location);
453
454
                                // get city and country
455
                                var defaultAddress = results[0].formatted_address;
456
                                var city = '';
457
                                var country = '';
458
459
                                for (var i=0; i<results[0].address_components.length; i++) {
460
                                    if (results[0].address_components[i].types[0] == \"locality\") {
461
                                        //this is the object you are looking for City
462
                                        city = results[0].address_components[i];
463
                                    }
464
                                    /*if (results[j].address_components[i].types[0] == \"administrative_area_level_1\") {
465
                                        //this is the object you are looking for State
466
                                        region = results[0].address_components[i];
467
                                    }*/
468
                                    if (results[0].address_components[i].types[0] == \"country\") {
469
                                        //this is the object you are looking for
470
                                        country = results[0].address_components[i];
471
                                    }
472
                                }
473
474
                                if (city && city.long_name && country && country.long_name) {
475
                                    defaultAddress = city.long_name + ', ' + country.long_name;
476
                                }
477
                                $('#{$variable}').val(defaultAddress);
478
                                $('#{$variable}_coordinates').val(
479
                                    results[0].geometry.location.lat()+','+results[0].geometry.location.lng()
480
                                );
481
482
                                var infowindow = new google.maps.InfoWindow({
483
                                    content: '<b>' + $('#extra_{$variable}').val() + '</b>',
484
                                    size: new google.maps.Size(150, 50)
485
                                });
486
487
                                var marker = new google.maps.Marker({
488
                                    position: results[0].geometry.location,
489
                                    map: map_{$variable},
490
                                    title: $('#extra_{$variable}').val()
491
                                });
492
                                google.maps.event.addListener(marker, 'click', function() {
493
                                    infowindow.open(map_{$variable}, marker);
494
                                });
495
                            } else {
496
                                alert('".get_lang('NotFound')."');
497
                            }
498
                        } else {
499
                            alert('Geocode ".get_lang('Error').': '.get_lang('AddressField').' '.get_lang('NotFound')."');
500
                        }
501
                    });
502
                }
503
            }
504
            </script>";
505
506
        return $html;
507
    }
508
509
    /**
510
     * @param string $variable
511
     * @param string $text
512
     *
513
     * @return string
514
     */
515
    public static function getLocalizationInput($variable, $text)
516
    {
517
        $textHelp = $text;
518
        if (is_array($text)) {
519
            $textHelp = $text[0];
520
        }
521
        return '
522
                <div class="form-group">
523
                    <label for="geolocalization_extra_'.$variable.'"
524
                        class="col-sm-2 control-label"></label>
525
                    <div class="col-sm-8">
526
                        <button class="btn btn--plain"
527
                            id="geolocalization_extra_'.$variable.'"
528
                            name="geolocalization_extra_'.$variable.'"
529
                            type="submit">
530
                            <em class="fa fa-map-marker"></em> '.get_lang('SearchGeolocalization').'
531
                        </button>
532
                        <button class="btn btn--plain" id="myLocation_extra_'.$variable.'"
533
                            name="myLocation_extra_'.$variable.'"
534
                            type="submit">
535
                            <em class="fa fa-crosshairs"></em> '.get_lang('MyLocation').'
536
                        </button>
537
                    </div>
538
                </div>
539
                <div class="form-group">
540
                    <label for="map_extra_'.$variable.'" class="col-sm-2 control-label">
541
                        '.$textHelp.' - '.get_lang('Map').'
542
                    </label>
543
                    <div class="col-sm-8">
544
                        <div name="map_extra_'.$variable.'"
545
                            id="map_extra_'.$variable.'" style="width:100%; height:300px;">
546
                        </div>
547
                    </div>
548
                </div>
549
            ';
550
    }
551
552
    /**
553
     * @return int
554
     */
555
    public function get_count()
556
    {
557
        $em = Database::getManager();
558
        $query = $em->getRepository(EntityExtraField::class)->createQueryBuilder('e');
559
        $query->select('count(e.id)');
560
        $query->where('e.itemType = :type');
561
        $query->setParameter('type', $this->getItemType());
562
563
        return $query->getQuery()->getSingleScalarResult();
564
    }
565
566
    /**
567
     * @return int
568
     */
569
    public function getItemType()
570
    {
571
        return (int) $this->itemType;
572
    }
573
574
    /**
575
     * @param string $sidx
576
     * @param string $sord
577
     * @param int    $start
578
     * @param int    $limit
579
     *
580
     * @return array<int, EntityExtraField>
581
     */
582
    public function getAllGrid($sidx, $sord, $start, $limit)
583
    {
584
        switch ($sidx) {
585
            case 'field_order':
586
                $sidx = 'e.fieldOrder';
587
                break;
588
            case 'variable':
589
                $sidx = 'e.variable';
590
                break;
591
            case 'display_text':
592
                $sidx = 'e.displayText';
593
                break;
594
            case 'changeable':
595
                $sidx = 'e.changeable';
596
                break;
597
            case 'visible_to_self':
598
                $sidx = 'e.visibleToSelf';
599
                break;
600
            case 'visible_to_others':
601
                $sidx = 'e.visibleToOthers';
602
                break;
603
            case 'filter':
604
                $sidx = 'e.filter';
605
                break;
606
            case 'auto_remove':
607
                $sidx = 'e.autoRemove';
608
                break;
609
        }
610
        $em = Database::getManager();
611
        $query = $em->getRepository(EntityExtraField::class)->createQueryBuilder('e');
612
        $query
613
            ->where('e.itemType = :type')
614
            ->setParameter('type', $this->getItemType())
615
            ->orderBy($sidx, $sord)
616
            ->setFirstResult($start)
617
            ->setMaxResults($limit);
618
619
        return $query->getQuery()->getResult();
620
    }
621
622
    /**
623
     * Get all the field info for tags.
624
     *
625
     * @param string $variable
626
     *
627
     * @return array|bool
628
     */
629
    public function get_handler_field_info_by_tags($variable)
630
    {
631
        $variable = Database::escape_string($variable);
632
        $sql = "SELECT * FROM {$this->table}
633
                WHERE
634
                    variable = '$variable' AND
635
                    item_type = $this->itemType";
636
        $result = Database::query($sql);
637
        $extraFieldRepo = Container::getExtraFieldRepository();
638
        if (Database::num_rows($result)) {
639
            $row = Database::fetch_assoc($result);
640
            $extraFieldId = $row['id'];
641
            /** @var EntityExtraField $extraField */
642
            $extraField = $extraFieldRepo->find($extraFieldId);
643
            $row['display_text'] = $extraField->getDisplayText();
644
645
            // All the tags of the field
646
            $sql = "SELECT * FROM $this->table_field_tag
647
                    WHERE field_id='".$extraFieldId."'
648
                    ORDER BY id ASC";
649
            $result = Database::query($sql);
650
            while ($option = Database::fetch_assoc($result)) {
651
                $row['options'][$option['id']] = $option;
652
            }
653
654
            return $row;
655
        }
656
657
        return false;
658
    }
659
660
    /**
661
     * @param int $fieldId
662
     *
663
     * @return array|bool
664
     */
665
    public function getFieldInfoByFieldId($fieldId)
666
    {
667
        $fieldId = (int) $fieldId;
668
        $sql = "SELECT * FROM {$this->table}
669
                WHERE
670
                    id = '$fieldId' AND
671
                    item_type = $this->itemType";
672
        $result = Database::query($sql);
673
        if (Database::num_rows($result)) {
674
            $row = Database::fetch_assoc($result);
675
676
            // All the options of the field
677
            $sql = "SELECT * FROM $this->table_field_options
678
                    WHERE field_id='".$fieldId."'
679
                    ORDER BY option_order ASC";
680
            $result = Database::query($sql);
681
            while ($option = Database::fetch_array($result)) {
682
                $row['options'][$option['id']] = $option;
683
            }
684
685
            return $row;
686
        } else {
687
            return false;
688
        }
689
    }
690
691
    /**
692
     * Add elements to a form.
693
     *
694
     * @param FormValidator $form                            The form object to which to attach this element
695
     * @param int           $itemId                          The item (course, user, session, etc) this extra_field is
696
     *                                                       linked to
697
     * @param array         $exclude                         Variables of extra field to exclude
698
     * @param bool          $filter                          Whether to get only the fields with the "filter" flag set
699
     *                                                       to 1 (true) or not (false)
700
     * @param bool          $useTagAsSelect                  Whether to show tag fields as select drop-down or not
701
     * @param array         $showOnlyTheseFields             Limit the extra fields shown to just the list given here
702
     * @param array         $orderFields                     An array containing the names of the fields shown, in the
703
     *                                                       right order
704
     * @param array         $extraData
705
     * @param bool          $orderDependingDefaults
706
     * @param bool          $adminPermissions
707
     * @param array         $separateExtraMultipleSelect
708
     * @param array         $customLabelsExtraMultipleSelect
709
     * @param bool          $addEmptyOptionSelects
710
     * @param array         $introductionTextList
711
     * @param array         $requiredFields
712
     * @param bool          $hideGeoLocalizationDetails
713
     *
714
     * @throws Exception
715
     *
716
     * @return array|bool If relevant, returns a one-element array with JS code to be added to the page HTML headers.
717
     *                    Returns false if the form object was not given
718
     */
719
    public function addElements(
720
        $form,
721
        $itemId = 0,
722
        $exclude = [],
723
        $filter = false,
724
        $useTagAsSelect = false,
725
        $showOnlyTheseFields = [],
726
        $orderFields = [],
727
        $extraData = [],
728
        $orderDependingDefaults = false,
729
        $adminPermissions = false,
730
        $separateExtraMultipleSelect = [],
731
        $customLabelsExtraMultipleSelect = [],
732
        $addEmptyOptionSelects = false,
733
        $introductionTextList = [],
734
        $requiredFields = [],
735
        $hideGeoLocalizationDetails = false,
736
        $help = false
737
    ) {
738
        if (empty($form)) {
739
            return false;
740
        }
741
742
        $itemId = (int) $itemId;
743
        $form->addHidden('item_id', $itemId);
744
        $extraData = false;
745
        if (!empty($itemId)) {
746
            $extraData = $this->get_handler_extra_data($itemId);
747
            if (!empty($showOnlyTheseFields)) {
748
                $setData = [];
749
                foreach ($showOnlyTheseFields as $variable) {
750
                    $extraName = 'extra_'.$variable;
751
                    if (in_array($extraName, array_keys($extraData))) {
752
                        $setData[$extraName] = $extraData[$extraName];
753
                    }
754
                }
755
                $form->setDefaults($setData);
756
            } else {
757
                $form->setDefaults($extraData);
758
            }
759
        }
760
761
        $conditions = [];
762
        if ($filter) {
763
            $conditions = ['filter = ?' => 1];
764
        }
765
766
        $extraFields = $this->get_all($conditions, 'option_order');
767
        $extra = $this->set_extra_fields_in_form(
768
            $form,
769
            $extraData,
770
            $adminPermissions,
771
            $extraFields,
772
            $itemId,
773
            $exclude,
774
            $useTagAsSelect,
775
            $showOnlyTheseFields,
776
            $orderFields,
777
            $orderDependingDefaults,
778
            $separateExtraMultipleSelect,
779
            $customLabelsExtraMultipleSelect,
780
            $addEmptyOptionSelects,
781
            $introductionTextList,
782
            $hideGeoLocalizationDetails,
783
            $help
784
        );
785
786
        if (!empty($requiredFields)) {
787
            /** @var HTML_QuickForm_input $element */
788
            foreach ($form->getElements() as $element) {
789
                $name = str_replace('extra_', '', $element->getName());
790
                if (in_array($name, $requiredFields)) {
791
                    $form->setRequired($element);
792
                }
793
            }
794
        }
795
796
        return $extra;
797
    }
798
799
    /**
800
     * Return an array of all the extra fields available for this item.
801
     *
802
     * @param int $itemId (session_id, question_id, course id)
803
     *
804
     * @return array
805
     */
806
    public function get_handler_extra_data($itemId)
807
    {
808
        if (empty($itemId)) {
809
            return [];
810
        }
811
812
        $extra_data = [];
813
        $fields = $this->get_all();
814
        $field_values = new ExtraFieldValue($this->type);
815
816
        if (!empty($fields)) {
817
            foreach ($fields as $field) {
818
                $field_value = $fieldValueArray = $field_values->get_values_by_handler_and_field_id(
819
                    $itemId,
820
                    $field['id']
821
                );
822
823
                if (self::FIELD_TYPE_TAG == $field['value_type']) {
824
                    $tags = UserManager::get_user_tags_to_string(
825
                        $itemId,
826
                        $field['id'],
827
                        false
828
                    );
829
                    $extra_data['extra_'.$field['variable']] = $tags;
830
831
                    continue;
832
                }
833
834
                if ($field_value) {
835
                    $variable = $field['variable'];
836
                    $field_value = $field_value['field_value'];
837
                    switch ($field['value_type']) {
838
                        case self::FIELD_TYPE_FILE_IMAGE:
839
                        case self::FIELD_TYPE_FILE:
840
                            // Get asset id
841
                            $extra_data['extra_'.$field['variable']] = $fieldValueArray['asset_id'] ?? 0;
842
                            break;
843
                        case self::FIELD_TYPE_TAG:
844
                            $tags = UserManager::get_user_tags_to_string(
845
                                $itemId,
846
                                $field['id'],
847
                                false
848
                            );
849
850
                            $extra_data['extra_'.$field['variable']] = $tags;
851
                            break;
852
                        case self::FIELD_TYPE_DOUBLE_SELECT:
853
                        case self::FIELD_TYPE_SELECT_WITH_TEXT_FIELD:
854
                            $selected_options = explode('::', $field_value);
855
                            $firstOption = isset($selected_options[0]) ? $selected_options[0] : '';
856
                            $secondOption = isset($selected_options[1]) ? $selected_options[1] : '';
857
                            $extra_data['extra_'.$field['variable']]['extra_'.$field['variable']] = $firstOption;
858
                            $extra_data['extra_'.$field['variable']]['extra_'.$field['variable'].'_second'] = $secondOption;
859
860
                            break;
861
                        case self::FIELD_TYPE_SELECT_MULTIPLE:
862
                            $field_value = explode(';', $field_value);
863
                            $extra_data['extra_'.$field['variable']] = $field_value;
864
                            break;
865
                        case self::FIELD_TYPE_RADIO:
866
                            $extra_data['extra_'.$field['variable']]['extra_'.$field['variable']] = $field_value;
867
                            break;
868
                        case self::FIELD_TYPE_TRIPLE_SELECT:
869
                            [$level1, $level2, $level3] = explode(';', $field_value);
870
871
                            $extra_data["extra_$variable"]["extra_$variable"] = $level1;
872
                            $extra_data["extra_$variable"]["extra_{$variable}_second"] = $level2;
873
                            $extra_data["extra_$variable"]["extra_{$variable}_third"] = $level3;
874
                            break;
875
                        case self::FIELD_TYPE_DURATION:
876
                            $extra_data['extra_'.$field['variable']] = self::formatDuration((int) $field_value);
0 ignored issues
show
Bug Best Practice introduced by
The method ExtraField::formatDuration() 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

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

1411
                        $jquery_ready_content .= self::/** @scrutinizer ignore-call */ addDoubleSelectElement(
Loading history...
1412
                            $form,
1413
                            $field_details,
1414
                            $extraData,
1415
                            $freezeElement
1416
                        );
1417
                        break;
1418
                    case self::FIELD_TYPE_DIVIDER:
1419
                        $form->addHtml('
1420
                            <div class="form-group ">
1421
                                <div class="col-sm-12">
1422
                                    <div class="panel-separator">
1423
                                       <h4 id="'.$variable.'" class="form-separator">'
1424
                                            .$field_details['display_text'].'
1425
                                       </h4>
1426
                                    </div>
1427
                                </div>
1428
                            </div>
1429
                        ');
1430
                        break;
1431
                    case self::FIELD_TYPE_TAG:
1432
                        $field_id = $field_details['id'];
1433
                        $separateValue = 0;
1434
                        if (isset($separateExtraMultipleSelect[$variable])) {
1435
                            $separateValue = $separateExtraMultipleSelect[$variable];
1436
                        }
1437
1438
                        $selectedOptions = [];
1439
                        if ($separateValue > 0) {
1440
                            $em = Database::getManager();
1441
                            $fieldTags = $em
1442
                                ->getRepository(ExtraFieldRelTag::class)
1443
                                ->findBy(
1444
                                    [
1445
                                        'field' => $field_id,
1446
                                        'itemId' => $itemId,
1447
                                    ]
1448
                                );
1449
                            // ofaj.
1450
                            for ($i = 0; $i < $separateValue; $i++) {
1451
                                $tagsSelect = $form->addSelect(
1452
                                    'extra_'.$variable.'['.$i.']',
1453
                                    $customLabelsExtraMultipleSelect[$variable][$i], //$field_details['display_text'],
1454
                                    [],
1455
                                    ['id' => 'extra_'.$variable.'_'.$i]
1456
                                );
1457
1458
                                if ($addEmptyOptionSelects) {
1459
                                    $tagsSelect->addOption(
1460
                                        '',
1461
                                        ''
1462
                                    );
1463
                                }
1464
                                /** @var ExtraFieldRelTag $fieldTag */
1465
                                foreach ($fieldTags as $fieldTag) {
1466
                                    $tag = $fieldTag->getTag();
1467
1468
                                    if (empty($tag)) {
1469
                                        continue;
1470
                                    }
1471
1472
                                    $tagsSelect->addOption(
1473
                                        $tag->getTag(),
1474
                                        $tag->getTag()
1475
                                    );
1476
                                }
1477
                            }
1478
                        } else {
1479
                            $tagsSelect = $form->addSelect(
1480
                                "extra_{$variable}",
1481
                                $field_details['display_text'],
1482
                                [],
1483
                                ['style' => 'width: 100%;']
1484
                            );
1485
1486
                            if (false === $useTagAsSelect) {
1487
                                $tagsSelect->setAttribute('class', null);
1488
                            }
1489
1490
                            $tagsSelect->setAttribute(
1491
                                'id',
1492
                                "extra_{$variable}"
1493
                            );
1494
                            $tagsSelect->setMultiple(true);
1495
1496
                            $selectedOptions = [];
1497
                            if ('user' === $this->type) {
1498
                                // The magic should be here
1499
                                $user_tags = UserManager::get_user_tags(
1500
                                    $itemId,
1501
                                    $field_details['id']
1502
                                );
1503
1504
                                if (is_array($user_tags) && count($user_tags) > 0) {
1505
                                    foreach ($user_tags as $tag) {
1506
                                        if (empty($tag['tag'])) {
1507
                                            continue;
1508
                                        }
1509
                                        $tagsSelect->addOption(
1510
                                            $tag['tag'],
1511
                                            $tag['tag'],
1512
                                            [
1513
                                                'selected' => 'selected',
1514
                                                'class' => 'selected',
1515
                                            ]
1516
                                        );
1517
                                        $selectedOptions[] = $tag['tag'];
1518
                                    }
1519
                                }
1520
                                $url = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php';
1521
                            } else {
1522
                                $em = Database::getManager();
1523
                                $fieldTags = $em->getRepository(
1524
                                    ExtraFieldRelTag::class
1525
                                )
1526
                                ->findBy(
1527
                                    [
1528
                                        'field' => $field_id,
1529
                                        'itemId' => $itemId,
1530
                                    ]
1531
                                );
1532
1533
                                /** @var ExtraFieldRelTag $fieldTag */
1534
                                foreach ($fieldTags as $fieldTag) {
1535
                                    $tag = $fieldTag->getTag();
1536
                                    if (empty($tag)) {
1537
                                        continue;
1538
                                    }
1539
                                    $tagsSelect->addOption(
1540
                                        $tag->getTag(),
1541
                                        $tag->getTag()
1542
                                    );
1543
                                    $selectedOptions[] = $tag->getTag();
1544
                                }
1545
1546
                                if (!empty($extraData) && isset($extraData['extra_'.$variable])) {
1547
                                    $data = $extraData['extra_'.$variable];
1548
                                    if (!empty($data)) {
1549
                                        foreach ($data as $option) {
1550
                                            $tagsSelect->addOption(
1551
                                                $option,
1552
                                                $option
1553
                                            );
1554
                                        }
1555
                                    }
1556
                                }
1557
1558
                                if ($useTagAsSelect) {
1559
                                    $fieldTags = $em->getRepository(ExtraFieldRelTag::class)
1560
                                        ->findBy(
1561
                                            [
1562
                                                'field' => $field_id,
1563
                                            ]
1564
                                        );
1565
                                    $tagsAdded = [];
1566
                                    /** @var ExtraFieldRelTag $fieldTag */
1567
                                    foreach ($fieldTags as $fieldTag) {
1568
                                        $tag = $fieldTag->getTag();
1569
1570
                                        if (empty($tag)) {
1571
                                            continue;
1572
                                        }
1573
1574
                                        $tagText = $tag->getTag();
1575
                                        if (in_array($tagText, $tagsAdded)) {
1576
                                            continue;
1577
                                        }
1578
1579
                                        $tagsSelect->addOption(
1580
                                            $tag->getTag(),
1581
                                            $tag->getTag(),
1582
                                            []
1583
                                        );
1584
1585
                                        $tagsAdded[] = $tagText;
1586
                                    }
1587
                                }
1588
                                $url = api_get_path(WEB_AJAX_PATH).'extra_field.ajax.php';
1589
                            }
1590
1591
                            $form->setDefaults(
1592
                                [
1593
                                    'extra_'.$variable => $selectedOptions,
1594
                                ]
1595
                            );
1596
1597
                            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...
1598
                                $jquery_ready_content .= "
1599
                                $('#extra_$variable').select2({
1600
                                    ajax: {
1601
                                        url: '$url?a=search_tags&field_id=$field_id&type={$this->type}',
1602
                                        processResults: function (data) {
1603
                                            return {
1604
                                                results: data.items
1605
                                            }
1606
                                        }
1607
                                    },
1608
                                    cache: false,
1609
                                    tags: true,
1610
                                    tokenSeparators: [','],
1611
                                    placeholder: '".get_lang('Start to type, then click on this bar to validate tag')."'
1612
                                });
1613
                            ";
1614
                            }
1615
                        }
1616
1617
                        break;
1618
                    case self::FIELD_TYPE_TIMEZONE:
1619
                        $form->addSelect(
1620
                            'extra_'.$variable,
1621
                            $field_details['display_text'],
1622
                            api_get_timezones(),
1623
                        );
1624
                        if ($freezeElement) {
1625
                            $form->freeze('extra_'.$variable);
1626
                        }
1627
                        break;
1628
                    case self::FIELD_TYPE_SOCIAL_PROFILE:
1629
                        // get the social network's favicon
1630
                        $extra_data_variable = isset($extraData['extra_'.$variable]) ? $extraData['extra_'.$variable] : null;
1631
                        $field_default_value = isset($field_details['field_default_value']) ? $field_details['field_default_value'] : null;
1632
                        $icon_path = UserManager::get_favicon_from_url(
1633
                            $extra_data_variable,
1634
                            $field_default_value
1635
                        );
1636
                        // special hack for hi5
1637
                        $leftpad = '1.7';
1638
                        $top = '0.4';
1639
                        $domain = parse_url($icon_path, PHP_URL_HOST);
1640
                        if ('www.hi5.com' === $domain || 'hi5.com' === $domain) {
1641
                            $leftpad = '3';
1642
                            $top = '0';
1643
                        }
1644
                        // print the input field
1645
                        $form->addElement(
1646
                            'text',
1647
                            'extra_'.$variable,
1648
                            $field_details['display_text'],
1649
                            [
1650
                                //'size' => 60,
1651
                                'size' => implode(
1652
                                    '; ',
1653
                                    [
1654
                                        "background-image: url('$icon_path')",
1655
                                        'background-repeat: no-repeat',
1656
                                        "background-position: 0.4em {$top}em",
1657
                                        "padding-left: {$leftpad}em",
1658
                                    ]
1659
                                ),
1660
                            ]
1661
                        );
1662
                        $form->applyFilter('extra_'.$variable, 'stripslashes');
1663
                        $form->applyFilter('extra_'.$variable, 'trim');
1664
                        if ($freezeElement) {
1665
                            $form->freeze('extra_'.$variable);
1666
                        }
1667
                        break;
1668
                    case self::FIELD_TYPE_MOBILE_PHONE_NUMBER:
1669
                        $form->addElement(
1670
                            'text',
1671
                            'extra_'.$variable,
1672
                            $field_details['display_text'].' ('.get_lang('Include the country dial code').')',
1673
                            ['size' => 40, 'placeholder' => '(xx)xxxxxxxxx']
1674
                        );
1675
                        $form->applyFilter('extra_'.$variable, 'stripslashes');
1676
                        $form->applyFilter('extra_'.$variable, 'trim');
1677
                        $form->applyFilter('extra_'.$variable, 'mobile_phone_number_filter');
1678
                        $form->applyFilter('extra_'.$variable, 'html_filter');
1679
                        $form->addRule(
1680
                            'extra_'.$variable,
1681
                            get_lang('Mobile phone number is incomplete or contains invalid characters'),
1682
                            'mobile_phone_number'
1683
                        );
1684
                        if ($freezeElement) {
1685
                            $form->freeze('extra_'.$variable);
1686
                        }
1687
                        break;
1688
                    case self::FIELD_TYPE_INTEGER:
1689
                        $form->addElement(
1690
                            'number',
1691
                            'extra_'.$variable,
1692
                            $field_details['display_text'],
1693
                            ['class' => 'span1', 'step' => 1]
1694
                        );
1695
1696
                        $form->applyFilter('extra_'.$variable, 'stripslashes');
1697
                        $form->applyFilter('extra_'.$variable, 'trim');
1698
                        $form->applyFilter('extra_'.$variable, 'intval');
1699
1700
                        if ($freezeElement) {
1701
                            $form->freeze('extra_'.$variable);
1702
                        }
1703
                        break;
1704
                    case self::FIELD_TYPE_FLOAT:
1705
                        $form->addElement(
1706
                            'number',
1707
                            'extra_'.$variable,
1708
                            $field_details['display_text'],
1709
                            ['class' => 'span1', 'step' => '0.01']
1710
                        );
1711
1712
                        $form->applyFilter('extra_'.$variable, 'stripslashes');
1713
                        $form->applyFilter('extra_'.$variable, 'trim');
1714
                        $form->applyFilter('extra_'.$variable, 'floatval');
1715
1716
                        if ($freezeElement) {
1717
                            $form->freeze('extra_'.$variable);
1718
                        }
1719
                        break;
1720
                    case self::FIELD_TYPE_FILE_IMAGE:
1721
                        $fieldVariable = "extra_{$variable}";
1722
                        $fieldTexts = [
1723
                            $field_details['display_text'],
1724
                        ];
1725
1726
                        if (is_array($extraData) && array_key_exists($fieldVariable, $extraData)) {
1727
                            $assetId = $extraData[$fieldVariable];
1728
                            if (!empty($assetId)) {
1729
                                $asset = $assetRepo->find($assetId);
1730
                                if (null !== $asset) {
1731
                                    $fieldTexts[] = Display::img(
1732
                                        $assetRepo->getAssetUrl($asset),
1733
                                        $field_details['display_text'],
1734
                                        ['width' => '300'],
1735
                                        false
1736
                                    );
1737
                                }
1738
                            }
1739
                        }
1740
1741
                        if ('Image' === $fieldTexts[0]) {
1742
                            $fieldTexts[0] = get_lang($fieldTexts[0]);
1743
                        }
1744
1745
                        $form->addFile(
1746
                            $fieldVariable,
1747
                            $fieldTexts,
1748
                            ['accept' => 'image/*', 'id' => 'extra_image', 'crop_image' => 'true']
1749
                        );
1750
1751
                        $form->applyFilter('extra_'.$variable, 'stripslashes');
1752
                        $form->applyFilter('extra_'.$variable, 'trim');
1753
1754
                        $allowedPictureTypes = ['jpg', 'jpeg', 'png', 'gif'];
1755
                        $form->addRule(
1756
                            'extra_'.$variable,
1757
                            get_lang('Only PNG, JPG or GIF images allowed').' ('.implode(',', $allowedPictureTypes).')',
1758
                            'filetype',
1759
                            $allowedPictureTypes
1760
                        );
1761
1762
                        if ($freezeElement) {
1763
                            $form->freeze('extra_'.$variable);
1764
                        }
1765
                        break;
1766
                    case self::FIELD_TYPE_FILE:
1767
                        $fieldVariable = "extra_{$variable}";
1768
                        $fieldTexts = [
1769
                            $field_details['display_text'],
1770
                        ];
1771
1772
                        if (is_array($extraData) &&
1773
                            array_key_exists($fieldVariable, $extraData)
1774
                        ) {
1775
                            $assetId = $extraData[$fieldVariable] ?? 0;
1776
                            /** @var Asset $asset */
1777
                            $asset = $assetRepo->find($assetId);
1778
                            if (null !== $asset) {
1779
                                $fileName = $asset->getTitle();
1780
                                $linkUrl = $assetRepo->getAssetUrl($asset);
1781
                                $linkToDelete = '';
1782
                                if (api_is_platform_admin()) {
1783
                                    $url = api_get_path(WEB_AJAX_PATH).'extra_field.ajax.php?type='.$this->type;
1784
                                    $url .= '&a=delete_file&field_id='.$field_details['id'].'&item_id='.$itemId;
1785
                                    $deleteId = $variable.'_delete';
1786
                                    $form->addHtml(
1787
                                        "
1788
                                        <script>
1789
                                            $(function() {
1790
                                                $('#".$deleteId."').on('click', function() {
1791
                                                    $.ajax({
1792
                                                        type: 'GET',
1793
                                                        url: '".$url."',
1794
                                                        success: function(result) {
1795
                                                            if (result == 1) {
1796
                                                                $('#".$variable."').html('".get_lang('Deleted')."');
1797
                                                            }
1798
                                                        }
1799
                                                    });
1800
                                                });
1801
                                            });
1802
                                        </script>
1803
                                    "
1804
                                    );
1805
1806
                                    $linkToDelete = '&nbsp;'.Display::url(
1807
                                        Display::getMdiIcon(ActionIcon::DELETE, 'ch-tool-icon', null, ICON_SIZE_SMALL, get_lang('Delete')),
1808
                                        'javascript:void(0)',
1809
                                        ['id' => $deleteId]
1810
                                    );
1811
                                }
1812
                                $anchor = Display::url(
1813
                                    $fileName,
1814
                                    $linkUrl,
1815
                                    [
1816
                                        'title' => $field_details['display_text'],
1817
                                        'target' => '_blank',
1818
                                    ]
1819
                                );
1820
                                $fieldTexts[] = '<div id="'.$variable.'">'.$anchor.$linkToDelete.'</div>';
1821
                            }
1822
                        }
1823
1824
                        $form->addElement(
1825
                            'file',
1826
                            $fieldVariable,
1827
                            $fieldTexts,
1828
                            []
1829
                        );
1830
1831
                        $form->applyFilter('extra_'.$variable, 'stripslashes');
1832
                        $form->applyFilter('extra_'.$variable, 'trim');
1833
1834
                        if ($freezeElement) {
1835
                            $form->freeze('extra_'.$variable);
1836
                        }
1837
                        break;
1838
                    case self::FIELD_TYPE_VIDEO_URL:
1839
                        $form->addUrl(
1840
                            "extra_{$variable}",
1841
                            $field_details['display_text'],
1842
                            false,
1843
                            ['placeholder' => 'https://']
1844
                        );
1845
                        if ($freezeElement) {
1846
                            $form->freeze('extra_'.$variable);
1847
                        }
1848
                        break;
1849
                    case self::FIELD_TYPE_LETTERS_ONLY:
1850
                        $form->addTextLettersOnly(
1851
                            "extra_{$variable}",
1852
                            $field_details['display_text']
1853
                        );
1854
                        $form->applyFilter('extra_'.$variable, 'stripslashes');
1855
1856
                        if ($freezeElement) {
1857
                            $form->freeze('extra_'.$variable);
1858
                        }
1859
                        break;
1860
                    case self::FIELD_TYPE_ALPHANUMERIC:
1861
                        $form->addTextAlphanumeric(
1862
                            "extra_{$variable}",
1863
                            $field_details['display_text']
1864
                        );
1865
                        $form->applyFilter(
1866
                            'extra_'.$variable,
1867
                            'stripslashes'
1868
                        );
1869
                        if ($freezeElement) {
1870
                            $form->freeze('extra_'.$variable);
1871
                        }
1872
                        break;
1873
                    case self::FIELD_TYPE_LETTERS_SPACE:
1874
                        $form->addTextLettersAndSpaces(
1875
                            "extra_{$variable}",
1876
                            $field_details['display_text']
1877
                        );
1878
                        $form->applyFilter('extra_'.$variable, 'stripslashes');
1879
1880
                        if ($freezeElement) {
1881
                            $form->freeze('extra_'.$variable);
1882
                        }
1883
                        break;
1884
                    case self::FIELD_TYPE_ALPHANUMERIC_SPACE:
1885
                        $form->addTextAlphanumericAndSpaces(
1886
                            "extra_{$variable}",
1887
                            $field_details['display_text']
1888
                        );
1889
                        $form->applyFilter(
1890
                            'extra_'.$variable,
1891
                            'stripslashes'
1892
                        );
1893
                        if ($freezeElement) {
1894
                            $form->freeze('extra_'.$variable);
1895
                        }
1896
                        break;
1897
                    case self::FIELD_TYPE_GEOLOCALIZATION_COORDINATES:
1898
                    case self::FIELD_TYPE_GEOLOCALIZATION:
1899
                        $dataValue = isset($extraData['extra_'.$variable]) ? $extraData['extra_'.$variable] : '';
1900
                        $form->addGeoLocationMapField(
1901
                            'extra_'.$variable,
1902
                            $field_details['display_text'],
1903
                            $dataValue,
1904
                            $hideGeoLocalizationDetails
1905
                        );
1906
1907
                        if ($freezeElement) {
1908
                            $form->freeze('extra_'.$variable);
1909
                        }
1910
                        break;
1911
                    case self::FIELD_TYPE_SELECT_WITH_TEXT_FIELD:
1912
                        $jquery_ready_content .= $this->addSelectWithTextFieldElement(
1913
                            $form,
1914
                            $field_details,
1915
                            $freezeElement
1916
                        );
1917
                        break;
1918
                    case self::FIELD_TYPE_TRIPLE_SELECT:
1919
                        $jquery_ready_content .= $this->addTripleSelectElement(
1920
                            $form,
1921
                            $field_details,
1922
                            is_array($extraData) ? $extraData : [],
1923
                            $freezeElement
1924
                        );
1925
                        break;
1926
                    case self::FIELD_TYPE_DURATION:
1927
                        $form->addElement(
1928
                            'text',
1929
                            'extra_'.$variable,
1930
                            $field_details['display_text'],
1931
                            ['class' => 'span2', 'placeholder' => 'hh:mm:ss']
1932
                        );
1933
1934
                        $form->addRule(
1935
                            'extra_'.$variable,
1936
                            get_lang('Invalid format'),
1937
                            'callback',
1938
                            'validate_duration_format'
1939
                        );
1940
1941
                        $form->applyFilter('extra_'.$variable, function ($value) {
1942
                            if (preg_match('/^(\d+):([0-5]?\d):([0-5]?\d)$/', $value, $matches)) {
1943
                                return ($matches[1] * 3600) + ($matches[2] * 60) + $matches[3];
1944
                            }
1945
                            return 0;
1946
                        });
1947
1948
                        if (isset($extraData['extra_'.$variable]) && is_numeric($extraData['extra_'.$variable])) {
1949
                            $form->setDefaults([
1950
                                'extra_'.$variable => self::formatDuration((int) $extraData['extra_'.$variable])
0 ignored issues
show
Bug Best Practice introduced by
The method ExtraField::formatDuration() 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

1950
                                'extra_'.$variable => self::/** @scrutinizer ignore-call */ formatDuration((int) $extraData['extra_'.$variable])
Loading history...
1951
                            ]);
1952
                        }
1953
1954
                        if ($freezeElement) {
1955
                            $form->freeze('extra_'.$variable);
1956
                        }
1957
                        break;
1958
                }
1959
            }
1960
        }
1961
1962
        $return = [];
1963
        $return['jquery_ready_content'] = $jquery_ready_content;
1964
1965
        return $return;
1966
    }
1967
1968
    /**
1969
     * Validates if a string is in the hh:mm:ss duration format.
1970
     */
1971
    function validate_duration_format($value): bool
1972
    {
1973
        return (bool) preg_match('/^(\d+):([0-5]?\d):([0-5]?\d)$/', $value);
1974
    }
1975
1976
    /**
1977
     * @param array $options
1978
     *
1979
     * @return array
1980
     */
1981
    public static function extra_field_double_select_convert_array_to_ordered_array($options)
1982
    {
1983
        $optionsParsed = [];
1984
        if (!empty($options)) {
1985
            foreach ($options as $option) {
1986
                if (0 == $option['option_value']) {
1987
                    $optionsParsed[$option['id']][] = $option;
1988
                } else {
1989
                    $optionsParsed[$option['option_value']][] = $option;
1990
                }
1991
            }
1992
        }
1993
1994
        return $optionsParsed;
1995
    }
1996
1997
    /**
1998
     * @return array
1999
     */
2000
    public static function tripleSelectConvertArrayToOrderedArray(array $options)
2001
    {
2002
        $level1 = self::getOptionsFromTripleSelect($options, 0);
2003
        $level2 = [];
2004
        $level3 = [];
2005
2006
        foreach ($level1 as $item1) {
2007
            $level2 += self::getOptionsFromTripleSelect($options, $item1['id']);
2008
        }
2009
2010
        foreach ($level2 as $item2) {
2011
            $level3 += self::getOptionsFromTripleSelect($options, $item2['id']);
2012
        }
2013
2014
        return ['level1' => $level1, 'level2' => $level2, 'level3' => $level3];
2015
    }
2016
2017
    /**
2018
     * @param string $type
2019
     *
2020
     * @return array
2021
     */
2022
    public function get_all_extra_field_by_type($type)
2023
    {
2024
        // all the information of the field
2025
        $sql = "SELECT * FROM {$this->table}
2026
                WHERE
2027
                    value_type = '".Database::escape_string($type)."' AND
2028
                    item_type = $this->itemType
2029
                ";
2030
        $result = Database::query($sql);
2031
2032
        $return = [];
2033
        while ($row = Database::fetch_array($result)) {
2034
            $return[] = $row['id'];
2035
        }
2036
2037
        return $return;
2038
    }
2039
2040
    /**
2041
     * @param int $id
2042
     */
2043
    public function get_field_type_by_id($id)
2044
    {
2045
        $types = $this->get_field_types();
2046
        if (isset($types[$id])) {
2047
            return $types[$id];
2048
        }
2049
2050
        return null;
2051
    }
2052
2053
    /**
2054
     * @return array
2055
     */
2056
    public function get_field_types()
2057
    {
2058
        return $this->get_extra_fields_by_handler($this->type);
2059
    }
2060
2061
    /**
2062
     * @param string $handler
2063
     *
2064
     * @return array
2065
     */
2066
    public static function get_extra_fields_by_handler($handler)
2067
    {
2068
        $types = [];
2069
        $types[self::FIELD_TYPE_TEXT] = get_lang('Text');
2070
        $types[self::FIELD_TYPE_TEXTAREA] = get_lang('Text area');
2071
        $types[self::FIELD_TYPE_RADIO] = get_lang('Radio buttons');
2072
        $types[self::FIELD_TYPE_SELECT] = get_lang('Select drop-down');
2073
        $types[self::FIELD_TYPE_SELECT_MULTIPLE] = get_lang('Multiple selection drop-down');
2074
        $types[self::FIELD_TYPE_DATE] = get_lang('Date');
2075
        $types[self::FIELD_TYPE_DATETIME] = get_lang('Date and time');
2076
        $types[self::FIELD_TYPE_DOUBLE_SELECT] = get_lang('Double select');
2077
        $types[self::FIELD_TYPE_DIVIDER] = get_lang('Visual divider');
2078
        $types[self::FIELD_TYPE_TAG] = get_lang('User tag');
2079
        $types[self::FIELD_TYPE_TIMEZONE] = get_lang('Timezone');
2080
        $types[self::FIELD_TYPE_SOCIAL_PROFILE] = get_lang('Social network link');
2081
        $types[self::FIELD_TYPE_MOBILE_PHONE_NUMBER] = get_lang('Mobile phone number');
2082
        $types[self::FIELD_TYPE_CHECKBOX] = get_lang('Checkbox');
2083
        $types[self::FIELD_TYPE_INTEGER] = get_lang('Integer');
2084
        $types[self::FIELD_TYPE_FILE_IMAGE] = get_lang('Image');
2085
        $types[self::FIELD_TYPE_FLOAT] = get_lang('Float');
2086
        $types[self::FIELD_TYPE_FILE] = get_lang('File');
2087
        $types[self::FIELD_TYPE_VIDEO_URL] = get_lang('Video URL');
2088
        $types[self::FIELD_TYPE_LETTERS_ONLY] = get_lang('Text only letters');
2089
        $types[self::FIELD_TYPE_ALPHANUMERIC] = get_lang('Text only alphanumeric characters');
2090
        $types[self::FIELD_TYPE_LETTERS_SPACE] = get_lang('Text letters and spaces');
2091
        $types[self::FIELD_TYPE_ALPHANUMERIC_SPACE] = get_lang('Text alphanumeric characters and spaces');
2092
        $types[self::FIELD_TYPE_GEOLOCALIZATION] = get_lang('Geolocalization');
2093
        $types[self::FIELD_TYPE_GEOLOCALIZATION_COORDINATES] = get_lang('Geolocalization by coordinates');
2094
        $types[self::FIELD_TYPE_SELECT_WITH_TEXT_FIELD] = get_lang('Select with text field');
2095
        $types[self::FIELD_TYPE_TRIPLE_SELECT] = get_lang('Triple select');
2096
        $types[self::FIELD_TYPE_DURATION] = get_lang('Duration (hh:mm:ss)');
2097
2098
        switch ($handler) {
2099
            case 'course':
2100
            case 'session':
2101
            case 'user':
2102
            case 'skill':
2103
                break;
2104
        }
2105
2106
        return $types;
2107
    }
2108
2109
    /**
2110
     * @param array $params
2111
     * @param bool  $showQuery
2112
     *
2113
     * @return int|bool
2114
     */
2115
    public function save($params, $showQuery = false)
2116
    {
2117
        $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

2117
        /** @scrutinizer ignore-call */ 
2118
        $fieldInfo = self::get_handler_field_info_by_field_variable($params['variable']);
Loading history...
2118
        $params = $this->clean_parameters($params);
2119
        $params['item_type'] = $this->itemType;
2120
2121
        if ($fieldInfo) {
2122
            return $fieldInfo['id'];
2123
        } else {
2124
            $id = parent::save($params, $showQuery);
2125
            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...
2126
                $fieldOption = new ExtraFieldOption($this->type);
2127
                $params['field_id'] = $id;
2128
                $fieldOption->save($params);
2129
            }
2130
2131
            return $id;
2132
        }
2133
    }
2134
2135
    /**
2136
     * @param string $variable
2137
     *
2138
     * @return array|bool
2139
     */
2140
    public function get_handler_field_info_by_field_variable($variable)
2141
    {
2142
        $variable = Database::escape_string($variable);
2143
        $sql = "SELECT * FROM {$this->table}
2144
                WHERE
2145
                    variable = '$variable' AND
2146
                    item_type = $this->itemType";
2147
        $result = Database::query($sql);
2148
        if (Database::num_rows($result)) {
2149
            $extraFieldRepo = Container::getExtraFieldRepository();
2150
            $row = Database::fetch_assoc($result);
2151
            if ($row) {
2152
                $extraFieldId = $row['id'];
2153
                /** @var EntityExtraField $extraField */
2154
                $field = $extraFieldRepo->find($extraFieldId);
2155
                $row['display_text'] = $field->getDisplayText();
2156
2157
                // All the options of the field
2158
                $sql = "SELECT * FROM $this->table_field_options
2159
                        WHERE field_id='".$extraFieldId."'
2160
                        ORDER BY option_order ASC";
2161
                $result = Database::query($sql);
2162
                while ($option = Database::fetch_array($result)) {
2163
                    $row['options'][$option['id']] = $option;
2164
                }
2165
2166
                return $row;
2167
            }
2168
        }
2169
2170
        return false;
2171
    }
2172
2173
    /**
2174
     * @param array $params
2175
     *
2176
     * @return array
2177
     */
2178
    public function clean_parameters($params)
2179
    {
2180
        if (!isset($params['variable']) || empty($params['variable'])) {
2181
            $params['variable'] = $params['display_text'];
2182
        }
2183
2184
        $params['variable'] = trim(strtolower(str_replace(' ', '_', $params['variable'])));
2185
2186
        if (!isset($params['field_order'])) {
2187
            $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

2187
            /** @scrutinizer ignore-call */ 
2188
            $max_order = self::get_max_field_order();
Loading history...
2188
            $params['field_order'] = $max_order;
2189
        } else {
2190
            $params['field_order'] = (int) $params['field_order'];
2191
        }
2192
2193
        return $params;
2194
    }
2195
2196
    /**
2197
     * @return int
2198
     */
2199
    public function get_max_field_order()
2200
    {
2201
        $sql = "SELECT MAX(field_order)
2202
                FROM {$this->table}
2203
                WHERE
2204
                    item_type = '.$this->itemType.'";
2205
        $res = Database::query($sql);
2206
2207
        $order = 0;
2208
        if (Database::num_rows($res) > 0) {
2209
            $row = Database::fetch_row($res);
2210
            $order = $row[0] + 1;
2211
        }
2212
2213
        return $order;
2214
    }
2215
2216
    /**
2217
     * {@inheritdoc}
2218
     */
2219
    public function update($params, $showQuery = false)
2220
    {
2221
        $params = $this->clean_parameters($params);
2222
        if (isset($params['id'])) {
2223
            $fieldOption = new ExtraFieldOption($this->type);
2224
            $params['field_id'] = $params['id'];
2225
            if (empty($params['value_type'])) {
2226
                $params['value_type'] = $this->type;
2227
            }
2228
            $fieldOption->save($params, $showQuery);
2229
        }
2230
2231
        return parent::update($params, $showQuery);
2232
    }
2233
2234
    /**
2235
     * @param $id
2236
     *
2237
     * @return bool
2238
     */
2239
    public function delete($id)
2240
    {
2241
        $em = Database::getManager();
2242
        $items = $em->getRepository(\Chamilo\CoreBundle\Entity\ExtraFieldSavedSearch::class)->findBy(['field' => $id]);
2243
        if ($items) {
2244
            foreach ($items as $item) {
2245
                $em->remove($item);
2246
            }
2247
            $em->flush();
2248
        }
2249
        $field_option = new ExtraFieldOption($this->type);
2250
        $field_option->delete_all_options_by_field_id($id);
2251
2252
        $session_field_values = new ExtraFieldValue($this->type);
2253
        $session_field_values->delete_all_values_by_field_id($id);
2254
2255
        return parent::delete($id);
2256
    }
2257
2258
    /**
2259
     * @param $breadcrumb
2260
     * @param $action
2261
     */
2262
    public function setupBreadcrumb(&$breadcrumb, $action)
2263
    {
2264
        if ('add' === $action) {
2265
            $breadcrumb[] = ['url' => $this->pageUrl, 'name' => $this->pageName];
2266
            $breadcrumb[] = ['url' => '#', 'name' => get_lang('Add')];
2267
        } elseif ('edit' === $action) {
2268
            $breadcrumb[] = ['url' => $this->pageUrl, 'name' => $this->pageName];
2269
            $breadcrumb[] = ['url' => '#', 'name' => get_lang('Edit')];
2270
        } else {
2271
            $breadcrumb[] = ['url' => '#', 'name' => $this->pageName];
2272
        }
2273
    }
2274
2275
    /**
2276
     * Displays the title + grid.
2277
     */
2278
    public function display()
2279
    {
2280
        $actions = '<a href="../admin/index.php">';
2281
        $actions .= Display::getMdiIcon(ActionIcon::BACK, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Back to').' '.get_lang('Administration'));
2282
        $actions .= '</a>';
2283
        $actions .= '<a href="'.api_get_self().'?action=add&type='.$this->type.'">';
2284
        $actions .= Display::getMdiIcon(ActionIcon::ADD, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Add'));
2285
        $actions .= '</a>';
2286
2287
        echo Display::toolbarAction('toolbar', [$actions]);
2288
        echo Display::grid_html($this->type.'_fields');
2289
    }
2290
2291
    /**
2292
     * @return array
2293
     */
2294
    public function getJqgridColumnNames()
2295
    {
2296
        $columns = [
2297
            get_lang('Name'),
2298
            get_lang('Field label'),
2299
            get_lang('Type'),
2300
            get_lang('Can change'),
2301
            get_lang('Visible to self'),
2302
            get_lang('Visible to others'),
2303
            get_lang('Filter'),
2304
            get_lang('Order'),
2305
            get_lang('Detail'),
2306
        ];
2307
2308
        if ($this->type === 'user') {
2309
            array_splice($columns, -1, 0, get_lang('Auto remove'));
2310
        }
2311
2312
        return $columns;
2313
    }
2314
2315
    /**
2316
     * @return array
2317
     */
2318
    public function getJqgridColumnModel()
2319
    {
2320
        $columnModel = [
2321
            [
2322
                'name' => 'display_text',
2323
                'index' => 'display_text',
2324
                'align' => 'left',
2325
            ],
2326
            [
2327
                'name' => 'variable',
2328
                'index' => 'variable',
2329
                'align' => 'left',
2330
                'sortable' => 'true',
2331
            ],
2332
            [
2333
                'name' => 'value_type',
2334
                'index' => 'value_type',
2335
                'align' => 'left',
2336
                'sortable' => 'true',
2337
            ],
2338
            [
2339
                'name' => 'changeable',
2340
                'index' => 'changeable',
2341
                'align' => 'center',
2342
                'sortable' => 'true',
2343
            ],
2344
            [
2345
                'name' => 'visible_to_self',
2346
                'index' => 'visible_to_self',
2347
                'align' => 'center',
2348
                'sortable' => 'true',
2349
            ],
2350
            [
2351
                'name' => 'visible_to_others',
2352
                'index' => 'visible_to_others',
2353
                'align' => 'center',
2354
                'sortable' => 'true',
2355
            ],
2356
            [
2357
                'name' => 'filter',
2358
                'index' => 'filter',
2359
                'align' => 'center',
2360
                'sortable' => 'true',
2361
            ],
2362
            [
2363
                'name' => 'field_order',
2364
                'index' => 'field_order',
2365
                'align' => 'center',
2366
                'sortable' => 'true',
2367
            ],
2368
            [
2369
                'name' => 'actions',
2370
                'index' => 'actions',
2371
                'align' => 'center',
2372
                'formatter' => 'action_formatter',
2373
                'sortable' => 'false',
2374
            ],
2375
        ];
2376
2377
        if ($this->type === 'user') {
2378
            $autoRemoveColumnModel = [
2379
                'name' => 'auto_remove',
2380
                'index' => 'auto_remove',
2381
                'align' => 'center',
2382
                'sortable' => 'true',
2383
            ];
2384
2385
            array_splice($columnModel, -1, 0, [$autoRemoveColumnModel]);
2386
        }
2387
2388
        return $columnModel;
2389
    }
2390
2391
    /**
2392
     * @param string $url
2393
     * @param string $action
2394
     *
2395
     * @return FormValidator
2396
     */
2397
    public function return_form($url, $action)
2398
    {
2399
        $form = new FormValidator($this->type.'_field', 'post', $url);
2400
2401
        $form->addHidden('type', $this->type);
2402
        $id = isset($_GET['id']) ? (int) $_GET['id'] : null;
2403
        $form->addHidden('id', $id);
2404
2405
        // Setting the form elements
2406
        $header = get_lang('Add');
2407
        $defaults = [];
2408
2409
        if ('edit' === $action) {
2410
            $header = get_lang('Edit');
2411
            // Setting the defaults
2412
            $defaults = $this->get($id);
2413
        }
2414
2415
        $form->addHeader($header);
2416
2417
        if ('edit' === $action) {
2418
            $translateUrl = Container::getRouter()->generate(
2419
                'legacy_main',
2420
                ['name' => 'extrafield/translate.php', 'extra_field' => $id]
2421
            );
2422
            $translateButton = Display::toolbarButton(
2423
                get_lang('Translate this term'),
2424
                $translateUrl,
2425
                'language',
2426
                'plain'
2427
            );
2428
2429
            $form->addElement('text', 'display_text', [get_lang('Name'), $translateButton]);
2430
        } else {
2431
            $form->addText('display_text', get_lang('Name'));
2432
        }
2433
2434
        $form->addHtmlEditor('description', get_lang('Description'), false);
2435
2436
        // Field type
2437
        $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

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