Passed
Push — master ( 3f9eef...ccbe5e )
by Julito
07:14
created

ExtraField::tripleSelectConvertArrayToString()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 19
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

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

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

1898
        /** @scrutinizer ignore-call */ 
1899
        $fieldInfo = self::get_handler_field_info_by_field_variable($params['variable']);
Loading history...
1899
        $params = $this->clean_parameters($params);
1900
        $params['extra_field_type'] = $this->extraFieldType;
1901
1902
        if ($fieldInfo) {
1903
            return $fieldInfo['id'];
1904
        } else {
1905
            $id = parent::save($params, $showQuery);
1906
            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...
1907
                $fieldOption = new ExtraFieldOption($this->type);
1908
                $params['field_id'] = $id;
1909
                $fieldOption->save($params);
1910
            }
1911
1912
            return $id;
1913
        }
1914
    }
1915
1916
    /**
1917
     * @param string $variable
1918
     *
1919
     * @return array|bool
1920
     */
1921
    public function get_handler_field_info_by_field_variable($variable)
1922
    {
1923
        $variable = Database::escape_string($variable);
1924
        $sql = "SELECT * FROM {$this->table}
1925
                WHERE
1926
                    variable = '$variable' AND
1927
                    extra_field_type = $this->extraFieldType";
1928
        $result = Database::query($sql);
1929
        if (Database::num_rows($result)) {
1930
            $row = Database::fetch_array($result, 'ASSOC');
1931
            if ($row) {
1932
                $row['display_text'] = $this->translateDisplayName(
1933
                    $row['variable'],
1934
                    $row['display_text']
1935
                );
1936
1937
                // All the options of the field
1938
                $sql = "SELECT * FROM $this->table_field_options
1939
                    WHERE field_id='".intval($row['id'])."'
1940
                    ORDER BY option_order ASC";
1941
                $result = Database::query($sql);
1942
                while ($option = Database::fetch_array($result)) {
1943
                    $row['options'][$option['id']] = $option;
1944
                }
1945
1946
                return $row;
1947
            }
1948
        }
1949
1950
        return false;
1951
    }
1952
1953
    /**
1954
     * @param array $params
1955
     *
1956
     * @return array
1957
     */
1958
    public function clean_parameters($params)
1959
    {
1960
        if (!isset($params['variable']) || empty($params['variable'])) {
1961
            $params['variable'] = $params['display_text'];
1962
        }
1963
1964
        $params['variable'] = trim(strtolower(str_replace(' ', '_', $params['variable'])));
1965
1966
        if (!isset($params['field_order'])) {
1967
            $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

1967
            /** @scrutinizer ignore-call */ 
1968
            $max_order = self::get_max_field_order();
Loading history...
1968
            $params['field_order'] = $max_order;
1969
        } else {
1970
            $params['field_order'] = (int) $params['field_order'];
1971
        }
1972
1973
        return $params;
1974
    }
1975
1976
    /**
1977
     * @return int
1978
     */
1979
    public function get_max_field_order()
1980
    {
1981
        $sql = "SELECT MAX(field_order)
1982
                FROM {$this->table}
1983
                WHERE
1984
                    extra_field_type = '.$this->extraFieldType.'";
1985
        $res = Database::query($sql);
1986
1987
        $order = 0;
1988
        if (Database::num_rows($res) > 0) {
1989
            $row = Database::fetch_row($res);
1990
            $order = $row[0] + 1;
1991
        }
1992
1993
        return $order;
1994
    }
1995
1996
    /**
1997
     * {@inheritdoc}
1998
     */
1999
    public function update($params, $showQuery = false)
2000
    {
2001
        $params = $this->clean_parameters($params);
2002
        if (isset($params['id'])) {
2003
            $fieldOption = new ExtraFieldOption($this->type);
2004
            $params['field_id'] = $params['id'];
2005
            if (empty($params['field_type'])) {
2006
                $params['field_type'] = $this->type;
2007
            }
2008
            $fieldOption->save($params, $showQuery);
2009
        }
2010
2011
        return parent::update($params, $showQuery);
2012
    }
2013
2014
    /**
2015
     * @param $id
2016
     *
2017
     * @return bool
2018
     */
2019
    public function delete($id)
2020
    {
2021
        $em = Database::getManager();
2022
        $items = $em->getRepository(\Chamilo\CoreBundle\Entity\ExtraFieldSavedSearch::class)->findBy(['field' => $id]);
2023
        if ($items) {
2024
            foreach ($items as $item) {
2025
                $em->remove($item);
2026
            }
2027
            $em->flush();
2028
        }
2029
        $field_option = new ExtraFieldOption($this->type);
2030
        $field_option->delete_all_options_by_field_id($id);
2031
2032
        $session_field_values = new ExtraFieldValue($this->type);
2033
        $session_field_values->delete_all_values_by_field_id($id);
2034
2035
        return parent::delete($id);
2036
    }
2037
2038
    /**
2039
     * @param $breadcrumb
2040
     * @param $action
2041
     */
2042
    public function setupBreadcrumb(&$breadcrumb, $action)
