ExtraField::set_extra_fields_in_form()   F
last analyzed

Complexity

Conditions 135
Paths 3

Size

Total Lines 830
Code Lines 534

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
eloc 534
c 1
b 0
f 1
dl 0
loc 830
rs 3.3333
cc 135
nc 3
nop 16

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

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1338
                        $jquery_ready_content .= self::/** @scrutinizer ignore-call */ addDoubleSelectElement(
Loading history...
1339
                            $form,
1340
                            $field_details,
1341
                            $extraData,
1342
                            $freezeElement
1343
                        );
1344
                        break;
1345
                    case self::FIELD_TYPE_DIVIDER:
1346
                        $form->addHtml(
1347
                            '
1348
                            <div class="form-group ">
1349
                                <div class="col-sm-12">
1350
                                    <div class="panel-separator">
1351
                                       <h4 id="'.$field_details['variable'].'" class="form-separator">'
1352
                            .$field_details['display_text'].'
1353
                                       </h4>
1354
                                    </div>
1355
                                </div>
1356
                            </div>
1357
                        '
1358
                        );
1359
                        break;
1360
                    case self::FIELD_TYPE_TAG:
1361
                        $variable = $field_details['variable'];
1362
                        $field_id = $field_details['id'];
1363
                        $separateValue = 0;
1364
                        if (isset($separateExtraMultipleSelect[$field_details['variable']])) {
1365
                            $separateValue = $separateExtraMultipleSelect[$field_details['variable']];
1366
                        }
1367
1368
                        $selectedOptions = [];
