Passed
Push — master ( 0c6bcd...ffcdc3 )
by Angel Fernando Quiroz
10:51
created

ExtraField::set_extra_fields_in_form()   F

Complexity

Conditions 139
Paths 3

Size

Total Lines 859
Code Lines 537

Duplication

Lines 0
Ratio 0 %

Importance

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

How to fix   Long Method    Complexity    Many Parameters   

Long Method

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

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

Commonly applied refactorings include:

Many Parameters

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

There are several approaches to avoid long parameter lists:

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

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

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

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

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