Passed
Push — master ( d50113...c8b87f )
by Julito
20:21
created

ExtraField::translateDisplayName()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 15
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

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

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

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

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

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