1369
                        if ($separateValue > 0) {
1370
                            $em = Database::getManager();
1371
                            $fieldTags = $em
1372
                                ->getRepository('ChamiloCoreBundle:ExtraFieldRelTag')
1373
                                ->findBy(
1374
                                    [
1375
                                        'fieldId' => $field_id,
1376
                                        'itemId' => $itemId,
1377
                                    ]
1378
                                );
1379
                            // ofaj
1380
1381
                            for ($i = 0; $i < $separateValue; $i++) {
1382
                                $tagsSelect = $form->addElement(
1383
                                    'select',
1384
                                    'extra_'.$field_details['variable'].'['.$i.']',
1385
                                    $customLabelsExtraMultipleSelect[$field_details['variable']][$i],
1386
                                    null,
1387
                                    ['id' => 'extra_'.$field_details['variable'].'_'.$i]
1388
                                );
1389
1390
                                if ($addEmptyOptionSelects) {
1391
                                    $tagsSelect->addOption(
1392
                                        '',
1393
                                        ''
1394
                                    );
1395
                                }
1396
1397
                                foreach ($fieldTags as $fieldTag) {
1398
                                    $tag = $em->find('ChamiloCoreBundle:Tag', $fieldTag->getTagId());
1399
1400
                                    if (empty($tag)) {
1401
                                        continue;
1402
                                    }
1403
1404
                                    $tagsSelect->addOption(
1405
                                        $tag->getTag(),
1406
                                        $tag->getTag()
1407
                                    );
1408
                                }
1409
                            }
1410
                        } else {
1411
                            $tagsSelect = $form->addSelect(
1412
                                "extra_{$field_details['variable']}",
1413
                                $field_details['display_text'],
1414
                                [],
1415
                                ['style' => 'width: 100%;']
1416
                            );
1417
1418
                            if (false === $useTagAsSelect) {
1419
                                $tagsSelect->setAttribute('class', null);
1420
                            }
1421
1422
                            $tagsSelect->setAttribute(
1423
                                'id',
1424
                                "extra_{$field_details['variable']}"
1425
                            );
1426
                            $tagsSelect->setMultiple(true);
1427
1428
                            $selectedOptions = [];
1429
                            if ('user' === $this->type) {
1430
                                // The magic should be here
1431
                                $user_tags = UserManager::get_user_tags(
1432
                                    $itemId,
1433
                                    $field_details['id']
1434
                                );
1435
1436
                                if (is_array($user_tags) && count($user_tags) > 0) {
1437
                                    foreach ($user_tags as $tag) {
1438
                                        if (empty($tag['tag'])) {
1439
                                            continue;
1440
                                        }
1441
                                        $tagsSelect->addOption(
1442
                                            $tag['tag'],
1443
                                            $tag['tag'],
1444
                                            [
1445
                                                'selected' => 'selected',
1446
                                                'class' => 'selected',
1447
                                            ]
1448
                                        );
1449
                                        $selectedOptions[] = $tag['tag'];
1450
                                    }
1451
                                } else {
1452
                                    if (!empty($extraData) && isset($extraData['extra_'.$field_details['variable']])) {
1453
                                        $data = $extraData['extra_'.$field_details['variable']];
1454
                                        if (!empty($data)) {
1455
                                            foreach ($data as $option) {
1456
                                                $tagsSelect->addOption(
1457
                                                    $option,
1458
                                                    $option,
1459
                                                    [
1460
                                                        'selected' => 'selected',
1461
                                                        'class' => 'selected',
1462
                                                    ]
1463
                                                );
1464
                                                $selectedOptions[] = $option;
1465
                                            }
1466
                                        }
1467
                                    }
1468
                                }
1469
                                $url = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php';
1470
                            } else {
1471
                                $em = Database::getManager();
1472
                                $fieldTags = $em->getRepository(
1473
                                    'ChamiloCoreBundle:ExtraFieldRelTag'
1474
                                )
1475
                                    ->findBy(
1476
                                        [
1477
                                            'fieldId' => $field_id,
1478
                                            'itemId' => $itemId,
1479
                                        ]
1480
                                    );
1481
1482
                                /** @var ExtraFieldRelTag $fieldTag */
1483
                                foreach ($fieldTags as $fieldTag) {
1484
                                    /** @var Tag $tag */
1485
                                    $tag = $em->find('ChamiloCoreBundle:Tag', $fieldTag->getTagId());
1486
1487
                                    if (empty($tag)) {
1488
                                        continue;
1489
                                    }
1490
                                    $tagsSelect->addOption(
1491
                                        $tag->getTag(),
1492
                                        $tag->getTag()
1493
                                    );
1494
                                    $selectedOptions[] = $tag->getTag();
1495
                                }
1496
1497
                                if (!empty($extraData) && isset($extraData['extra_'.$field_details['variable']])) {
1498
                                    $data = $extraData['extra_'.$field_details['variable']];
1499
                                    if (!empty($data)) {
1500
                                        foreach ($data as $option) {
1501
                                            $tagsSelect->addOption(
1502
                                                $option,
1503
                                                $option
1504
                                            );
1505
                                        }
1506
                                    }
1507
                                }
1508
1509
                                if ($useTagAsSelect) {
1510
                                    $fieldTags = $em->getRepository('ChamiloCoreBundle:ExtraFieldRelTag')
1511
                                        ->findBy(
1512
                                            [
1513
                                                'fieldId' => $field_id,
1514
                                            ]
1515
                                        );
1516
                                    $tagsAdded = [];
1517
                                    foreach ($fieldTags as $fieldTag) {
1518
                                        $tag = $em->find('ChamiloCoreBundle:Tag', $fieldTag->getTagId());
1519
1520
                                        if (empty($tag)) {
1521
                                            continue;
1522
                                        }
1523
1524
                                        $tagText = $tag->getTag();
1525
1526
                                        if (in_array($tagText, $tagsAdded)) {
1527
                                            continue;
1528
                                        }
1529
1530
                                        $tagsSelect->addOption(
1531
                                            $tag->getTag(),
1532
                                            $tag->getTag(),
1533
                                            []
1534
                                        );
1535
1536
                                        $tagsAdded[] = $tagText;
1537
                                    }
1538
                                }
1539
                                $url = api_get_path(WEB_AJAX_PATH).'extra_field.ajax.php';
1540
                            }
1541
1542
                            $allowAsTags = 'true';
1543
1544
                            if ('portfolio' === $this->type) {
1545
                                $allowAsTags = 'false';
1546
                            }
1547
1548
                            $form->setDefaults(
1549
                                [
1550
                                    'extra_'.$field_details['variable'] => $selectedOptions,
1551
                                ]
1552
                            );
1553
1554
                            if (false == $useTagAsSelect) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
1555
                                $jquery_ready_content .= "
1556
                                $('#extra_$variable').select2({
1557
                                    ajax: {
1558
                                        url: '$url?a=search_tags&field_id=$field_id&type={$this->type}',
1559
                                        processResults: function (data) {
1560
                                            return {
1561
                                                results: data.items
1562
                                            }
1563
                                        }
1564
                                    },
1565
                                    cache: false,
1566
                                    tags: $allowAsTags,
1567
                                    tokenSeparators: [','],
1568
                                    placeholder: '".get_lang('StartToType')."'
1569
                                });
1570
                            ";
1571
                            }