2043
    {
2044
        if ('add' === $action) {
2045
            $breadcrumb[] = ['url' => $this->pageUrl, 'name' => $this->pageName];
2046
            $breadcrumb[] = ['url' => '#', 'name' => get_lang('Add')];
2047
        } elseif ('edit' === $action) {
2048
            $breadcrumb[] = ['url' => $this->pageUrl, 'name' => $this->pageName];
2049
            $breadcrumb[] = ['url' => '#', 'name' => get_lang('Edit')];
2050
        } else {
2051
            $breadcrumb[] = ['url' => '#', 'name' => $this->pageName];
2052
        }
2053
    }
2054
2055
    /**
2056
     * Displays the title + grid.
2057
     */
2058
    public function display()
2059
    {
2060
        // action links
2061
        echo '<div class="actions">';
2062
        echo '<a href="../admin/index.php">';
2063
        echo Display::return_icon(
2064
            'back.png',
2065
            get_lang('Back to').' '.get_lang('Administration'),
2066
            '',
2067
            ICON_SIZE_MEDIUM
2068
        );
2069
        echo '</a>';
2070
        echo '<a href="'.api_get_self().'?action=add&type='.$this->type.'">';
2071
        echo Display::return_icon(
2072
            'add_user_fields.png',
2073
            get_lang('Add'),
2074
            '',
2075
            ICON_SIZE_MEDIUM
2076
        );
2077
        echo '</a>';
2078
        echo '</div>';
2079
        echo Display::grid_html($this->type.'_fields');
2080
    }
2081
2082
    /**
2083
     * @return array
2084
     */
2085
    public function getJqgridColumnNames()
2086
    {
2087
        return [
2088
            get_lang('Name'),
2089
            get_lang('Field label'),
2090
            get_lang('Type'),
2091
            get_lang('Can change'),
2092
            get_lang('Visible to self'),
2093
            get_lang('Visible to others'),
2094
            get_lang('Filter'),
2095
            get_lang('Order'),
2096
            get_lang('Detail'),
2097
        ];
2098
    }
2099
2100
    /**
2101
     * @return array
2102
     */
2103
    public function getJqgridColumnModel()
2104
    {
2105
        return [
2106
            [
2107
                'name' => 'display_text',
2108
                'index' => 'display_text',
2109
                'width' => '140',
2110
                'align' => 'left',
2111
            ],
2112
            [
2113
                'name' => 'variable',
2114
                'index' => 'variable',
2115
                'width' => '90',
2116
                'align' => 'left',
2117
                'sortable' => 'true',
2118
            ],
2119
            [
2120
                'name' => 'field_type',
2121
                'index' => 'field_type',
2122
                'width' => '70',
2123
                'align' => 'left',
2124
                'sortable' => 'true',
2125
            ],
2126
            [
2127
                'name' => 'changeable',
2128
                'index' => 'changeable',
2129
                'width' => '35',
2130
                'align' => 'left',
2131
                'sortable' => 'true',
2132
            ],
2133
            [
2134
                'name' => 'visible_to_self',
2135
                'index' => 'visible_to_self',
2136
                'width' => '45',
2137
                'align' => 'left',
2138
                'sortable' => 'true',
2139
            ],
2140
            [
2141
                'name' => 'visible_to_others',
2142
                'index' => 'visible_to_others',
2143
                'width' => '35',
2144
                'align' => 'left',
2145
                'sortable' => 'true',
2146
            ],
2147
            [
2148
                'name' => 'filter',
2149
                'index' => 'filter',
2150
                'width' => '30',
2151
                'align' => 'left',
2152
                'sortable' => 'true',
2153
            ],
2154
            [
2155
                'name' => 'field_order',
2156
                'index' => 'field_order',
2157
                'width' => '25',
2158
                'align' => 'left',
2159
                'sortable' => 'true',
2160
            ],
2161
            [
2162
                'name' => 'actions',
2163
                'index' => 'actions',
2164
                'width' => '40',
2165
                'align' => 'left',
2166
                'formatter' => 'action_formatter',
2167
                'sortable' => 'false',
2168
            ],
2169
        ];
2170
    }
2171
2172
    /**
2173
     * @param string $url
2174
     * @param string $action
2175
     *
2176
     * @return FormValidator
2177
     */
2178
    public function return_form($url, $action)
2179
    {
2180
        $form = new FormValidator($this->type.'_field', 'post', $url);
2181
2182
        $form->addElement('hidden', 'type', $this->type);
2183
        $id = isset($_GET['id']) ? (int) $_GET['id'] : null;
2184
        $form->addElement('hidden', 'id', $id);
2185
2186
        // Setting the form elements
2187
        $header = get_lang('Add');
2188
        $defaults = [];
2189
2190
        if ('edit' === $action) {
2191
            $header = get_lang('Edit');
2192
            // Setting the defaults
2193
            $defaults = $this->get($id, false);
2194
        }
2195
2196
        $form->addElement('header', $header);
2197
2198
        if ('edit' === $action) {
2199
            $translateUrl = api_get_path(WEB_CODE_PATH).'extrafield/translate.php?'
2200
                .http_build_query(['extra_field' => $id]);
2201
            $translateButton = Display::toolbarButton(get_lang('Translate this term'), $translateUrl, 'language', 'link');
2202
2203
            $form->addText(
2204
                'display_text',
2205
                [get_lang('Name'), $translateButton]
2206
            );
2207
        } else {
2208
            $form->addElement('text', 'display_text', get_lang('Name'));
2209
        }
2210
2211
        $form->addHtmlEditor('description', get_lang('Description'), false);
2212
2213
        // Field type
2214
        $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

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