ExtraField::addElements()   C
last analyzed

Complexity

Conditions 17
Paths 121

Size

Total Lines 104
Code Lines 55

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 55
c 1
b 0
f 0
dl 0
loc 104
rs 5.0416
cc 17
nc 121
nop 17

How to fix   Long Method    Complexity    Many Parameters   

Long Method

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

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

Commonly applied refactorings include:

Many Parameters

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

There are several approaches to avoid long parameter lists:

1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
use Chamilo\CoreBundle\Entity\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
     * Return an array of all the extra fields available for this item.
869
     *
870
     * @param int $itemId (session_id, question_id, course id)
871
     *
872
     * @return array
873
     */
874
    public function get_handler_extra_data($itemId)
875
    {
876
        if (empty($itemId)) {
877
            return [];
878
        }
879
880
        $extra_data = [];
881
        $fields = $this->get_all();
882
        $field_values = new ExtraFieldValue($this->type);
883
884
        if (!empty($fields)) {
885
            foreach ($fields as $field) {
886
                $field_value = $field_values->get_values_by_handler_and_field_id(
887
                    $itemId,
888
                    $field['id']
889
                );
890
891
                if (self::FIELD_TYPE_TAG == $field['field_type']) {
892
                    $tags = UserManager::get_user_tags_to_string(
893
                        $itemId,
894
                        $field['id'],
895
                        false
896
                    );
897
                    $extra_data['extra_'.$field['variable']] = $tags;
898
899
                    continue;
900
                }
901
902
                if ($field_value) {
903
                    $variable = $field['variable'];
904
                    $field_value = $field_value['value'];
905
                    switch ($field['field_type']) {
906
                        case self::FIELD_TYPE_TAG:
907
                            $tags = UserManager::get_user_tags_to_string(
908
                                $itemId,
909
                                $field['id'],
910
                                false
911
                            );
912
913
                            $extra_data['extra_'.$field['variable']] = $tags;
914
                            break;
915
                        case self::FIELD_TYPE_DOUBLE_SELECT:
916
                        case self::FIELD_TYPE_SELECT_WITH_TEXT_FIELD:
917
                            $selected_options = explode('::', $field_value);
918
                            $firstOption = isset($selected_options[0]) ? $selected_options[0] : '';
919
                            $secondOption = isset($selected_options[1]) ? $selected_options[1] : '';
920
                            $extra_data['extra_'.$field['variable']]['extra_'.$field['variable']] = $firstOption;
921
                            $extra_data['extra_'.$field['variable']]['extra_'.$field['variable'].'_second'] = $secondOption;
922
923
                            break;
924
                        case self::FIELD_TYPE_SELECT_MULTIPLE:
925
                            $field_value = explode(';', $field_value);
926
                            $extra_data['extra_'.$field['variable']] = $field_value;
927
                            break;
928
                        case self::FIELD_TYPE_RADIO:
929
                            $extra_data['extra_'.$field['variable']]['extra_'.$field['variable']] = $field_value;
930
                            break;
931
                        case self::FIELD_TYPE_TRIPLE_SELECT:
932
                            [$level1, $level2, $level3] = explode(';', $field_value);
933
934
                            $extra_data["extra_$variable"]["extra_$variable"] = $level1;
935
                            $extra_data["extra_$variable"]["extra_{$variable}_second"] = $level2;
936
                            $extra_data["extra_$variable"]["extra_{$variable}_third"] = $level3;
937
                            break;
938
                        default:
939
                            $extra_data['extra_'.$field['variable']] = $field_value;
940
                            break;
941
                    }
942
                } else {
943
                    // Set default values
944
                    if (isset($field['field_default_value']) &&
945
                        !empty($field['field_default_value'])
946
                    ) {
947
                        $extra_data['extra_'.$field['variable']] = $field['field_default_value'];
948
                    }
949
                }
950
            }
951
        }
952
953
        return $extra_data;
954
    }
955
956
    /**
957
     * Get an array of all the values from the extra_field and extra_field_options tables
958
     * based on the current object's type.
959
     *
960
     * @param array $conditions
961
     * @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...
962
     *
963
     * @return array
964
     */