1572
                        }
1573
1574
                        break;
1575
                    case self::FIELD_TYPE_TIMEZONE:
1576
                        $form->addElement(
1577
                            'select',
1578
                            'extra_'.$field_details['variable'],
1579
                            $field_details['display_text'],
1580
                            api_get_timezones(),
1581
                            ''
1582
                        );
1583
                        if ($freezeElement) {
1584
                            $form->freeze('extra_'.$field_details['variable']);
1585
                        }
1586
                        break;
1587
                    case self::FIELD_TYPE_SOCIAL_PROFILE:
1588
                        // get the social network's favicon
1589
                        $extra_data_variable = isset($extraData['extra_'.$field_details['variable']])
1590
                            ? $extraData['extra_'.$field_details['variable']]
1591
                            : null;
1592
                        $field_default_value = isset($field_details['field_default_value'])
1593
                            ? $field_details['field_default_value']
1594
                            : null;
1595
                        $icon_path = UserManager::get_favicon_from_url(
1596
                            $extra_data_variable,
1597
                            $field_default_value
1598
                        );
1599
                        // special hack for hi5
1600
                        $leftpad = '1.7';
1601
                        $top = '0.4';
1602
                        $domain = parse_url($icon_path, PHP_URL_HOST);
1603
                        if ('www.hi5.com' === $domain || 'hi5.com' === $domain) {
1604
                            $leftpad = '3';
1605
                            $top = '0';
1606
                        }
1607
                        // print the input field
1608
                        $form->addElement(
1609
                            'text',
1610
                            'extra_'.$field_details['variable'],
1611
                            $field_details['display_text'],
1612
                            [
1613
                                'size' => 60,
1614
                                'size' => implode(
1615
                                    '; ',
1616
                                    [
1617
                                        "background-image: url('$icon_path')",
1618
                                        'background-repeat: no-repeat',
1619
                                        "background-position: 0.4em {$top}em",
1620
                                        "padding-left: {$leftpad}em",
1621
                                    ]
1622
                                ),
1623
                            ]
1624
                        );
1625
                        $form->applyFilter('extra_'.$field_details['variable'], 'stripslashes');
1626
                        $form->applyFilter('extra_'.$field_details['variable'], 'trim');
1627
                        $form->applyFilter('extra_'.$field_details['variable'], 'html_filter');
1628
                        if ($freezeElement) {
1629
                            $form->freeze('extra_'.$field_details['variable']);
1630
                        }
1631
                        break;
1632
                    case self::FIELD_TYPE_MOBILE_PHONE_NUMBER:
1633
                        $form->addElement(
1634
                            'text',
1635
                            'extra_'.$field_details['variable'],
1636
                            $field_details['display_text'].' ('.get_lang('CountryDialCode').')',
1637
                            ['size' => 40, 'placeholder' => '(xx)xxxxxxxxx']
1638
                        );
1639
                        $form->applyFilter('extra_'.$field_details['variable'], 'stripslashes');
1640
                        $form->applyFilter('extra_'.$field_details['variable'], 'trim');
1641
                        $form->applyFilter('extra_'.$field_details['variable'], 'mobile_phone_number_filter');
1642
                        $form->applyFilter('extra_'.$field_details['variable'], 'html_filter');
