Passed
Push — master ( ab8e22...a86bce )
by Yannick
13:34 queued 02:44
created

ExtraField::set_extra_fields_in_form()   F

Complexity

Conditions 144
Paths 3

Size

Total Lines 895
Code Lines 561

Duplication

Lines 0
Ratio 0 %

Importance

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

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

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

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

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

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

2092
        /** @scrutinizer ignore-call */ 
2093
        $fieldInfo = self::get_handler_field_info_by_field_variable($params['variable']);
Loading history...
2093
        $params = $this->clean_parameters($params);
2094
        $params['item_type'] = $this->itemType;
2095
2096
        if ($fieldInfo) {
2097
            return $fieldInfo['id'];
2098
        } else {
2099
            $id = parent::save($params, $showQuery);
2100
            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...
2101
                $fieldOption = new ExtraFieldOption($this->type);
2102
                $params['field_id'] = $id;
2103
                $fieldOption->save($params);
2104
            }
2105
2106
            return $id;
2107
        }
2108
    }
2109
2110
    /**
2111
     * @param string $variable
2112
     *
2113
     * @return array|bool
2114
     */
2115
    public function get_handler_field_info_by_field_variable($variable)
2116
    {
2117
        $variable = Database::escape_string($variable);
2118
        $sql = "SELECT * FROM {$this->table}
2119
                WHERE
2120
                    variable = '$variable' AND
2121
                    item_type = $this->itemType";
2122
        $result = Database::query($sql);
2123
        if (Database::num_rows($result)) {
2124
            $extraFieldRepo = Container::getExtraFieldRepository();
2125
            $row = Database::fetch_assoc($result);
2126
            if ($row) {
2127
                $extraFieldId = $row['id'];
2128
                /** @var EntityExtraField $extraField */
2129
                $field = $extraFieldRepo->find($extraFieldId);
2130
                $row['display_text'] = $field->getDisplayText();
2131
2132
                // All the options of the field
2133
                $sql = "SELECT * FROM $this->table_field_options
2134
                        WHERE field_id='".$extraFieldId."'
2135
                        ORDER BY option_order ASC";
2136
                $result = Database::query($sql);
2137
                while ($option = Database::fetch_array($result)) {
2138
                    $row['options'][$option['id']] = $option;
2139
                }
2140
2141
                return $row;
2142
            }
2143
        }
2144
2145
        return false;
2146
    }
2147
2148
    /**
2149
     * @param array $params
2150
     *
2151
     * @return array
2152
     */
2153
    public function clean_parameters($params)
2154
    {
2155
        if (!isset($params['variable']) || empty($params['variable'])) {
2156
            $params['variable'] = $params['display_text'];
2157
        }
2158
2159
        $params['variable'] = trim(strtolower(str_replace(' ', '_', $params['variable'])));
2160
2161
        if (!isset($params['field_order'])) {
2162
            $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

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

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