965
    public function get_all($conditions = [], $order_field_options_by = null)
966
    {
967
        $conditions = Database::parse_conditions(['where' => $conditions]);
968
969
        if (empty($conditions)) {
970
            $conditions .= ' WHERE extra_field_type = '.$this->extraFieldType;
971
        } else {
972
            $conditions .= ' AND extra_field_type = '.$this->extraFieldType;
973
        }
974
975
        $sql = "SELECT * FROM $this->table
976
                $conditions
977
                ORDER BY field_order ASC
978
        ";
979
980
        $result = Database::query($sql);
981
        $extraFields = Database::store_result($result, 'ASSOC');
982
983
        $option = new ExtraFieldOption($this->type);
984
        if (!empty($extraFields)) {
985
            foreach ($extraFields as &$extraField) {
986
                $extraField['display_text'] = $this->translateDisplayName(
987
                    $extraField['variable'],
988
                    $extraField['display_text']
989
                );
990
                $extraField['options'] = $option->get_field_options_by_field(
991
                    $extraField['id'],
992
                    false,
993
                    $order_field_options_by
994
                );
995
            }
996
        }
997
998
        return $extraFields;
999
    }
1000
1001
    /**
1002
     * Add an element that matches the given extra field to the given $form object.
1003
     *
1004
     * @param FormValidator $form                The form these fields are to be attached to
1005
     * @param array         $extraData
1006
     * @param bool          $adminPermissions    Whether the display is considered without edition limits (true) or not
1007
     *                                           (false)
1008
     * @param array         $extra
1009
     * @param int           $itemId              The item (course, user, session, etc) this extra_field is attached to
1010
     * @param array         $exclude             Extra fields to be skipped, by textual ID
1011
     * @param bool          $useTagAsSelect      Whether to show tag fields as select drop-down or not
1012
     * @param array         $showOnlyTheseFields Limit the extra fields shown to just the list given here
1013
     * @param array         $orderFields         An array containing the names of the fields shown, in the right order
1014
     *
1015
     * @throws Exception
1016
     *
1017
     * @return array If relevant, returns a one-element array with JS code to be added to the page HTML headers
1018
     */