1643
                        $form->addRule(
1644
                            'extra_'.$field_details['variable'],
1645
                            get_lang('MobilePhoneNumberWrong'),
1646
                            'mobile_phone_number'
1647
                        );
1648
                        if ($freezeElement) {
1649
                            $form->freeze('extra_'.$field_details['variable']);
1650
                        }
1651
                        break;
1652
                    case self::FIELD_TYPE_INTEGER:
1653
                        $form->addElement(
1654
                            'number',
1655
                            'extra_'.$field_details['variable'],
1656
                            $field_details['display_text'],
1657
                            ['class' => 'span1', 'step' => 1]
1658
                        );
1659
1660
                        $form->applyFilter('extra_'.$field_details['variable'], 'stripslashes');
1661
                        $form->applyFilter('extra_'.$field_details['variable'], 'trim');
1662
                        $form->applyFilter('extra_'.$field_details['variable'], 'intval');
1663
1664
                        if ($freezeElement) {
1665
                            $form->freeze('extra_'.$field_details['variable']);
1666
                        }
1667
                        break;
1668
                    case self::FIELD_TYPE_FILE_IMAGE:
1669
                        $fieldVariable = "extra_{$field_details['variable']}";
1670
                        $fieldTexts = [
1671
                            $field_details['display_text'],
1672
                        ];
1673
1674
                        if (is_array($extraData) && array_key_exists($fieldVariable, $extraData)) {
1675
                            if (file_exists(api_get_path(SYS_UPLOAD_PATH).$extraData[$fieldVariable])) {
1676
                                $fieldTexts[] = Display::img(
1677
                                    api_get_path(WEB_UPLOAD_PATH).$extraData[$fieldVariable],
1678
                                    $field_details['display_text'],
1679
                                    ['width' => '300']
1680
                                );
1681
                            }
1682
                        }
1683
1684
                        if ('Image' === $fieldTexts[0]) {
1685
                            $fieldTexts[0] = get_lang($fieldTexts[0]);
1686
                        }
1687
1688
                        $form->addFile(
1689
                            $fieldVariable,
1690
                            $fieldTexts,
1691
                            ['accept' => 'image/*', 'id' => 'extra_image', 'crop_image' => 'true']
1692
                        );
1693
1694
                        $form->applyFilter('extra_'.$field_details['variable'], 'stripslashes');
1695
                        $form->applyFilter('extra_'.$field_details['variable'], 'trim');
1696
1697
                        $allowedPictureTypes = ['jpg', 'jpeg', 'png', 'gif'];
1698
                        $form->addRule(
1699
                            'extra_'.$field_details['variable'],
1700
                            get_lang('OnlyImagesAllowed').' ('.implode(',', $allowedPictureTypes).')',
1701
                            'filetype',
1702
                            $allowedPictureTypes
1703
                        );
1704
1705
                        if ($freezeElement) {
1706
                            $form->freeze('extra_'.$field_details['variable']);
1707
                        }
1708
                        break;
1709
                    case self::FIELD_TYPE_FLOAT:
1710
                        $form->addElement(
1711
                            'number',
1712
                            'extra_'.$field_details['variable'],
1713
                            $field_details['display_text'],
1714
                            ['class' => 'span1', 'step' => '0.01']
1715
                        );
1716
1717
                        $form->applyFilter('extra_'.$field_details['variable'], 'stripslashes');
1718
                        $form->applyFilter('extra_'.$field_details['variable'], 'trim');
1719
                        $form->applyFilter('extra_'.$field_details['variable'], 'floatval');
1720
1721
                        if ($freezeElement) {
1722
                            $form->freeze('extra_'.$field_details['variable']);
1723
                        }
1724
                        break;
1725
                    case self::FIELD_TYPE_FILE:
1726
                        $fieldVariable = "extra_{$field_details['variable']}";
1727
                        $fieldTexts = [
1728
                            $field_details['display_text'],
1729
                        ];
