ExtraField::parseConditions()   F
last analyzed

Complexity

Conditions 29
Paths 144

Size

Total Lines 162
Code Lines 113

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 29
eloc 113
nc 144
nop 2
dl 0
loc 162
rs 3.0399
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

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

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

2034
        /** @scrutinizer ignore-call */ 
2035
        $fieldInfo = self::get_handler_field_info_by_field_variable($params['variable']);
Loading history...
2035
        $params = $this->clean_parameters($params);
2036
        $params['extra_field_type'] = $this->extraFieldType;
2037
2038
        if ($fieldInfo) {
2039
            return $fieldInfo['id'];
2040
        } else {
2041
            $id = parent::save($params, $show_query);
2042
            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...
2043
                $fieldOption = new ExtraFieldOption($this->type);
2044
                $params['field_id'] = $id;
2045
                $fieldOption->save($params);
2046
            }
2047
2048
            return $id;
2049
        }
2050
    }
2051
2052
    /**
2053
     * Gets the set of values of an extra_field searching for the variable name.
2054
     *
2055
     * Example:
2056
     * <code>
2057
     * <?php
2058
     * $extraField = new ExtraField('lp_item');
2059
     * $extraFieldArray =  $extraField->get_handler_field_info_by_field_variable('authorlpitem');
2060
     * echo "<pre>".var_export($extraFieldArray,true)."</pre>";
2061
     * ?>
2062
     * </code>
2063
     *
2064
     * @param string $variable
2065
     *
2066
     * @return array|bool
2067
     */
2068
    public function get_handler_field_info_by_field_variable($variable)
2069
    {
2070
        $variable = Database::escape_string($variable);
2071
        $sql = "SELECT * FROM {$this->table}
2072
                WHERE
2073
                    variable = '$variable' AND
2074
                    extra_field_type = $this->extraFieldType";
2075
        $result = Database::query($sql);
2076
        if (Database::num_rows($result)) {
2077
            $row = Database::fetch_array($result, 'ASSOC');
2078
            if ($row) {
2079
                $row['display_text'] = self::translateDisplayName($row['variable'], $row['display_text']);
2080
2081
                // All the options of the field
2082
                $sql = "SELECT * FROM $this->table_field_options
2083
                    WHERE field_id='".intval($row['id'])."'
2084
                    ORDER BY option_order ASC";
2085
                $result = Database::query($sql);
2086
                while ($option = Database::fetch_array($result)) {
2087
                    $row['options'][$option['id']] = $option;
2088
                }
2089
2090
                return $row;
2091
            }
2092
        }
2093
2094
        return false;
2095
    }
2096
2097
    public function getHandlerEntityByFieldVariable(string $variable)
2098
    {
2099
        return Database::getManager()
2100
            ->getRepository('ChamiloCoreBundle:ExtraField')
2101
            ->findOneBy(['variable' => $variable, 'extraFieldType' => $this->extraFieldType]);
2102
    }
2103
2104
    /**
2105
     * @param array $params
2106
     *
2107
     * @return array
2108
     */
2109
    public function clean_parameters($params)
2110
    {
2111
        if (!isset($params['variable']) || empty($params['variable'])) {
2112
            $params['variable'] = $params['display_text'];
2113
        }
2114
2115
        $params['variable'] = trim(strtolower(str_replace(' ', '_', $params['variable'])));
2116
2117
        if (!isset($params['field_order'])) {
2118
            $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

2118
            /** @scrutinizer ignore-call */ 
2119
            $max_order = self::get_max_field_order();
Loading history...
2119
            $params['field_order'] = $max_order;
2120
        } else {
2121
            $params['field_order'] = (int) $params['field_order'];
2122
        }
2123
2124
        return $params;
2125
    }
2126
2127
    /**
2128
     * @return int
2129
     */
2130
    public function get_max_field_order()
2131
    {
2132
        $sql = "SELECT MAX(field_order)
2133
                FROM {$this->table}
2134
                WHERE
2135
                    extra_field_type = '.$this->extraFieldType.'";
2136
        $res = Database::query($sql);
2137
2138
        $order = 0;
2139
        if (Database::num_rows($res) > 0) {
2140
            $row = Database::fetch_row($res);
2141
            $order = $row[0] + 1;
2142
        }
2143
2144
        return $order;
2145
    }
2146
2147
    /**
2148
     * {@inheritdoc}
2149
     */
2150
    public function update($params, $showQuery = false)
2151
    {
2152
        $params = $this->clean_parameters($params);
2153
        if (isset($params['id'])) {
2154
            $fieldOption = new ExtraFieldOption($this->type);
2155
            $params['field_id'] = $params['id'];
2156
            if (empty($params['field_type'])) {
2157
                $params['field_type'] = $this->type;
2158
            }
2159
            $fieldOption->save($params, $showQuery);
2160
        }
2161
2162
        return parent::update($params, $showQuery);
2163
    }
2164
2165
    /**
2166
     * @param $id
2167
     *
2168
     * @return bool
2169
     */
2170
    public function delete($id)
2171
    {
2172
        $em = Database::getManager();
2173
        $items = $em->getRepository('ChamiloCoreBundle:ExtraFieldSavedSearch')->findBy(['field' => $id]);
2174
        if ($items) {
2175
            foreach ($items as $item) {
2176
                $em->remove($item);
2177
            }
2178
            $em->flush();
2179
        }
2180
        $field_option = new ExtraFieldOption($this->type);
2181
        $field_option->delete_all_options_by_field_id($id);
2182
2183
        $session_field_values = new ExtraFieldValue($this->type);
2184
        $session_field_values->delete_all_values_by_field_id($id);
2185
2186
        return parent::delete($id);
2187
    }