1019
    public function set_extra_fields_in_form(
1020
        $form,
1021
        $extraData,
1022
        $adminPermissions = false,
1023
        $extra = [],
1024
        $itemId = null,
1025
        $exclude = [],
1026
        $useTagAsSelect = false,
1027
        $showOnlyTheseFields = [],
1028
        $orderFields = [],
1029
        $orderDependingDefaults = false,
1030
        $separateExtraMultipleSelect = [],
1031
        $customLabelsExtraMultipleSelect = [],
1032
        $addEmptyOptionSelects = false,
1033
        $introductionTextList = [],
1034
        $hideGeoLocalizationDetails = false,
1035
        $help = false
1036
    ) {
1037
        $jquery_ready_content = null;
1038
        if (!empty($extra)) {
1039
            $newOrder = [];
1040
            if (!empty($orderFields)) {
1041
                foreach ($orderFields as $order) {
1042
                    foreach ($extra as $field_details) {
1043
                        if ($order == $field_details['variable']) {
1044
                            $newOrder[] = $field_details;
1045
                        }
1046
                    }
1047
                }
1048
                $extra = $newOrder;
1049
            }
1050
1051
            foreach ($extra as $field_details) {
1052
                if (!empty($showOnlyTheseFields)) {
1053
                    if (!in_array($field_details['variable'], $showOnlyTheseFields)) {
1054
                        continue;
1055
                    }
1056
                }
1057
1058
                // Getting default value id if is set
1059
                $defaultValueId = null;
1060
                if (isset($field_details['options']) && !empty($field_details['options'])) {
1061
                    $valueToFind = null;
1062
                    if (isset($field_details['field_default_value'])) {
1063
                        $valueToFind = $field_details['field_default_value'];
1064
                    }
1065
                    // If a value is found we override the default value
1066
                    if (isset($extraData['extra_'.$field_details['variable']])) {
1067
                        $valueToFind = $extraData['extra_'.$field_details['variable']];
1068
                    }
1069
1070
                    foreach ($field_details['options'] as $option) {
1071
                        if ($option['option_value'] == $valueToFind) {
1072
                            $defaultValueId = $option['id'];
1073
                        }
1074
                    }
1075
                }
1076
1077
                if (!$adminPermissions) {
1078
                    if (0 == $field_details['visible_to_self']) {
1079
                        continue;
1080
                    }
1081
1082
                    if (in_array($field_details['variable'], $exclude)) {
1083
                        continue;
1084
                    }
1085
                }
1086
1087
                if (!empty($introductionTextList) &&
1088
                    in_array($field_details['variable'], array_keys($introductionTextList))
1089
                ) {
1090
                    $form->addHtml($introductionTextList[$field_details['variable']]);
1091
                }
1092
1093
                $freezeElement = false;
1094
                if (!$adminPermissions) {
1095
                    $freezeElement = 0 == $field_details['visible_to_self'] || 0 == $field_details['changeable'];
1096
                }
1097
1098
                $translatedDisplayText = get_lang($field_details['display_text'], true);
1099
                $translatedDisplayHelpText = '';
1100
                if ($help) {
1101
                    $translatedDisplayHelpText .= get_lang($field_details['display_text'].'Help');
1102
                }
1103
                if (!empty($translatedDisplayText)) {
1104
                    if (!empty($translatedDisplayHelpText)) {
1105
                        // In this case, exceptionally, display_text is an array
1106
                        // which is then treated by display_form()
1107
                        $field_details['display_text'] = [$translatedDisplayText, $translatedDisplayHelpText];
1108
                    } else {
1109
                        // We have an helper text, use it
1110
                        $field_details['display_text'] = $translatedDisplayText;
1111
                    }
1112
                }
1113
1114
                switch ($field_details['field_type']) {
1115
                    case self::FIELD_TYPE_TEXT:
1116
                        $form->addElement(
1117
                            'text',
1118
                            'extra_'.$field_details['variable'],
1119
                            $field_details['display_text'],
1120
                            [
1121
                                'id' => 'extra_'.$field_details['variable'],
1122
                            ]
1123
                        );
1124
                        $form->applyFilter(
1125
                            'extra_'.$field_details['variable'],
1126
                            'stripslashes'
1127
                        );
1128
                        $form->applyFilter(
1129
                            'extra_'.$field_details['variable'],
1130
                            'trim'
1131
                        );
1132
                        $form->applyFilter(
1133
                            'extra_'.$field_details['variable'],
1134
                            'html_filter'
1135
                        );
1136
                        if (!empty($field_details['default_value'])) {
1137
                            $defaults['extra_'.$field_details['variable']] = $field_details['default_value'];
1138
                        }
1139
                        if (!isset($form->_defaultValues['extra_'.$field_details['variable']])) {
1140
                            $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...
1141
                        }
1142
                        if ($freezeElement) {
1143
                            $form->freeze('extra_'.$field_details['variable']);
1144
                        }
1145
                        break;
1146
                    case self::FIELD_TYPE_TEXTAREA:
1147
                        $form->addHtmlEditor(
1148
                            'extra_'.$field_details['variable'],
1149
                            $field_details['display_text'],
1150
                            false,
1151
                            false,
1152
                            [
1153
                                'ToolbarSet' => 'Profile',
1154
                                'Width' => '100%',
1155
                                'Height' => '130',
1156
                                'id' => 'extra_'.$field_details['variable'],
1157
                            ]
1158
                        );
1159
                        $form->applyFilter('extra_'.$field_details['variable'], 'stripslashes');
1160
                        $form->applyFilter('extra_'.$field_details['variable'], 'trim');
1161
                        if ($freezeElement) {
1162
                            $form->freeze('extra_'.$field_details['variable']);
1163
                        }
1164
                        break;
1165
                    case self::FIELD_TYPE_RADIO:
1166
                        $group = [];
1167
                        if (isset($field_details['options']) &&
1168
                            !empty($field_details['options'])
1169
                        ) {
1170
                            foreach ($field_details['options'] as $option_details) {
1171
                                $options[$option_details['option_value']] = $option_details['display_text'];
1172
                                $group[] = $form->createElement(
1173
                                    'radio',
1174
                                    'extra_'.$field_details['variable'],
1175
                                    $option_details['option_value'],
1176
                                    $option_details['display_text'].'<br />',
1177
                                    $option_details['option_value']
1178
                                );
1179
                            }
1180
                        }
1181
                        $form->addGroup(
1182
                            $group,
1183
                            'extra_'.$field_details['variable'],
1184
                            $field_details['display_text']
1185
                        );
1186
                        if ($freezeElement) {
1187
                            $form->freeze('extra_'.$field_details['variable']);
1188
                        }
1189
                        break;
1190
                    case self::FIELD_TYPE_CHECKBOX:
1191
                        $group = [];
1192
                        if (isset($field_details['options']) &&
1193
                            !empty($field_details['options'])
1194
                        ) {
1195
                            foreach ($field_details['options'] as $option_details) {
1196
                                $options[$option_details['option_value']] = $option_details['display_text'];
1197
                                $group[] = $form->createElement(
1198
                                    'checkbox',
1199
                                    'extra_'.$field_details['variable'],
1200
                                    $option_details['option_value'],
1201
                                    $option_details['display_text'].'<br />',
1202
                                    $option_details['option_value']
1203
                                );
1204
                            }
1205
                        } else {
1206
                            $fieldVariable = "extra_{$field_details['variable']}";
1207
                            $checkboxAttributes = [];
1208
                            if (is_array($extraData) &&
1209
                                array_key_exists($fieldVariable, $extraData)
1210
                            ) {
1211
                                if (!empty($extraData[$fieldVariable])) {
1212
                                    $checkboxAttributes['checked'] = 1;
1213
                                }
1214
                            }
1215
1216
                            if (empty($checkboxAttributes) &&
1217
                                isset($field_details['default_value']) && empty($extraData)) {
1218
                                if (1 == $field_details['default_value']) {
1219
                                    $checkboxAttributes['checked'] = 1;
1220
                                }
1221
                            }
1222
1223
                            // We assume that is a switch on/off with 1 and 0 as values
1224
                            $group[] = $form->createElement(
1225
                                'checkbox',
1226
                                'extra_'.$field_details['variable'],
1227
                                null,
1228
                                get_lang('Yes'),
1229
                                $checkboxAttributes
1230
                            );
1231
                        }
1232
1233
                        $form->addGroup(
1234
                            $group,
1235
                            'extra_'.$field_details['variable'],
1236
                            $field_details['display_text']
1237
                        );
1238
                        if ($freezeElement) {
1239
                            $form->freeze('extra_'.$field_details['variable']);
1240
                        }
1241
                        break;
1242
                    case self::FIELD_TYPE_SELECT:
1243
                        $this->addSelectElement($form, $field_details, $defaultValueId, $freezeElement);
1244
                        break;
1245
                    case self::FIELD_TYPE_SELECT_MULTIPLE:
1246
                        $options = [];
1247
                        if (empty($defaultValueId)) {
1248
                            $options[''] = get_lang('SelectAnOption');
1249
                        }
1250
1251
                        if (isset($field_details['options']) && !empty($field_details['options'])) {
1252
                            foreach ($field_details['options'] as $optionDetails) {
1253
                                $options[$optionDetails['option_value']] = $optionDetails['display_text'];
1254
                            }
1255
                        }
1256
1257
                        $form->addElement(
1258
                            'select',
1259
                            'extra_'.$field_details['variable'],
1260
                            $field_details['display_text'],
1261
                            $options,
1262
                            [
1263
                                'multiple' => 'multiple',
1264
                                'id' => 'extra_'.$field_details['variable'],
1265
                            ]
1266
                        );
1267
                        if ($freezeElement) {
1268
                            $form->freeze('extra_'.$field_details['variable']);
1269
                        }
1270
                        break;
1271
                    case self::FIELD_TYPE_DATE:
1272
                        $form->addDatePicker('extra_'.$field_details['variable'], $field_details['display_text']);
1273
                        if ($freezeElement) {
1274
                            $form->freeze('extra_'.$field_details['variable']);
1275
                        }
1276
                        break;
1277
                    case self::FIELD_TYPE_DATETIME:
1278
                        $form->addDateTimePicker(
1279
                            'extra_'.$field_details['variable'],
1280
                            $field_details['display_text']
1281
                        );
1282
1283
                        $defaults = [];
1284
                        if (EntityExtraField::LP_ITEM_FIELD_TYPE !== (int) $field_details['extra_field_type']) {
1285
                            $defaults['extra_'.$field_details['variable']] = api_get_local_time();
1286
                        }
1287
                        if (!isset($form->_defaultValues['extra_'.$field_details['variable']])) {
1288
                            $form->setDefaults($defaults);
1289
                        }
1290
                        if ($freezeElement) {
1291
                            $form->freeze('extra_'.$field_details['variable']);
1292
                        }
1293
                        break;
1294
                    case self::FIELD_TYPE_DOUBLE_SELECT:
1295
                        $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

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

1991
        /** @scrutinizer ignore-call */ 
1992
        $fieldInfo = self::get_handler_field_info_by_field_variable($params['variable']);
Loading history...
1992
        $params = $this->clean_parameters($params);
1993
        $params['extra_field_type'] = $this->extraFieldType;
1994
1995
        if ($fieldInfo) {
1996
            return $fieldInfo['id'];
1997
        } else {
1998
            $id = parent::save($params, $show_query);
1999
            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...
2000
                $fieldOption = new ExtraFieldOption($this->type);
2001
                $params['field_id'] = $id;
2002
                $fieldOption->save($params);
2003
            }
2004
2005
            return $id;
2006
        }
2007
    }
2008
2009
    /**
2010
     * Gets the set of values of an extra_field searching for the variable name.
2011
     *
2012
     * Example:
2013
     * <code>
2014
     * <?php
2015
     * $extraField = new ExtraField('lp_item');
2016
     * $extraFieldArray =  $extraField->get_handler_field_info_by_field_variable('authorlpitem');
2017
     * echo "<pre>".var_export($extraFieldArray,true)."</pre>";
2018
     * ?>
2019
     * </code>
2020
     *
2021
     * @param string $variable
2022
     *
2023
     * @return array|bool
2024
     */
2025
    public function get_handler_field_info_by_field_variable($variable)
2026
    {
2027
        $variable = Database::escape_string($variable);
2028
        $sql = "SELECT * FROM {$this->table}
2029
                WHERE
2030
                    variable = '$variable' AND
2031
                    extra_field_type = $this->extraFieldType";
2032
        $result = Database::query($sql);
2033
        if (Database::num_rows($result)) {
2034
            $row = Database::fetch_array($result, 'ASSOC');
2035
            if ($row) {
2036
                $row['display_text'] = self::translateDisplayName($row['variable'], $row['display_text']);
2037
2038
                // All the options of the field
2039
                $sql = "SELECT * FROM $this->table_field_options
2040
                    WHERE field_id='".intval($row['id'])."'
2041
                    ORDER BY option_order ASC";
2042
                $result = Database::query($sql);
2043
                while ($option = Database::fetch_array($result)) {
2044
                    $row['options'][$option['id']] = $option;
2045
                }
2046
2047
                return $row;
2048
            }
2049
        }
2050
2051
        return false;
2052
    }
2053
2054
    public function getHandlerEntityByFieldVariable(string $variable)
2055
    {
2056
        return Database::getManager()
2057
            ->getRepository('ChamiloCoreBundle:ExtraField')
2058
            ->findOneBy(['variable' => $variable, 'extraFieldType' => $this->extraFieldType]);
2059
    }
2060
2061
    /**
2062
     * @param array $params
2063
     *
2064
     * @return array
2065
     */
2066
    public function clean_parameters($params)
2067
    {
2068
        if (!isset($params['variable']) || empty($params['variable'])) {
2069
            $params['variable'] = $params['display_text'];
2070
        }
2071
2072
        $params['variable'] = trim(strtolower(str_replace(' ', '_', $params['variable'])));
2073
2074
        if (!isset($params['field_order'])) {
2075
            $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

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

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