1730
1731
                        if (is_array($extraData) &&
1732
                            array_key_exists($fieldVariable, $extraData)
1733
                        ) {
1734
                            if (file_exists(api_get_path(SYS_UPLOAD_PATH).$extraData[$fieldVariable])) {
1735
                                $linkToDelete = '';
1736
                                $divItemId = $field_details['variable'];
1737
                                if (api_is_platform_admin()) {
1738
                                    $url = api_get_path(WEB_AJAX_PATH).'extra_field.ajax.php?type='.$this->type;
1739
                                    $url .= '&a=delete_file&field_id='.$field_details['id'].'&item_id='.$itemId;
1740
1741
                                    $deleteId = $field_details['variable'].'_delete';
1742
                                    $form->addHtml(
1743
                                        "
1744
                                        <script>
1745
                                            $(function() {
1746
                                                $('#".$deleteId."').on('click', function() {
1747
                                                    $.ajax({
1748
                                                        type: 'GET',
1749
                                                        url: '".$url."',
1750
                                                        success: function(result) {
1751
                                                            if (result == 1) {
1752
                                                                $('#".$divItemId."').html('".get_lang('Deleted')."');
1753
                                                            }
1754
                                                        }
1755
                                                    });
1756
                                                });
1757
                                            });
1758
                                        </script>
1759
                                    "
1760
                                    );
1761
1762
                                    $linkToDelete = '&nbsp;'.Display::url(
1763
                                            Display::return_icon('delete.png', get_lang('Delete')),
1764
                                            'javascript:void(0)',
1765
                                            ['id' => $deleteId]
1766
                                        );
1767
                                }
1768
                                $fieldTexts[] = '<div id="'.$divItemId.'">'.Display::url(
1769
                                        basename($extraData[$fieldVariable]),
1770
                                        api_get_path(WEB_UPLOAD_PATH).$extraData[$fieldVariable],
1771
                                        [
1772
                                            'title' => $field_details['display_text'],
1773
                                            'target' => '_blank',
1774
                                        ]
1775
                                    ).$linkToDelete.'</div>';
1776
                            }
1777
                        }
1778
1779
                        $form->addElement(
1780
                            'file',
1781
                            $fieldVariable,
1782
                            $fieldTexts,
1783
                            []
1784
                        );
1785
1786
                        $form->applyFilter('extra_'.$field_details['variable'], 'stripslashes');
1787
                        $form->applyFilter('extra_'.$field_details['variable'], 'trim');
1788
1789
                        if ($freezeElement) {
1790
                            $form->freeze('extra_'.$field_details['variable']);
1791
                        }
1792
                        break;
1793
                    case self::FIELD_TYPE_VIDEO_URL:
1794
                        $form->addUrl(
1795
                            "extra_{$field_details['variable']}",
1796
                            $field_details['display_text'],
1797
                            false,
1798
                            ['placeholder' => 'https://']
1799
                        );
1800
                        if ($freezeElement) {
1801
                            $form->freeze('extra_'.$field_details['variable']);
1802
                        }
1803
                        break;
1804
                    case self::FIELD_TYPE_LETTERS_ONLY:
1805
                        $form->addTextLettersOnly(
1806
                            "extra_{$field_details['variable']}",
1807
                            $field_details['display_text']
1808
                        );
1809
                        $form->applyFilter('extra_'.$field_details['variable'], 'stripslashes');
1810
1811
                        if ($freezeElement) {
1812
                            $form->freeze('extra_'.$field_details['variable']);
1813
                        }
1814
                        break;
1815
                    case self::FIELD_TYPE_ALPHANUMERIC:
1816
                        $form->addTextAlphanumeric(
1817
                            "extra_{$field_details['variable']}",
1818
                            $field_details['display_text']
1819
                        );
1820
                        $form->applyFilter(
1821
                            'extra_'.$field_details['variable'],
1822
                            'stripslashes'
1823
                        );
1824
                        if ($freezeElement) {
1825
                            $form->freeze('extra_'.$field_details['variable']);
1826
                        }
1827
                        break;
1828
                    case self::FIELD_TYPE_LETTERS_SPACE:
1829
                        $form->addTextLettersAndSpaces(
1830
                            "extra_{$field_details['variable']}",
1831
                            $field_details['display_text']
1832
                        );
