Passed
Pull Request — master (#4373)
by Yannick
16:21
created

ExtraField::set_extra_fields_in_form()   F

Complexity

Conditions 139
Paths 3

Size

Total Lines 859
Code Lines 537

Duplication

Lines 0
Ratio 0 %

Importance

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

How to fix   Long Method    Complexity    Many Parameters   

Long Method

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

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

Commonly applied refactorings include:

Many Parameters

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

There are several approaches to avoid long parameter lists:

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

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

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

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

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