Passed
Push — master ( c8b87f...30f75c )
by Julito
11:29
created

ExtraField::getExtraFieldTypeFromString()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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

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

1947
        /** @scrutinizer ignore-call */ 
1948
        $fieldInfo = self::get_handler_field_info_by_field_variable($params['variable']);
Loading history...
1948
        $params = $this->clean_parameters($params);
1949
        $params['extra_field_type'] = $this->extraFieldType;
1950
1951
        if ($fieldInfo) {
1952
            return $fieldInfo['id'];
1953
        } else {
1954
            $id = parent::save($params, $showQuery);
1955
            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...
1956
                $fieldOption = new ExtraFieldOption($this->type);
1957
                $params['field_id'] = $id;
1958
                $fieldOption->save($params);
1959
            }
1960
1961
            return $id;
1962
        }
1963
    }
1964
1965
    /**
1966
     * @param string $variable
1967
     *
1968
     * @return array|bool
1969
     */
1970
    public function get_handler_field_info_by_field_variable($variable)
1971
    {
1972
        $variable = Database::escape_string($variable);
1973
        $sql = "SELECT * FROM {$this->table}
1974
                WHERE
1975
                    variable = '$variable' AND
1976
                    extra_field_type = $this->extraFieldType";
1977
        $result = Database::query($sql);
1978
        if (Database::num_rows($result)) {
1979
            $extraFieldRepo = Container::getExtraFieldRepository();
1980
            $row = Database::fetch_array($result, 'ASSOC');
1981
            if ($row) {
1982
                $extraFieldId = $row['id'];
1983
                /** @var \Chamilo\CoreBundle\Entity\ExtraField $extraField */
1984
                $field = $extraFieldRepo->find($extraFieldId);
1985
                $row['display_text'] = $field->getDisplayText();
1986
1987
                // All the options of the field
1988
                $sql = "SELECT * FROM $this->table_field_options
1989
                        WHERE field_id='".$extraFieldId."'
1990
                        ORDER BY option_order ASC";
1991
                $result = Database::query($sql);
1992
                while ($option = Database::fetch_array($result)) {
1993
                    $row['options'][$option['id']] = $option;
1994
                }
1995
1996
                return $row;
1997
            }
1998
        }
1999
2000
        return false;
2001
    }
2002
2003
    /**
2004
     * @param array $params
2005
     *
2006
     * @return array
2007
     */
2008
    public function clean_parameters($params)
2009
    {
2010
        if (!isset($params['variable']) || empty($params['variable'])) {
2011
            $params['variable'] = $params['display_text'];
2012
        }
2013
2014
        $params['variable'] = trim(strtolower(str_replace(' ', '_', $params['variable'])));
2015
2016
        if (!isset($params['field_order'])) {
2017
            $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

2017
            /** @scrutinizer ignore-call */ 
2018
            $max_order = self::get_max_field_order();
Loading history...
2018
            $params['field_order'] = $max_order;
2019
        } else {
2020
            $params['field_order'] = (int) $params['field_order'];
2021
        }
2022
2023
        return $params;
2024
    }
2025
2026
    /**
2027
     * @return int
2028
     */
2029
    public function get_max_field_order()
2030
    {
2031
        $sql = "SELECT MAX(field_order)
2032
                FROM {$this->table}
2033
                WHERE
2034
                    extra_field_type = '.$this->extraFieldType.'";
2035
        $res = Database::query($sql);
2036
2037
        $order = 0;
2038
        if (Database::num_rows($res) > 0) {
2039
            $row = Database::fetch_row($res);
2040
            $order = $row[0] + 1;
2041
        }
2042
2043
        return $order;
2044
    }
2045
2046
    /**
2047
     * {@inheritdoc}
2048
     */
2049
    public function update($params, $showQuery = false)
2050
    {
2051
        $params = $this->clean_parameters($params);
2052
        if (isset($params['id'])) {
2053
            $fieldOption = new ExtraFieldOption($this->type);
2054
            $params['field_id'] = $params['id'];
2055
            if (empty($params['field_type'])) {
2056
                $params['field_type'] = $this->type;
2057
            }
2058
            $fieldOption->save($params, $showQuery);
2059
        }
2060
2061
        return parent::update($params, $showQuery);
2062
    }
2063
2064
    /**
2065
     * @param $id
2066
     *
2067
     * @return bool
2068
     */
2069
    public function delete($id)
2070
    {
2071
        $em = Database::getManager();
2072
        $items = $em->getRepository(\Chamilo\CoreBundle\Entity\ExtraFieldSavedSearch::class)->findBy(['field' => $id]);
2073
        if ($items) {
2074
            foreach ($items as $item) {
2075
                $em->remove($item);
2076
            }
2077
            $em->flush();
2078
        }
2079
        $field_option = new ExtraFieldOption($this->type);
2080
        $field_option->delete_all_options_by_field_id($id);
2081
2082
        $session_field_values = new ExtraFieldValue($this->type);
2083
        $session_field_values->delete_all_values_by_field_id($id);
2084
2085
        return parent::delete($id);
2086
    }
2087
2088
    /**
2089
     * @param $breadcrumb
2090
     * @param $action
2091
     */
2092
    public function setupBreadcrumb(&$breadcrumb, $action)