1833
                        $form->applyFilter('extra_'.$field_details['variable'], 'stripslashes');
1834
1835
                        if ($freezeElement) {
1836
                            $form->freeze('extra_'.$field_details['variable']);
1837
                        }
1838
                        break;
1839
                    case self::FIELD_TYPE_ALPHANUMERIC_SPACE:
1840
                        $form->addTextAlphanumericAndSpaces(
1841
                            "extra_{$field_details['variable']}",
1842
                            $field_details['display_text']
1843
                        );
1844
                        $form->applyFilter(
1845
                            'extra_'.$field_details['variable'],
1846
                            'stripslashes'
1847
                        );
1848
                        if ($freezeElement) {
1849
                            $form->freeze('extra_'.$field_details['variable']);
1850
                        }
1851
                        break;
1852
                    case self::FIELD_TYPE_GEOLOCALIZATION_COORDINATES:
1853
                    case self::FIELD_TYPE_GEOLOCALIZATION:
1854
                        $dataValue = isset($extraData['extra_'.$field_details['variable']])
1855
                            ? $extraData['extra_'.$field_details['variable']]
1856
                            : '';
1857
1858
                        $form->addGeoLocationMapField(
1859
                            'extra_'.$field_details['variable'],
1860
                            $field_details['display_text'],
1861
                            $dataValue,
1862
                            $hideGeoLocalizationDetails
1863
                        );
1864
1865
                        if ($freezeElement) {
1866
                            $form->freeze('extra_'.$field_details['variable']);
1867
                        }
1868
                        break;
1869
                    case self::FIELD_TYPE_SELECT_WITH_TEXT_FIELD:
1870
                        $jquery_ready_content .= $this->addSelectWithTextFieldElement(
1871
                            $form,
1872
                            $field_details,
1873
                            $freezeElement
1874
                        );
1875
                        break;
1876
                    case self::FIELD_TYPE_TRIPLE_SELECT:
1877
                        $jquery_ready_content .= $this->addTripleSelectElement(
1878
                            $form,
1879
                            $field_details,
1880
                            is_array($extraData) ? $extraData : [],
1881
                            $freezeElement
1882
                        );
1883
                        break;
1884
                }
1885
            }
1886
        }
1887
1888
        $return = [];
1889
        $return['jquery_ready_content'] = $jquery_ready_content;
1890
1891
        return $return;
1892
    }
1893
1894
    /**
1895
     * @param array $options
1896
     *
1897
     * @return array
1898
     */
1899
    public static function extra_field_double_select_convert_array_to_ordered_array($options)
1900
    {
1901
        $optionsParsed = [];
1902
        if (!empty($options)) {
1903
            foreach ($options as $option) {
1904
                if (0 == $option['option_value']) {
1905
                    $optionsParsed[$option['id']][] = $option;
1906
                } else {
1907
                    $optionsParsed[$option['option_value']][] = $option;
1908
                }
1909
            }
1910
        }
1911
1912
        return $optionsParsed;
1913
    }
1914
1915
    /**
1916
     * @return array
1917
     */
1918
    public static function tripleSelectConvertArrayToOrderedArray(array $options)
1919
    {
1920
        $level1 = self::getOptionsFromTripleSelect($options, 0);
1921
        $level2 = [];
1922
        $level3 = [];
1923
1924
        foreach ($level1 as $item1) {
1925
            $level2 += self::getOptionsFromTripleSelect($options, $item1['id']);
1926
        }
1927
1928
        foreach ($level2 as $item2) {
1929
            $level3 += self::getOptionsFromTripleSelect($options, $item2['id']);
1930
        }
1931
1932
        return ['level1' => $level1, 'level2' => $level2, 'level3' => $level3];
1933
    }
1934
1935
    /**
1936
     * @param string $type
1937
     *
1938
     * @return array
1939
     */
1940
    public function get_all_extra_field_by_type($type)