2188
2189
    /**
2190
     * @param $breadcrumb
2191
     * @param $action
2192
     */
2193
    public function setupBreadcrumb(&$breadcrumb, $action)
2194
    {
2195
        if ('add' === $action) {
2196
            $breadcrumb[] = ['url' => $this->pageUrl, 'name' => $this->pageName];
2197
            $breadcrumb[] = ['url' => '#', 'name' => get_lang('Add')];
2198
        } elseif ('edit' === $action) {
2199
            $breadcrumb[] = ['url' => $this->pageUrl, 'name' => $this->pageName];
2200
            $breadcrumb[] = ['url' => '#', 'name' => get_lang('Edit')];
2201
        } else {
2202
            $breadcrumb[] = ['url' => '#', 'name' => $this->pageName];
2203
        }
2204
    }
2205
2206
    /**
2207
     * Displays the title + grid.
2208
     */
2209
    public function display()
2210
    {
2211
        // action links
2212
        echo '<div class="actions">';
2213
        echo '<a href="../admin/index.php">';
2214
        echo Display::return_icon(
2215
            'back.png',
2216
            get_lang('BackTo').' '.get_lang('PlatformAdmin'),
2217
            '',
2218
            ICON_SIZE_MEDIUM
2219
        );
2220
        echo '</a>';
2221
        echo '<a href="'.api_get_self().'?action=add&type='.$this->type.'">';
2222
        echo Display::return_icon(
2223
            'add_user_fields.png',
2224
            get_lang('Add'),
2225
            '',
2226
            ICON_SIZE_MEDIUM
2227
        );
2228
        echo '</a>';
2229
        echo '</div>';
2230
        echo Display::grid_html($this->type.'_fields');
2231
    }
2232
2233
    /**
2234
     * @return array
2235
     */
2236
    public function getJqgridColumnNames()
2237
    {
2238
        return [
2239
            get_lang('Name'),
2240
            get_lang('FieldLabel'),
2241
            get_lang('Type'),
2242
            get_lang('FieldChangeability'),
2243
            get_lang('VisibleToSelf'),
2244
            get_lang('VisibleToOthers'),
2245
            get_lang('Filter'),
2246
            get_lang('FieldOrder'),
2247
            get_lang('Actions'),
2248
        ];
2249
    }
2250
2251
    /**
2252
     * @return array
2253
     */
2254
    public function getJqgridColumnModel()
2255
    {
2256
        return [
2257
            [
2258
                'name' => 'display_text',
2259
                'index' => 'display_text',
2260
                'width' => '140',
2261
                'align' => 'left',
2262
            ],
2263
            [
2264
                'name' => 'variable',
2265
                'index' => 'variable',
2266
                'width' => '90',
2267
                'align' => 'left',
2268
                'sortable' => 'true',
2269
            ],
2270
            [
2271
                'name' => 'field_type',
2272
                'index' => 'field_type',
2273
                'width' => '70',
2274
                'align' => 'left',
2275
                'sortable' => 'true',
2276
            ],
2277
            [
2278
                'name' => 'changeable',
2279
                'index' => 'changeable',
2280
                'width' => '35',
2281
                'align' => 'left',
2282
                'sortable' => 'true',
2283
            ],
2284
            [
2285
                'name' => 'visible_to_self',
2286
                'index' => 'visible_to_self',
2287
                'width' => '45',
2288
                'align' => 'left',
2289
                'sortable' => 'true',
2290
            ],
2291
            [
2292
                'name' => 'visible_to_others',
2293
                'index' => 'visible_to_others',
2294
                'width' => '35',
2295
                'align' => 'left',
2296
                'sortable' => 'true',
2297
            ],
2298
            [
2299
                'name' => 'filter',
2300
                'index' => 'filter',
2301
                'width' => '30',
2302
                'align' => 'left',
2303
                'sortable' => 'true',
2304
            ],
2305
            [
2306
                'name' => 'field_order',
2307
                'index' => 'field_order',
2308
                'width' => '25',
2309
                'align' => 'left',
2310
                'sortable' => 'true',
2311
            ],
2312
            [
2313
                'name' => 'actions',
2314
                'index' => 'actions',
2315
                'width' => '40',
2316
                'align' => 'left',
2317
                'formatter' => 'action_formatter',
2318
                'sortable' => 'false',
2319
            ],
2320
        ];
2321
    }
2322
2323
    /**
2324
     * @param string $url
2325
     * @param string $action
2326
     *
2327
     * @return FormValidator
2328
     */
2329
    public function return_form($url, $action)
2330
    {
2331
        $form = new FormValidator($this->type.'_field', 'post', $url);
2332
2333
        $form->addHidden('type', $this->type);
2334
        $id = isset($_GET['id']) ? (int) $_GET['id'] : null;
2335
        $form->addHidden('id', $id);
2336
2337
        // Setting the form elements
2338
        $header = get_lang('Add');
2339
        $defaults = [];
2340
2341
        if ('edit' === $action) {
2342
            $header = get_lang('Modify');
2343
            // Setting the defaults
2344
            $defaults = $this->get($id, false);
2345
        }
2346
2347
        $form->addHeader($header);
2348
2349
        if ('edit' === $action) {
2350
            $translateUrl = api_get_path(WEB_CODE_PATH).'extrafield/translate.php?'
2351
                .http_build_query(['extra_field' => $id]);
2352
            $translateButton = Display::toolbarButton(get_lang('TranslateThisTerm'), $translateUrl, 'language', 'link');
2353
2354
            $form->addText(
2355
                'display_text',
2356
                [get_lang('Title'), $translateButton]
2357
            );
2358
        } else {
2359
            $form->addText('display_text', get_lang('Title'));
2360
        }
2361
2362
        // Field type
2363
        $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

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