2093
    {
2094
        if ('add' === $action) {
2095
            $breadcrumb[] = ['url' => $this->pageUrl, 'name' => $this->pageName];
2096
            $breadcrumb[] = ['url' => '#', 'name' => get_lang('Add')];
2097
        } elseif ('edit' === $action) {
2098
            $breadcrumb[] = ['url' => $this->pageUrl, 'name' => $this->pageName];
2099
            $breadcrumb[] = ['url' => '#', 'name' => get_lang('Edit')];
2100
        } else {
2101
            $breadcrumb[] = ['url' => '#', 'name' => $this->pageName];
2102
        }
2103
    }
2104
2105
    /**
2106
     * Displays the title + grid.
2107
     */
2108
    public function display()
2109
    {
2110
        $actions = '<a href="../admin/index.php">';
2111
        $actions .= Display::return_icon(
2112
            'back.png',
2113
            get_lang('Back to').' '.get_lang('Administration'),
2114
            '',
2115
            ICON_SIZE_MEDIUM
2116
        );
2117
        $actions .= '</a>';
2118
        $actions .= '<a href="'.api_get_self().'?action=add&type='.$this->type.'">';
2119
        $actions .= Display::return_icon(
2120
            'add_user_fields.png',
2121
            get_lang('Add'),
2122
            '',
2123
            ICON_SIZE_MEDIUM
2124
        );
2125
        $actions .= '</a>';
2126
2127
        echo Display::toolbarAction('toolbar', [$actions]);
2128
        echo Display::grid_html($this->type.'_fields');
2129
    }
2130
2131
    /**
2132
     * @return array
2133
     */
2134
    public function getJqgridColumnNames()
2135
    {
2136
        return [
2137
            get_lang('Name'),
2138
            get_lang('Field label'),
2139
            get_lang('Type'),
2140
            get_lang('Can change'),
2141
            get_lang('Visible to self'),
2142
            get_lang('Visible to others'),
2143
            get_lang('Filter'),
2144
            get_lang('Order'),
2145
            get_lang('Detail'),
2146
        ];
2147
    }
2148
2149
    /**
2150
     * @return array
2151
     */
2152
    public function getJqgridColumnModel()
2153
    {
2154
        return [
2155
            [
2156
                'name' => 'display_text',
2157
                'index' => 'display_text',
2158
                'width' => '140',
2159
                'align' => 'left',
2160
            ],
2161
            [
2162
                'name' => 'variable',
2163
                'index' => 'variable',
2164
                'width' => '90',
2165
                'align' => 'left',
2166
                'sortable' => 'true',
2167
            ],
2168
            [
2169
                'name' => 'field_type',
2170
                'index' => 'field_type',
2171
                'width' => '70',
2172
                'align' => 'left',
2173
                'sortable' => 'true',
2174
            ],
2175
            [
2176
                'name' => 'changeable',
2177
                'index' => 'changeable',
2178
                'width' => '35',
2179
                'align' => 'left',
2180
                'sortable' => 'true',
2181
            ],
2182
            [
2183
                'name' => 'visible_to_self',
2184
                'index' => 'visible_to_self',
2185
                'width' => '45',
2186
                'align' => 'left',
2187
                'sortable' => 'true',
2188
            ],
2189
            [
2190
                'name' => 'visible_to_others',
2191
                'index' => 'visible_to_others',
2192
                'width' => '35',
2193
                'align' => 'left',
2194
                'sortable' => 'true',
2195
            ],
2196
            [
2197
                'name' => 'filter',
2198
                'index' => 'filter',
2199
                'width' => '30',
2200
                'align' => 'left',
2201
                'sortable' => 'true',
2202
            ],
2203
            [
2204
                'name' => 'field_order',
2205
                'index' => 'field_order',
2206
                'width' => '25',
2207
                'align' => 'left',
2208
                'sortable' => 'true',
2209
            ],
2210
            [
2211
                'name' => 'actions',
2212
                'index' => 'actions',
2213
                'width' => '40',
2214
                'align' => 'left',
2215
                'formatter' => 'action_formatter',
2216
                'sortable' => 'false',
2217
            ],
2218
        ];
2219
    }
2220
2221
    /**
2222
     * @param string $url
2223
     * @param string $action
2224
     *
2225
     * @return FormValidator
2226
     */
2227
    public function return_form($url, $action)
2228
    {
2229
        $form = new FormValidator($this->type.'_field', 'post', $url);
2230
2231
        $form->addElement('hidden', 'type', $this->type);
2232
        $id = isset($_GET['id']) ? (int) $_GET['id'] : null;
2233
        $form->addElement('hidden', 'id', $id);
2234
2235
        // Setting the form elements
2236
        $header = get_lang('Add');
2237
        $defaults = [];
2238
2239
        if ('edit' === $action) {
2240
            $header = get_lang('Edit');
2241
            // Setting the defaults
2242
            $defaults = $this->get($id, false);
2243
        }
2244
2245
        $form->addElement('header', $header);
2246
2247
        if ('edit' === $action) {
2248
            $translateUrl = api_get_path(WEB_CODE_PATH).'extrafield/translate.php?'.http_build_query(['id' => $id]);
2249
            $translateButton = Display::toolbarButton(
2250
                get_lang('Translate this term'),
2251
                $translateUrl,
2252
                'language',
2253
                'link'
2254
            );
2255
2256
            $form->addText(
2257
                'display_text',
2258
                [get_lang('Name'), $translateButton]
2259
            );
2260
        } else {
2261
            $form->addElement('text', 'display_text', get_lang('Name'));
2262
        }
2263
2264
        $form->addHtmlEditor('description', get_lang('Description'), false);
2265
2266
        // Field type
2267
        $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

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