1941
    {
1942
        // all the information of the field
1943
        $sql = "SELECT * FROM {$this->table}
1944
                WHERE
1945
                    field_type = '".Database::escape_string($type)."' AND
1946
                    extra_field_type = $this->extraFieldType
1947
                ";
1948
        $result = Database::query($sql);
1949
1950
        $return = [];
1951
        while ($row = Database::fetch_array($result)) {
1952
            $return[] = $row['id'];
1953
        }
1954
1955
        return $return;
1956
    }
1957
1958
    /**
1959
     * @param int $id
1960
     */
1961
    public function get_field_type_by_id($id)
1962
    {
1963
        $types = $this->get_field_types();
1964
        if (isset($types[$id])) {
1965
            return $types[$id];
1966
        }
1967
1968
        return null;
1969
    }
1970
1971
    /**
1972
     * @return array
1973
     */
1974
    public function get_field_types()
1975
    {
1976
        return $this->get_extra_fields_by_handler($this->type);
1977
    }
1978
1979
    /**
1980
     * @param string $handler
1981
     *
1982
     * @return array
1983
     */
1984
    public static function get_extra_fields_by_handler($handler)
1985
    {
1986
        $types = [];
1987
        $types[self::FIELD_TYPE_TEXT] = get_lang('FieldTypeText');
1988
        $types[self::FIELD_TYPE_TEXTAREA] = get_lang('FieldTypeTextarea');
1989
        $types[self::FIELD_TYPE_RADIO] = get_lang('FieldTypeRadio');
1990
        $types[self::FIELD_TYPE_SELECT] = get_lang('FieldTypeSelect');
1991
        $types[self::FIELD_TYPE_SELECT_MULTIPLE] = get_lang('FieldTypeSelectMultiple');
1992
        $types[self::FIELD_TYPE_DATE] = get_lang('FieldTypeDate');
1993
        $types[self::FIELD_TYPE_DATETIME] = get_lang('FieldTypeDatetime');
1994
        $types[self::FIELD_TYPE_DOUBLE_SELECT] = get_lang('FieldTypeDoubleSelect');
1995
        $types[self::FIELD_TYPE_DIVIDER] = get_lang('FieldTypeDivider');
1996
        $types[self::FIELD_TYPE_TAG] = get_lang('FieldTypeTag');
1997
        $types[self::FIELD_TYPE_TIMEZONE] = get_lang('FieldTypeTimezone');
1998
        $types[self::FIELD_TYPE_SOCIAL_PROFILE] = get_lang('FieldTypeSocialProfile');
1999
        $types[self::FIELD_TYPE_MOBILE_PHONE_NUMBER] = get_lang('FieldTypeMobilePhoneNumber');
2000
        $types[self::FIELD_TYPE_CHECKBOX] = get_lang('FieldTypeCheckbox');
2001
        $types[self::FIELD_TYPE_INTEGER] = get_lang('FieldTypeInteger');
2002
        $types[self::FIELD_TYPE_FILE_IMAGE] = get_lang('FieldTypeFileImage');
2003
        $types[self::FIELD_TYPE_FLOAT] = get_lang('FieldTypeFloat');
2004
        $types[self::FIELD_TYPE_FILE] = get_lang('FieldTypeFile');
2005
        $types[self::FIELD_TYPE_VIDEO_URL] = get_lang('FieldTypeVideoUrl');
2006
        $types[self::FIELD_TYPE_LETTERS_ONLY] = get_lang('FieldTypeOnlyLetters');
2007
        $types[self::FIELD_TYPE_ALPHANUMERIC] = get_lang('FieldTypeAlphanumeric');
2008
        $types[self::FIELD_TYPE_LETTERS_SPACE] = get_lang('FieldTypeLettersSpaces');
2009
        $types[self::FIELD_TYPE_ALPHANUMERIC_SPACE] = get_lang('FieldTypeAlphanumericSpaces');
2010
        $types[self::FIELD_TYPE_GEOLOCALIZATION] = get_lang('Geolocalization');
2011
        $types[self::FIELD_TYPE_GEOLOCALIZATION_COORDINATES] = get_lang('GeolocalizationCoordinates');
2012
        $types[self::FIELD_TYPE_SELECT_WITH_TEXT_FIELD] = get_lang('FieldTypeSelectWithTextField');
2013
        $types[self::FIELD_TYPE_TRIPLE_SELECT] = get_lang('FieldTypeTripleSelect');
2014
2015
        switch ($handler) {
2016
            case 'course':
2017
            case 'session':
2018
            case 'user':
2019
            case 'skill':
2020
                break;
2021
        }
2022
2023
        return $types;
2024
    }
2025
2026
    /**
2027
     * @param array $params
2028
     * @param bool  $show_query
2029
     *
2030
     * @return int|bool
2031
     */
2032
    public function save($params, $show_query = false)
2033
    {
2034
        $fieldInfo = self::get_handler_field_info_by_field_variable($params['variable']);
0 ignored issues
show
Bug Best Practice introduced by
The method ExtraField::get_handler_...nfo_by_field_variable() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2034
        /** @scrutinizer ignore-call */ 
2035
        $fieldInfo = self::get_handler_field_info_by_field_variable($params['variable']);
Loading history...
2035
        $params = $this->clean_parameters($params);
2036
        $params['extra_field_type'] = $this->extraFieldType;
2037
2038
        if ($fieldInfo) {
2039
            return $fieldInfo['id'];
2040
        } else {
2041
            $id = parent::save($params, $show_query);
2042
            if ($id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $id of type false|integer is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
2043
                $fieldOption = new ExtraFieldOption($this->type);
2044
                $params['field_id'] = $id;
2045
                $fieldOption->save($params);
2046
            }
2047
2048
            return $id;
2049
        }
2050
    }
2051
2052
    /**
2053
     * Gets the set of values of an extra_field searching for the variable name.
2054
     *
2055
     * Example:
2056
     * <code>
2057
     * <?php
2058
     * $extraField = new ExtraField('lp_item');
2059
     * $extraFieldArray =  $extraField->get_handler_field_info_by_field_variable('authorlpitem');
2060
     * echo "<pre>".var_export($extraFieldArray,true)."</pre>";
2061
     * ?>
2062
     * </code>
2063
     *
2064
     * @param string $variable
2065
     *
2066
     * @return array|bool
2067
     */
2068
    public function get_handler_field_info_by_field_variable($variable)
2069
    {
2070
        $variable = Database::escape_string($variable);
2071
        $sql = "SELECT * FROM {$this->table}
2072
                WHERE
2073
                    variable = '$variable' AND
2074
                    extra_field_type = $this->extraFieldType";
2075
        $result = Database::query($sql);
2076
        if (Database::num_rows($result)) {
2077
            $row = Database::fetch_array($result, 'ASSOC');
2078
            if ($row) {
2079
                $row['display_text'] = self::translateDisplayName($row['variable'], $row['display_text']);
2080
2081
                // All the options of the field
2082
                $sql = "SELECT * FROM $this->table_field_options
2083
                    WHERE field_id='".intval($row['id'])."'
2084
                    ORDER BY option_order ASC";
2085
                $result = Database::query($sql);
2086
                while ($option = Database::fetch_array($result)) {
2087
                    $row['options'][$option['id']] = $option;
2088
                }
2089
2090
                return $row;
2091
            }
2092
        }
2093
2094
        return false;
2095
    }
2096
2097
    public function getHandlerEntityByFieldVariable(string $variable)
2098
    {
2099
        return Database::getManager()
2100
            ->getRepository('ChamiloCoreBundle:ExtraField')
2101
            ->findOneBy(['variable' => $variable, 'extraFieldType' => $this->extraFieldType]);
2102
    }
2103
2104
    /**
2105
     * @param array $params
2106
     *
2107
     * @return array
2108
     */
2109
    public function clean_parameters($params)
2110
    {
2111
        if (!isset($params['variable']) || empty($params['variable'])) {
2112
            $params['variable'] = $params['display_text'];
2113
        }
2114
2115
        $params['variable'] = trim(strtolower(str_replace(' ', '_', $params['variable'])));
2116
2117
        if (!isset($params['field_order'])) {
2118
            $max_order = self::get_max_field_order();
0 ignored issues
show
Bug Best Practice introduced by
The method ExtraField::get_max_field_order() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

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

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

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