Passed
Push — 1.11.x ( bce6cd...c146d9 )
by Angel Fernando Quiroz
12:25
created

main/inc/lib/extra_field.lib.php (1 issue)

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_field_options;
81
    public $table_field_values;
82
    public $table_field_tag;
83
    public $table_field_rel_tag;
84
85
    public $handler_id;
86
    public $primaryKey;
87
88
    /**
89
     * @param string $type
90
     */
91
    public function __construct($type)
92
    {
93
        parent::__construct();
94
95
        $this->type = $type;
96
        $this->table = Database::get_main_table(TABLE_EXTRA_FIELD);
97
        $this->table_field_options = Database::get_main_table(TABLE_EXTRA_FIELD_OPTIONS);
98
        $this->table_field_values = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
99
        $this->table_field_tag = Database::get_main_table(TABLE_MAIN_TAG);
100
        $this->table_field_rel_tag = Database::get_main_table(TABLE_MAIN_EXTRA_FIELD_REL_TAG);
101
102
        $this->handler_id = 'item_id';
103
104
        switch ($this->type) {
105
            case 'calendar_event':
106
                $this->extraFieldType = EntityExtraField::CALENDAR_FIELD_TYPE;
107
                break;
108
            case 'course':
109
                $this->extraFieldType = EntityExtraField::COURSE_FIELD_TYPE;
110
                $this->primaryKey = 'id';
111
                break;
112
            case 'user':
113
                $this->extraFieldType = EntityExtraField::USER_FIELD_TYPE;
114
                $this->primaryKey = 'id';
115
                break;
116
            case 'session':
117
                $this->extraFieldType = EntityExtraField::SESSION_FIELD_TYPE;
118
                $this->primaryKey = 'id';
119
                break;
120
            case 'exercise':
121
                $this->extraFieldType = EntityExtraField::EXERCISE_FIELD_TYPE;
122
                break;
123
            case 'question':
124
                $this->extraFieldType = EntityExtraField::QUESTION_FIELD_TYPE;
125
                break;
126
            case 'lp':
127
                $this->extraFieldType = EntityExtraField::LP_FIELD_TYPE;
128
                break;
129
            case 'lp_item':
130
                $this->extraFieldType = EntityExtraField::LP_ITEM_FIELD_TYPE;
131
                break;
132
            case 'skill':
133
                $this->extraFieldType = EntityExtraField::SKILL_FIELD_TYPE;
134
                break;
135
            case 'work':
136
                $this->extraFieldType = EntityExtraField::WORK_FIELD_TYPE;
137
                break;
138
            case 'career':
139
                $this->extraFieldType = EntityExtraField::CAREER_FIELD_TYPE;
140
                break;
141
            case 'user_certificate':
142
                $this->extraFieldType = EntityExtraField::USER_CERTIFICATE;
143
                break;
144
            case 'survey':
145
                $this->extraFieldType = EntityExtraField::SURVEY_FIELD_TYPE;
146
                break;
147
            case 'scheduled_announcement':
148
                $this->extraFieldType = EntityExtraField::SCHEDULED_ANNOUNCEMENT;
149
                break;
150
            case 'terms_and_condition':
151
                $this->extraFieldType = EntityExtraField::TERMS_AND_CONDITION_TYPE;
152
                break;
153
            case 'forum_category':
154
                $this->extraFieldType = EntityExtraField::FORUM_CATEGORY_TYPE;
155
                break;
156
            case 'forum_post':
157
                $this->extraFieldType = EntityExtraField::FORUM_POST_TYPE;
158
                break;
159
            case 'track_exercise':
160
                $this->extraFieldType = EntityExtraField::TRACK_EXERCISE_FIELD_TYPE;
161
                break;
162
            case 'portfolio':
163
                $this->extraFieldType = EntityExtraField::PORTFOLIO_TYPE;
164
                break;
165
            case 'lp_view':
166
                $this->extraFieldType = EntityExtraField::LP_VIEW_TYPE;
167
                break;
168
            case 'course_announcement':
169
                $this->extraFieldType = EntityExtraField::COURSE_ANNOUNCEMENT;
170
        }
171
172
        $this->pageUrl = 'extra_fields.php?type='.$this->type;
173
        // Example QuestionFields
174
        $this->pageName = get_lang(ucwords($this->type).'Fields');
175
    }
176
177
    /**
178
     * @return array
179
     */
180
    public static function getValidExtraFieldTypes()
181
    {
182
        $result = [
183
            'user',
184
            'course',
185
            'session',
186
            'question',
187
            'lp',
188
            'calendar_event',
189
            'lp_item',
190
            'skill',
191
            'work',
192
            'career',
193
            'user_certificate',
194
            'survey',
195
            'terms_and_condition',
196
            'forum_category',
197
            'forum_post',
198
            'exercise',
199
            'track_exercise',
200
            'lp_view',
201
            'course_announcement',
202
        ];
203
204
        if (api_get_configuration_value('allow_scheduled_announcements')) {
205
            $result[] = 'scheduled_announcement';
206
        }
207
208
        if (api_get_configuration_value('allow_portfolio_tool')) {
209
            $result[] = 'portfolio';
210
        }
211
        sort($result);
212
213
        return $result;
214
    }
215
216
    /**
217
     * Converts a string like this:
218
     * France:Paris;Bretagne;Marseille;Lyon|Belgique:Bruxelles;Namur;Liège;Bruges|Peru:Lima;Piura;
219
     * into
220
     * array(
221
     *   'France' =>
222
     *      array('Paris', 'Bretagne', 'Marseille'),
223
     *   'Belgique' =>
224
     *      array('Namur', 'Liège')
225
     * ), etc.
226
     *
227
     * @param string $string
228
     *
229
     * @return array
230
     */
231
    public static function extra_field_double_select_convert_string_to_array($string)
232
    {
233
        $options = explode('|', $string);
234
        $options_parsed = [];
235
        $id = 0;
236
237
        if (!empty($options)) {
238
            foreach ($options as $sub_options) {
239
                $options = explode(':', $sub_options);
240
                $sub_sub_options = isset($options[1]) ? explode(';', $options[1]) : [];
241
                $options_parsed[$id] = [
242
                    'label' => $options[0],
243
                    'options' => $sub_sub_options,
244
                ];
245
                $id++;
246
            }
247
        }
248
249
        return $options_parsed;
250
    }
251
252
    /**
253
     * @param $string
254
     *
255
     * @return array
256
     */
257
    public static function tripleSelectConvertStringToArray($string)
258
    {
259
        $options = [];
260
        foreach (explode('|', $string) as $i => $item0) {
261
            $level1 = explode('\\', $item0);
262
263
            foreach ($level1 as $j => $item1) {
264
                if (0 === $j) {
265
                    $options[] = ['label' => $item1, 'options' => []];
266
267
                    continue;
268
                }
269
270
                foreach (explode(':', $item1) as $k => $item2) {
271
                    if (0 === $k) {
272
                        $options[$i]['options'][] = ['label' => $item2, 'options' => []];
273
274
                        continue;
275
                    }
276
277
                    $options[$i]['options'][$j - 1]['options'][] = explode(';', $item2);
278
                }
279
            }
280
        }
281
282
        array_walk_recursive(
283
            $options,
284
            function (&$item) {
285
                $item = trim($item);
286
            }
287
        );
288
289
        return $options;
290
    }
291
292
    /**
293
     * @param array $options the result of the get_field_options_by_field() array
294
     *
295
     * @return string
296
     */
297
    public static function extra_field_double_select_convert_array_to_string($options)
298
    {
299
        $string = null;
300
        $optionsParsed = self::extra_field_double_select_convert_array_to_ordered_array($options);
301
302
        if (!empty($optionsParsed)) {
303
            foreach ($optionsParsed as $option) {
304
                foreach ($option as $key => $item) {
305
                    $string .= $item['display_text'];
306
                    if (0 == $key) {
307
                        $string .= ':';
308
                    } else {
309
                        if (isset($option[$key + 1])) {
310
                            $string .= ';';
311
                        }
312
                    }
313
                }
314
                $string .= '|';
315
            }
316
        }
317
318
        if (!empty($string)) {
319
            $string = substr($string, 0, strlen($string) - 1);
320
        }
321
322
        return $string;
323
    }
324
325
    /**
326
     * @param array $options The result of the get_field_options_by_field() array
327
     *
328
     * @return string
329
     */
330
    public static function extraFieldSelectWithTextConvertArrayToString(array $options)
331
    {
332
        $parsedOptions = self::extra_field_double_select_convert_array_to_ordered_array($options);
333
334
        if (empty($parsedOptions)) {
335
            return '';
336
        }
337
338
        $string = '';
339
        foreach ($parsedOptions as $options) {
340
            $option = current($options);
341
            $string .= $option['display_text'];
342
            $string .= '|';
343
        }
344
345
        return rtrim($string, '|');
346
    }
347
348
    /**
349
     * @return string
350
     */
351
    public static function tripleSelectConvertArrayToString(array $options)
352
    {
353
        $parsedOptions = self::tripleSelectConvertArrayToOrderedArray($options);
354
        $string = '';
355
        foreach ($parsedOptions['level1'] as $item1) {
356
            $string .= $item1['display_text'];
357
            $level2 = self::getOptionsFromTripleSelect($parsedOptions['level2'], $item1['id']);
358
359
            foreach ($level2 as $item2) {
360
                $string .= '\\'.$item2['display_text'].':';
361
                $level3 = self::getOptionsFromTripleSelect($parsedOptions['level3'], $item2['id']);
362
363
                $string .= implode(';', array_column($level3, 'display_text'));
364
            }
365
366
            $string .= '|';
367
        }
368
369
        return trim($string, '\\|;');
370
    }
371
372
    /**
373
     * @param string $variable
374
     * @param string $dataValue
375
     *
376
     * @return string
377
     */
378
    public static function getLocalizationJavascript($variable, $dataValue)
379
    {
380
        $dataValue = addslashes($dataValue);
381
        $html = "<script>
382
            $(function() {
383
                if (typeof google === 'object') {
384
                    var address = '$dataValue';
385
                    initializeGeo{$variable}(address, false);
386
387
                    $('#geolocalization_extra_{$variable}').on('click', function() {
388
                        var address = $('#{$variable}').val();
389
                        initializeGeo{$variable}(address, false);
390
                        return false;
391
                    });
392
393
                    $('#myLocation_extra_{$variable}').on('click', function() {
394
                        myLocation{$variable}();
395
                        return false;
396
                    });
397
398
                    // When clicking enter
399
                    $('#{$variable}').keypress(function(event) {
400
                        if (event.which == 13) {
401
                            $('#geolocalization_extra_{$variable}').click();
402
                            return false;
403
                        }
404
                    });
405
406
                    // On focus out update city
407
                    $('#{$variable}').focusout(function() {
408
                        $('#geolocalization_extra_{$variable}').click();
409
                        return false;
410
                    });
411
412
                    return;
413
                }
414
415
                $('#map_extra_{$variable}')
416
                    .html('<div class=\"alert alert-info\">"
417
            .addslashes(get_lang('YouNeedToActivateTheGoogleMapsPluginInAdminPlatformToSeeTheMap'))
418
            ."</div>');
419
            });
420
421
            function myLocation{$variable}()
422
            {
423
                if (navigator.geolocation) {
424
                    var geoPosition = function(position) {
425
                        var lat = position.coords.latitude;
426
                        var lng = position.coords.longitude;
427
                        var latLng = new google.maps.LatLng(lat, lng);
428
                        initializeGeo{$variable}(false, latLng);
429
                    };
430
431
                    var geoError = function(error) {
432
                        alert('Geocode ".get_lang('Error').": ' + error);
433
                    };
434
435
                    var geoOptions = {
436
                        enableHighAccuracy: true
437
                    };
438
                    navigator.geolocation.getCurrentPosition(geoPosition, geoError, geoOptions);
439
                }
440
            }
441
442
            function initializeGeo{$variable}(address, latLng)
443
            {
444
                var geocoder = new google.maps.Geocoder();
445
                var latlng = new google.maps.LatLng(-34.397, 150.644);
446
                var myOptions = {
447
                    zoom: 15,
448
                    center: latlng,
449
                    mapTypeControl: true,
450
                    mapTypeControlOptions: {
451
                        style: google.maps.MapTypeControlStyle.DROPDOWN_MENU
452
                    },
453
                    navigationControl: true,
454
                    mapTypeId: google.maps.MapTypeId.ROADMAP
455
                };
456
457
                map_{$variable} = new google.maps.Map(
458
                    document.getElementById('map_extra_{$variable}'),
459
                    myOptions
460
                );
461
462
                var parameter = address ? {'address': address} : latLng ? {'latLng': latLng} : false;
463
464
                if (geocoder && parameter) {
465
                    geocoder.geocode(parameter, function(results, status) {
466
                        if (status == google.maps.GeocoderStatus.OK) {
467
                            if (status != google.maps.GeocoderStatus.ZERO_RESULTS) {
468
                                map_{$variable}.setCenter(results[0].geometry.location);
469
470
                                // get city and country
471
                                var defaultAddress = results[0].formatted_address;
472
                                var city = '';
473
                                var country = '';
474
475
                                for (var i=0; i<results[0].address_components.length; i++) {
476
                                    if (results[0].address_components[i].types[0] == \"locality\") {
477
                                        //this is the object you are looking for City
478
                                        city = results[0].address_components[i];
479
                                    }
480
                                    /*if (results[j].address_components[i].types[0] == \"administrative_area_level_1\") {
481
                                        //this is the object you are looking for State
482
                                        region = results[0].address_components[i];
483
                                    }*/
484
                                    if (results[0].address_components[i].types[0] == \"country\") {
485
                                        //this is the object you are looking for
486
                                        country = results[0].address_components[i];
487
                                    }
488
                                }
489
490
                                if (city && city.long_name && country && country.long_name) {
491
                                    defaultAddress = city.long_name + ', ' + country.long_name;
492
                                }
493
                                $('#{$variable}').val(defaultAddress);
494
                                $('#{$variable}_coordinates').val(
495
                                    results[0].geometry.location.lat()+','+results[0].geometry.location.lng()
496
                                );
497
498
                                var infowindow = new google.maps.InfoWindow({
499
                                    content: '<b>' + $('#extra_{$variable}').val() + '</b>',
500
                                    size: new google.maps.Size(150, 50)
501
                                });
502
503
                                var marker = new google.maps.Marker({
504
                                    position: results[0].geometry.location,
505
                                    map: map_{$variable},
506
                                    title: $('#extra_{$variable}').val()
507
                                });
508
                                google.maps.event.addListener(marker, 'click', function() {
509
                                    infowindow.open(map_{$variable}, marker);
510
                                });
511
                            } else {
512
                                alert('".get_lang('NotFound')."');
513
                            }
514
                        } else {
515
                            alert('Geocode ".get_lang('Error').': '.get_lang('AddressField').' '.get_lang('NotFound')."');
516
                        }
517
                    });
518
                }
519
            }
520
            </script>";
521
522
        return $html;
523
    }
524
525
    /**
526
     * @param string $variable
527
     * @param string $text
528
     *
529
     * @return string
530
     */
531
    public static function getLocalizationInput($variable, $text)
532
    {
533
        $html = '
534
                <div class="form-group">
535
                    <label for="geolocalization_extra_'.$variable.'"
536
                        class="col-sm-2 control-label"></label>
537
                    <div class="col-sm-8">
538
                        <button class="btn btn-default"
539
                            id="geolocalization_extra_'.$variable.'"
540
                            name="geolocalization_extra_'.$variable.'"
541
                            type="submit">
542
                            <em class="fa fa-map-marker"></em> '.get_lang('SearchGeolocalization').'
543
                        </button>
544
                        <button class="btn btn-default" id="myLocation_extra_'.$variable.'"
545
                            name="myLocation_extra_'.$variable.'"
546
                            type="submit">
547
                            <em class="fa fa-crosshairs"></em> '.get_lang('MyLocation').'
548
                        </button>
549
                    </div>
550
                </div>
551
                <div class="form-group">
552
                    <label for="map_extra_'.$variable.'" class="col-sm-2 control-label">
553
                        '.$text.' - '.get_lang('Map').'
554
                    </label>
555
                    <div class="col-sm-8">
556
                        <div name="map_extra_'.$variable.'"
557
                            id="map_extra_'.$variable.'" style="width:100%; height:300px;">
558
                        </div>
559
                    </div>
560
                </div>
561
            ';
562
563
        return $html;
564
    }
565
566
    /**
567
     * @return int
568
     */
569
    public function get_count()
570
    {
571
        $em = Database::getManager();
572
        $query = $em->getRepository('ChamiloCoreBundle:ExtraField')->createQueryBuilder('e');
573
        $query->select('count(e.id)');
574
        $query->where('e.extraFieldType = :type');
575
        $query->setParameter('type', $this->getExtraFieldType());
576
577
        return $query->getQuery()->getSingleScalarResult();
578
    }
579
580
    /**
581
     * @return int
582
     */
583
    public function getExtraFieldType()
584
    {
585
        return (int) $this->extraFieldType;
586
    }
587
588
    /**
589
     * @param string $sidx
590
     * @param string $sord
591
     * @param int    $start
592
     * @param int    $limit
593
     *
594
     * @return array
595
     */
596
    public function getAllGrid($sidx, $sord, $start, $limit)
597
    {
598
        switch ($sidx) {
599
            case 'field_order':
600
                $sidx = 'e.fieldOrder';
601
                break;
602
            case 'variable':
603
                $sidx = 'e.variable';
604
                break;
605
            case 'display_text':
606
                $sidx = 'e.displayText';
607
                break;
608
            case 'changeable':
609
                $sidx = 'e.changeable';
610
                break;
611
            case 'visible_to_self':
612
                $sidx = 'e.visibleToSelf';
613
                break;
614
            case 'visible_to_others':
615
                $sidx = 'e.visibleToOthers';
616
                break;
617
            case 'filter':
618
                $sidx = 'e.filter';
619
                break;
620
        }
621
        $em = Database::getManager();
622
        $query = $em->getRepository('ChamiloCoreBundle:ExtraField')->createQueryBuilder('e');
623
        $query->select('e')
624
            ->where('e.extraFieldType = :type')
625
            ->setParameter('type', $this->getExtraFieldType())
626
            ->orderBy($sidx, $sord)
627
            ->setFirstResult($start)
628
            ->setMaxResults($limit);
629
630
        return $query->getQuery()->getArrayResult();
631
    }
632
633
    /**
634
     * Get all the field info for tags.
635
     *
636
     * @param string $variable
637
     *
638
     * @return array|bool
639
     */
640
    public function get_handler_field_info_by_tags($variable)
641
    {
642
        $variable = Database::escape_string($variable);
643
        $sql = "SELECT * FROM {$this->table}
644
                WHERE
645
                    variable = '$variable' AND
646
                    extra_field_type = $this->extraFieldType";
647
        $result = Database::query($sql);
648
        if (Database::num_rows($result)) {
649
            $row = Database::fetch_array($result, 'ASSOC');
650
            $row['display_text'] = $this->translateDisplayName(
651
                $row['variable'],
652
                $row['display_text']
653
            );
654
655
            // All the tags of the field
656
            $sql = "SELECT * FROM $this->table_field_tag
657
                    WHERE field_id='".intval($row['id'])."'
658
                    ORDER BY id ASC";
659
            $result = Database::query($sql);
660
            while ($option = Database::fetch_array($result, 'ASSOC')) {
661
                $row['options'][$option['id']] = $option;
662
            }
663
664
            return $row;
665
        } else {
666
            return false;
667
        }
668
    }
669
670
    /**
671
     * Translate the display text for a extra field.
672
     *
673
     * @param string $variable
674
     * @param string $defaultDisplayText
675
     *
676
     * @return string
677
     */
678
    public static function translateDisplayName($variable, $defaultDisplayText)
679
    {
680
        $camelCase = api_underscore_to_camel_case($variable);
681
682
        return isset($GLOBALS[$camelCase]) ? $GLOBALS[$camelCase] : $defaultDisplayText;
683
    }
684
685
    /**
686
     * @param int $fieldId
687
     *
688
     * @return array|bool
689
     */
690
    public function getFieldInfoByFieldId($fieldId)
691
    {
692
        $fieldId = (int) $fieldId;
693
        $sql = "SELECT * FROM {$this->table}
694
                WHERE
695
                    id = '$fieldId' AND
696
                    extra_field_type = $this->extraFieldType";
697
        $result = Database::query($sql);
698
        if (Database::num_rows($result)) {
699
            $row = Database::fetch_array($result, 'ASSOC');
700
701
            // All the options of the field
702
            $sql = "SELECT * FROM $this->table_field_options
703
                    WHERE field_id='".$fieldId."'
704
                    ORDER BY option_order ASC";
705
            $result = Database::query($sql);
706
            while ($option = Database::fetch_array($result)) {
707
                $row['options'][$option['id']] = $option;
708
            }
709
710
            return $row;
711
        } else {
712
            return false;
713
        }
714
    }
715
716
    /**
717
     * Add elements to a form.
718
     *
719
     * @param FormValidator $form                            The form object to which to attach this element
720
     * @param int           $itemId                          The item (course, user, session, etc) this extra_field is linked to
721
     * @param array         $exclude                         Variables of extra field to exclude
722
     * @param bool          $filter                          Whether to get only the fields with the "filter" flag set to 1 (true)
723
     *                                                       or not (false)
724
     * @param bool          $useTagAsSelect                  Whether to show tag fields as select drop-down or not
725
     * @param array         $showOnlyTheseFields             Limit the extra fields shown to just the list given here
726
     * @param array         $orderFields                     An array containing the names of the fields shown, in the right order
727
     * @param array         $extraData
728
     * @param bool          $orderDependingDefaults
729
     * @param bool          $adminPermissions
730
     * @param array         $separateExtraMultipleSelect
731
     * @param array         $customLabelsExtraMultipleSelect
732
     * @param bool          $addEmptyOptionSelects
733
     * @param array         $introductionTextList
734
     * @param array         $requiredFields
735
     * @param bool          $hideGeoLocalizationDetails
736
     *
737
     * @throws Exception
738
     *
739
     * @return array|bool If relevant, returns a one-element array with JS code to be added to the page HTML headers.
740
     *                    Returns false if the form object was not given
741
     */
742
    public function addElements(
743
        $form,
744
        $itemId = 0,
745
        $exclude = [],
746
        $filter = false,
747
        $useTagAsSelect = false,
748
        $showOnlyTheseFields = [],
749
        $orderFields = [],
750
        $extraData = [],
751
        $orderDependingDefaults = false,
752
        $adminPermissions = false,
753
        $separateExtraMultipleSelect = [],
754
        $customLabelsExtraMultipleSelect = [],
755
        $addEmptyOptionSelects = false,
756
        $introductionTextList = [],
757
        $requiredFields = [],
758
        $hideGeoLocalizationDetails = false,
759
        $help = false
760
    ) {
761
        if (empty($form)) {
762
            return false;
763
        }
764
765
        $itemId = (int) $itemId;
766
        $form->addHidden('item_id', $itemId);
767
        $extraData = false;
768
        if (!empty($itemId)) {
769
            $extraData = $this->get_handler_extra_data($itemId);
770
            if (!empty($showOnlyTheseFields)) {
771
                $setData = [];
772
                foreach ($showOnlyTheseFields as $variable) {
773
                    $extraName = 'extra_'.$variable;
774
                    if (in_array($extraName, array_keys($extraData))) {
775
                        $setData[$extraName] = $extraData[$extraName];
776
                    }
777
                }
778
                $form->setDefaults($setData);
779
            } else {
780
                $form->setDefaults($extraData);
781
            }
782
        }
783
784
        $conditions = [];
785
        if ($filter) {
786
            $conditions = ['filter = ?' => 1];
787
        }
788
789
        $extraFields = $this->get_all($conditions, 'option_order');
790
        $extra = $this->set_extra_fields_in_form(
791
            $form,
792
            $extraData,
793
            $adminPermissions,
794
            $extraFields,
795
            $itemId,
796
            $exclude,
797
            $useTagAsSelect,
798
            $showOnlyTheseFields,
799
            $orderFields,
800
            $orderDependingDefaults,
801
            $separateExtraMultipleSelect,
802
            $customLabelsExtraMultipleSelect,
803
            $addEmptyOptionSelects,
804
            $introductionTextList,
805
            $hideGeoLocalizationDetails,
806
            $help
807
        );
808
809
        if (!empty($requiredFields)) {
810
            /** @var HTML_QuickForm_input $element */
811
            foreach ($form->getElements() as $element) {
812
                $name = str_replace('extra_', '', $element->getName());
813
                if (in_array($name, $requiredFields)) {
814
                    $form->setRequired($element);
815
                }
816
            }
817
        }
818
819
        return $extra;
820
    }
821
822
    /**
823
     * Return an array of all the extra fields available for this item.
824
     *
825
     * @param int $itemId (session_id, question_id, course id)
826
     *
827
     * @return array
828
     */
829
    public function get_handler_extra_data($itemId)
830
    {
831
        if (empty($itemId)) {
832
            return [];
833
        }
834
835
        $extra_data = [];
836
        $fields = $this->get_all();
837
        $field_values = new ExtraFieldValue($this->type);
838
839
        if (!empty($fields)) {
840
            foreach ($fields as $field) {
841
                $field_value = $field_values->get_values_by_handler_and_field_id(
842
                    $itemId,
843
                    $field['id']
844
                );
845
846
                if (self::FIELD_TYPE_TAG == $field['field_type']) {
847
                    $tags = UserManager::get_user_tags_to_string(
848
                        $itemId,
849
                        $field['id'],
850
                        false
851
                    );
852
                    $extra_data['extra_'.$field['variable']] = $tags;
853
854
                    continue;
855
                }
856
857
                if ($field_value) {
858
                    $variable = $field['variable'];
859
                    $field_value = $field_value['value'];
860
                    switch ($field['field_type']) {
861
                        case self::FIELD_TYPE_TAG:
862
                            $tags = UserManager::get_user_tags_to_string(
863
                                $itemId,
864
                                $field['id'],
865
                                false
866
                            );
867
868
                            $extra_data['extra_'.$field['variable']] = $tags;
869
                            break;
870
                        case self::FIELD_TYPE_DOUBLE_SELECT:
871
                        case self::FIELD_TYPE_SELECT_WITH_TEXT_FIELD:
872
                            $selected_options = explode('::', $field_value);
873
                            $firstOption = isset($selected_options[0]) ? $selected_options[0] : '';
874
                            $secondOption = isset($selected_options[1]) ? $selected_options[1] : '';
875
                            $extra_data['extra_'.$field['variable']]['extra_'.$field['variable']] = $firstOption;
876
                            $extra_data['extra_'.$field['variable']]['extra_'.$field['variable'].'_second'] = $secondOption;
877
878
                            break;
879
                        case self::FIELD_TYPE_SELECT_MULTIPLE:
880
                            $field_value = explode(';', $field_value);
881
                            $extra_data['extra_'.$field['variable']] = $field_value;
882
                            break;
883
                        case self::FIELD_TYPE_RADIO:
884
                            $extra_data['extra_'.$field['variable']]['extra_'.$field['variable']] = $field_value;
885
                            break;
886
                        case self::FIELD_TYPE_TRIPLE_SELECT:
887
                            [$level1, $level2, $level3] = explode(';', $field_value);
888
889
                            $extra_data["extra_$variable"]["extra_$variable"] = $level1;
890
                            $extra_data["extra_$variable"]["extra_{$variable}_second"] = $level2;
891
                            $extra_data["extra_$variable"]["extra_{$variable}_third"] = $level3;
892
                            break;
893
                        default:
894
                            $extra_data['extra_'.$field['variable']] = $field_value;
895
                            break;
896
                    }
897
                } else {
898
                    // Set default values
899
                    if (isset($field['field_default_value']) &&
900
                        !empty($field['field_default_value'])
901
                    ) {
902
                        $extra_data['extra_'.$field['variable']] = $field['field_default_value'];
903
                    }
904
                }
905
            }
906
        }
907
908
        return $extra_data;
909
    }
910
911
    /**
912
     * Get an array of all the values from the extra_field and extra_field_options tables
913
     * based on the current object's type.
914
     *
915
     * @param array $conditions
916
     * @param null  $order_field_options_by
917
     *
918
     * @return array
919
     */
920
    public function get_all($conditions = [], $order_field_options_by = null)
921
    {
922
        $conditions = Database::parse_conditions(['where' => $conditions]);
923
924
        if (empty($conditions)) {
925
            $conditions .= ' WHERE extra_field_type = '.$this->extraFieldType;
926
        } else {
927
            $conditions .= ' AND extra_field_type = '.$this->extraFieldType;
928
        }
929
930
        $sql = "SELECT * FROM $this->table
931
                $conditions
932
                ORDER BY field_order ASC
933
        ";
934
935
        $result = Database::query($sql);
936
        $extraFields = Database::store_result($result, 'ASSOC');
937
938
        $option = new ExtraFieldOption($this->type);
939
        if (!empty($extraFields)) {
940
            foreach ($extraFields as &$extraField) {
941
                $extraField['display_text'] = $this->translateDisplayName(
942
                    $extraField['variable'],
943
                    $extraField['display_text']
944
                );
945
                $extraField['options'] = $option->get_field_options_by_field(
946
                    $extraField['id'],
947
                    false,
948
                    $order_field_options_by
949
                );
950
            }
951
        }
952
953
        return $extraFields;
954
    }
955
956
    /**
957
     * Add an element that matches the given extra field to the given $form object.
958
     *
959
     * @param FormValidator $form                The form these fields are to be attached to
960
     * @param array         $extraData
961
     * @param bool          $adminPermissions    Whether the display is considered without edition limits (true) or not
962
     *                                           (false)
963
     * @param array         $extra
964
     * @param int           $itemId              The item (course, user, session, etc) this extra_field is attached to
965
     * @param array         $exclude             Extra fields to be skipped, by textual ID
966
     * @param bool          $useTagAsSelect      Whether to show tag fields as select drop-down or not
967
     * @param array         $showOnlyTheseFields Limit the extra fields shown to just the list given here
968
     * @param array         $orderFields         An array containing the names of the fields shown, in the right order
969
     *
970
     * @throws Exception
971
     *
972
     * @return array If relevant, returns a one-element array with JS code to be added to the page HTML headers
973
     */
974
    public function set_extra_fields_in_form(
975
        $form,
976
        $extraData,
977
        $adminPermissions = false,
978
        $extra = [],
979
        $itemId = null,
980
        $exclude = [],
981
        $useTagAsSelect = false,
982
        $showOnlyTheseFields = [],
983
        $orderFields = [],
984
        $orderDependingDefaults = false,
985
        $separateExtraMultipleSelect = [],
986
        $customLabelsExtraMultipleSelect = [],
987
        $addEmptyOptionSelects = false,
988
        $introductionTextList = [],
989
        $hideGeoLocalizationDetails = false,
990
        $help = false
991
    ) {
992
        $jquery_ready_content = null;
993
        if (!empty($extra)) {
994
            $newOrder = [];
995
            if (!empty($orderFields)) {
996
                foreach ($orderFields as $order) {
997
                    foreach ($extra as $field_details) {
998
                        if ($order == $field_details['variable']) {
999
                            $newOrder[] = $field_details;
1000
                        }
1001
                    }
1002
                }
1003
                $extra = $newOrder;
1004
            }
1005
1006
            foreach ($extra as $field_details) {
1007
                if (!empty($showOnlyTheseFields)) {
1008
                    if (!in_array($field_details['variable'], $showOnlyTheseFields)) {
1009
                        continue;
1010
                    }
1011
                }
1012
1013
                // Getting default value id if is set
1014
                $defaultValueId = null;
1015
                if (isset($field_details['options']) && !empty($field_details['options'])) {
1016
                    $valueToFind = null;
1017
                    if (isset($field_details['field_default_value'])) {
1018
                        $valueToFind = $field_details['field_default_value'];
1019
                    }
1020
                    // If a value is found we override the default value
1021
                    if (isset($extraData['extra_'.$field_details['variable']])) {
1022
                        $valueToFind = $extraData['extra_'.$field_details['variable']];
1023
                    }
1024
1025
                    foreach ($field_details['options'] as $option) {
1026
                        if ($option['option_value'] == $valueToFind) {
1027
                            $defaultValueId = $option['id'];
1028
                        }
1029
                    }
1030
                }
1031
1032
                if (!$adminPermissions) {
1033
                    if (0 == $field_details['visible_to_self']) {
1034
                        continue;
1035
                    }
1036
1037
                    if (in_array($field_details['variable'], $exclude)) {
1038
                        continue;
1039
                    }
1040
                }
1041
1042
                if (!empty($introductionTextList) &&
1043
                    in_array($field_details['variable'], array_keys($introductionTextList))
1044
                ) {
1045
                    $form->addHtml($introductionTextList[$field_details['variable']]);
1046
                }
1047
1048
                $freezeElement = false;
1049
                if (!$adminPermissions) {
1050
                    $freezeElement = 0 == $field_details['visible_to_self'] || 0 == $field_details['changeable'];
1051
                }
1052
1053
                $translatedDisplayText = get_lang($field_details['display_text'], true);
1054
                $translatedDisplayHelpText = '';
1055
                if ($help) {
1056
                    $translatedDisplayHelpText .= get_lang($field_details['display_text'].'Help');
1057
                }
1058
                if (!empty($translatedDisplayText)) {
1059
                    if (!empty($translatedDisplayHelpText)) {
1060
                        // In this case, exceptionally, display_text is an array
1061
                        // which is then treated by display_form()
1062
                        $field_details['display_text'] = [$translatedDisplayText, $translatedDisplayHelpText];
1063
                    } else {
1064
                        // We have an helper text, use it
1065
                        $field_details['display_text'] = $translatedDisplayText;
1066
                    }
1067
                }
1068
1069
                switch ($field_details['field_type']) {
1070
                    case self::FIELD_TYPE_TEXT:
1071
                        $form->addElement(
1072
                            'text',
1073
                            'extra_'.$field_details['variable'],
1074
                            $field_details['display_text'],
1075
                            [
1076
                                'id' => 'extra_'.$field_details['variable'],
1077
                            ]
1078
                        );
1079
                        $form->applyFilter(
1080
                            'extra_'.$field_details['variable'],
1081
                            'stripslashes'
1082
                        );
1083
                        $form->applyFilter(
1084
                            'extra_'.$field_details['variable'],
1085
                            'trim'
1086
                        );
1087
                        if ($freezeElement) {
1088
                            $form->freeze('extra_'.$field_details['variable']);
1089
                        }
1090
                        break;
1091
                    case self::FIELD_TYPE_TEXTAREA:
1092
                        $form->addHtmlEditor(
1093
                            'extra_'.$field_details['variable'],
1094
                            $field_details['display_text'],
1095
                            false,
1096
                            false,
1097
                            [
1098
                                'ToolbarSet' => 'Profile',
1099
                                'Width' => '100%',
1100
                                'Height' => '130',
1101
                                'id' => 'extra_'.$field_details['variable'],
1102
                            ]
1103
                        );
1104
                        $form->applyFilter('extra_'.$field_details['variable'], 'stripslashes');
1105
                        $form->applyFilter('extra_'.$field_details['variable'], 'trim');
1106
                        if ($freezeElement) {
1107
                            $form->freeze('extra_'.$field_details['variable']);
1108
                        }
1109
                        break;
1110
                    case self::FIELD_TYPE_RADIO:
1111
                        $group = [];
1112
                        if (isset($field_details['options']) &&
1113
                            !empty($field_details['options'])
1114
                        ) {
1115
                            foreach ($field_details['options'] as $option_details) {
1116
                                $options[$option_details['option_value']] = $option_details['display_text'];
1117
                                $group[] = $form->createElement(
1118
                                    'radio',
1119
                                    'extra_'.$field_details['variable'],
1120
                                    $option_details['option_value'],
1121
                                    $option_details['display_text'].'<br />',
1122
                                    $option_details['option_value']
1123
                                );
1124
                            }
1125
                        }
1126
                        $form->addGroup(
1127
                            $group,
1128
                            'extra_'.$field_details['variable'],
1129
                            $field_details['display_text']
1130
                        );
1131
                        if ($freezeElement) {
1132
                            $form->freeze('extra_'.$field_details['variable']);
1133
                        }
1134
                        break;
1135
                    case self::FIELD_TYPE_CHECKBOX:
1136
                        $group = [];
1137
                        if (isset($field_details['options']) &&
1138
                            !empty($field_details['options'])
1139
                        ) {
1140
                            foreach ($field_details['options'] as $option_details) {
1141
                                $options[$option_details['option_value']] = $option_details['display_text'];
1142
                                $group[] = $form->createElement(
1143
                                    'checkbox',
1144
                                    'extra_'.$field_details['variable'],
1145
                                    $option_details['option_value'],
1146
                                    $option_details['display_text'].'<br />',
1147
                                    $option_details['option_value']
1148
                                );
1149
                            }
1150
                        } else {
1151
                            $fieldVariable = "extra_{$field_details['variable']}";
1152
                            $checkboxAttributes = [];
1153
                            if (is_array($extraData) &&
1154
                                array_key_exists($fieldVariable, $extraData)
1155
                            ) {
1156
                                if (!empty($extraData[$fieldVariable])) {
1157
                                    $checkboxAttributes['checked'] = 1;
1158
                                }
1159
                            }
1160
1161
                            if (empty($checkboxAttributes) &&
1162
                                isset($field_details['default_value']) && empty($extraData)) {
1163
                                if (1 == $field_details['default_value']) {
1164
                                    $checkboxAttributes['checked'] = 1;
1165
                                }
1166
                            }
1167
1168
                            // We assume that is a switch on/off with 1 and 0 as values
1169
                            $group[] = $form->createElement(
1170
                                'checkbox',
1171
                                'extra_'.$field_details['variable'],
1172
                                null,
1173
                                get_lang('Yes'),
1174
                                $checkboxAttributes
1175
                            );
1176
                        }
1177
1178
                        $form->addGroup(
1179
                            $group,
1180
                            'extra_'.$field_details['variable'],
1181
                            $field_details['display_text']
1182
                        );
1183
                        if ($freezeElement) {
1184
                            $form->freeze('extra_'.$field_details['variable']);
1185
                        }
1186
                        break;
1187
                    case self::FIELD_TYPE_SELECT:
1188
                        $this->addSelectElement($form, $field_details, $defaultValueId, $freezeElement);
1189
                        break;
1190
                    case self::FIELD_TYPE_SELECT_MULTIPLE:
1191
                        $options = [];
1192
                        if (empty($defaultValueId)) {
1193
                            $options[''] = get_lang('SelectAnOption');
1194
                        }
1195
1196
                        if (isset($field_details['options']) && !empty($field_details['options'])) {
1197
                            foreach ($field_details['options'] as $optionDetails) {
1198
                                $options[$optionDetails['option_value']] = $optionDetails['display_text'];
1199
                            }
1200
                        }
1201
1202
                        $form->addElement(
1203
                            'select',
1204
                            'extra_'.$field_details['variable'],
1205
                            $field_details['display_text'],
1206
                            $options,
1207
                            [
1208
                                'multiple' => 'multiple',
1209
                                'id' => 'extra_'.$field_details['variable'],
1210
                            ]
1211
                        );
1212
                        if ($freezeElement) {
1213
                            $form->freeze('extra_'.$field_details['variable']);
1214
                        }
1215
                        break;
1216
                    case self::FIELD_TYPE_DATE:
1217
                        $form->addDatePicker('extra_'.$field_details['variable'], $field_details['display_text']);
1218
                        if ($freezeElement) {
1219
                            $form->freeze('extra_'.$field_details['variable']);
1220
                        }
1221
                        break;
1222
                    case self::FIELD_TYPE_DATETIME:
1223
                        $form->addDateTimePicker(
1224
                            'extra_'.$field_details['variable'],
1225
                            $field_details['display_text']
1226
                        );
1227
1228
                        $defaults['extra_'.$field_details['variable']] = api_get_local_time();
1229
                        if (!isset($form->_defaultValues['extra_'.$field_details['variable']])) {
1230
                            $form->setDefaults($defaults);
1231
                        }
1232
                        if ($freezeElement) {
1233
                            $form->freeze('extra_'.$field_details['variable']);
1234
                        }
1235
                        break;
1236
                    case self::FIELD_TYPE_DOUBLE_SELECT:
1237
                        $jquery_ready_content .= self::addDoubleSelectElement(
1238
                            $form,
1239
                            $field_details,
1240
                            $extraData,
1241
                            $freezeElement
1242
                        );
1243
                        break;
1244
                    case self::FIELD_TYPE_DIVIDER:
1245
                        $form->addHtml(
1246
                            '
1247
                            <div class="form-group ">
1248
                                <div class="col-sm-12">
1249
                                    <div class="panel-separator">
1250
                                       <h4 id="'.$field_details['variable'].'" class="form-separator">'
1251
                            .$field_details['display_text'].'
1252
                                       </h4>
1253
                                    </div>
1254
                                </div>
1255
                            </div>
1256
                        '
1257
                        );
1258
                        break;
1259
                    case self::FIELD_TYPE_TAG:
1260
                        $variable = $field_details['variable'];
1261
                        $field_id = $field_details['id'];
1262
                        $separateValue = 0;
1263
                        if (isset($separateExtraMultipleSelect[$field_details['variable']])) {
1264
                            $separateValue = $separateExtraMultipleSelect[$field_details['variable']];
1265
                        }
1266
1267
                        $selectedOptions = [];
1268
                        if ($separateValue > 0) {
1269
                            $em = Database::getManager();
1270
                            $fieldTags = $em
1271
                                ->getRepository('ChamiloCoreBundle:ExtraFieldRelTag')
1272
                                ->findBy(
1273
                                    [
1274
                                        'fieldId' => $field_id,
1275
                                        'itemId' => $itemId,
1276
                                    ]
1277
                                );
1278
                            // ofaj
1279
1280
                            for ($i = 0; $i < $separateValue; $i++) {
1281
                                $tagsSelect = $form->addElement(
1282
                                    'select',
1283
                                    'extra_'.$field_details['variable'].'['.$i.']',
1284
                                    $customLabelsExtraMultipleSelect[$field_details['variable']][$i],
1285
                                    null,
1286
                                    ['id' => 'extra_'.$field_details['variable'].'_'.$i]
1287
                                );
1288
1289
                                if ($addEmptyOptionSelects) {
1290
                                    $tagsSelect->addOption(
1291
                                        '',
1292
                                        ''
1293
                                    );
1294
                                }
1295
1296
                                foreach ($fieldTags as $fieldTag) {
1297
                                    $tag = $em->find('ChamiloCoreBundle:Tag', $fieldTag->getTagId());
1298
1299
                                    if (empty($tag)) {
1300
                                        continue;
1301
                                    }
1302
1303
                                    $tagsSelect->addOption(
1304
                                        $tag->getTag(),
1305
                                        $tag->getTag()
1306
                                    );
1307
                                }
1308
                            }
1309
                        } else {
1310
                            $tagsSelect = $form->addSelect(
1311
                                "extra_{$field_details['variable']}",
1312
                                $field_details['display_text'],
1313
                                [],
1314
                                ['style' => 'width: 100%;']
1315
                            );
1316
1317
                            if (false === $useTagAsSelect) {
1318
                                $tagsSelect->setAttribute('class', null);
1319
                            }
1320
1321
                            $tagsSelect->setAttribute(
1322
                                'id',
1323
                                "extra_{$field_details['variable']}"
1324
                            );
1325
                            $tagsSelect->setMultiple(true);
1326
1327
                            $selectedOptions = [];
1328
                            if ('user' === $this->type) {
1329
                                // The magic should be here
1330
                                $user_tags = UserManager::get_user_tags(
1331
                                    $itemId,
1332
                                    $field_details['id']
1333
                                );
1334
1335
                                if (is_array($user_tags) && count($user_tags) > 0) {
1336
                                    foreach ($user_tags as $tag) {
1337
                                        if (empty($tag['tag'])) {
1338
                                            continue;
1339
                                        }
1340
                                        $tagsSelect->addOption(
1341
                                            $tag['tag'],
1342
                                            $tag['tag'],
1343
                                            [
1344
                                                'selected' => 'selected',
1345
                                                'class' => 'selected',
1346
                                            ]
1347
                                        );
1348
                                        $selectedOptions[] = $tag['tag'];
1349
                                    }
1350
                                }
1351
                                $url = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php';
1352
                            } else {
1353
                                $em = Database::getManager();
1354
                                $fieldTags = $em->getRepository(
1355
                                    'ChamiloCoreBundle:ExtraFieldRelTag'
1356
                                )
1357
                                    ->findBy(
1358
                                        [
1359
                                            'fieldId' => $field_id,
1360
                                            'itemId' => $itemId,
1361
                                        ]
1362
                                    );
1363
1364
                                /** @var ExtraFieldRelTag $fieldTag */
1365
                                foreach ($fieldTags as $fieldTag) {
1366
                                    /** @var Tag $tag */
1367
                                    $tag = $em->find('ChamiloCoreBundle:Tag', $fieldTag->getTagId());
1368
1369
                                    if (empty($tag)) {
1370
                                        continue;
1371
                                    }
1372
                                    $tagsSelect->addOption(
1373
                                        $tag->getTag(),
1374
                                        $tag->getTag()
1375
                                    );
1376
                                    $selectedOptions[] = $tag->getTag();
1377
                                }
1378
1379
                                if (!empty($extraData) && isset($extraData['extra_'.$field_details['variable']])) {
1380
                                    $data = $extraData['extra_'.$field_details['variable']];
1381
                                    if (!empty($data)) {
1382
                                        foreach ($data as $option) {
1383
                                            $tagsSelect->addOption(
1384
                                                $option,
1385
                                                $option
1386
                                            );
1387
                                        }
1388
                                    }
1389
                                }
1390
1391
                                if ($useTagAsSelect) {
1392
                                    $fieldTags = $em->getRepository('ChamiloCoreBundle:ExtraFieldRelTag')
1393
                                        ->findBy(
1394
                                            [
1395
                                                'fieldId' => $field_id,
1396
                                            ]
1397
                                        );
1398
                                    $tagsAdded = [];
1399
                                    foreach ($fieldTags as $fieldTag) {
1400
                                        $tag = $em->find('ChamiloCoreBundle:Tag', $fieldTag->getTagId());
1401
1402
                                        if (empty($tag)) {
1403
                                            continue;
1404
                                        }
1405
1406
                                        $tagText = $tag->getTag();
1407
1408
                                        if (in_array($tagText, $tagsAdded)) {
1409
                                            continue;
1410
                                        }
1411
1412
                                        $tagsSelect->addOption(
1413
                                            $tag->getTag(),
1414
                                            $tag->getTag(),
1415
                                            []
1416
                                        );
1417
1418
                                        $tagsAdded[] = $tagText;
1419
                                    }
1420
                                }
1421
                                $url = api_get_path(WEB_AJAX_PATH).'extra_field.ajax.php';
1422
                            }
1423
1424
                            $form->setDefaults(
1425
                                [
1426
                                    'extra_'.$field_details['variable'] => $selectedOptions,
1427
                                ]
1428
                            );
1429
1430
                            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...
1431
                                $jquery_ready_content .= "
1432
                                $('#extra_$variable').select2({
1433
                                    ajax: {
1434
                                        url: '$url?a=search_tags&field_id=$field_id&type={$this->type}',
1435
                                        processResults: function (data) {
1436
                                            return {
1437
                                                results: data.items
1438
                                            }
1439
                                        }
1440
                                    },
1441
                                    cache: false,
1442
                                    tags: true,
1443
                                    tokenSeparators: [','],
1444
                                    placeholder: '".get_lang('StartToType')."'
1445
                                });
1446
                            ";
1447
                            }
1448
                        }
1449
1450
                        break;
1451
                    case self::FIELD_TYPE_TIMEZONE:
1452
                        $form->addElement(
1453
                            'select',
1454
                            'extra_'.$field_details['variable'],
1455
                            $field_details['display_text'],
1456
                            api_get_timezones(),
1457
                            ''
1458
                        );
1459
                        if ($freezeElement) {
1460
                            $form->freeze('extra_'.$field_details['variable']);
1461
                        }
1462
                        break;
1463
                    case self::FIELD_TYPE_SOCIAL_PROFILE:
1464
                        // get the social network's favicon
1465
                        $extra_data_variable = isset($extraData['extra_'.$field_details['variable']])
1466
                            ? $extraData['extra_'.$field_details['variable']]
1467
                            : null;
1468
                        $field_default_value = isset($field_details['field_default_value'])
1469
                            ? $field_details['field_default_value']
1470
                            : null;
1471
                        $icon_path = UserManager::get_favicon_from_url(
1472
                            $extra_data_variable,
1473
                            $field_default_value
1474
                        );
1475
                        // special hack for hi5
1476
                        $leftpad = '1.7';
1477
                        $top = '0.4';
1478
                        $domain = parse_url($icon_path, PHP_URL_HOST);
1479
                        if ('www.hi5.com' === $domain || 'hi5.com' === $domain) {
1480
                            $leftpad = '3';
1481
                            $top = '0';
1482
                        }
1483
                        // print the input field
1484
                        $form->addElement(
1485
                            'text',
1486
                            'extra_'.$field_details['variable'],
1487
                            $field_details['display_text'],
1488
                            [
1489
                                'size' => 60,
1490
                                'size' => implode(
1491
                                    '; ',
1492
                                    [
1493
                                        "background-image: url('$icon_path')",
1494
                                        'background-repeat: no-repeat',
1495
                                        "background-position: 0.4em {$top}em",
1496
                                        "padding-left: {$leftpad}em",
1497
                                    ]
1498
                                ),
1499
                            ]
1500
                        );
1501
                        $form->applyFilter('extra_'.$field_details['variable'], 'stripslashes');
1502
                        $form->applyFilter('extra_'.$field_details['variable'], 'trim');
1503
                        if ($freezeElement) {
1504
                            $form->freeze('extra_'.$field_details['variable']);
1505
                        }
1506
                        break;
1507
                    case self::FIELD_TYPE_MOBILE_PHONE_NUMBER:
1508
                        $form->addElement(
1509
                            'text',
1510
                            'extra_'.$field_details['variable'],
1511
                            $field_details['display_text'].' ('.get_lang('CountryDialCode').')',
1512
                            ['size' => 40, 'placeholder' => '(xx)xxxxxxxxx']
1513
                        );
1514
                        $form->applyFilter('extra_'.$field_details['variable'], 'stripslashes');
1515
                        $form->applyFilter('extra_'.$field_details['variable'], 'trim');
1516
                        $form->applyFilter('extra_'.$field_details['variable'], 'mobile_phone_number_filter');
1517
                        $form->addRule(
1518
                            'extra_'.$field_details['variable'],
1519
                            get_lang('MobilePhoneNumberWrong'),
1520
                            'mobile_phone_number'
1521
                        );
1522
                        if ($freezeElement) {
1523
                            $form->freeze('extra_'.$field_details['variable']);
1524
                        }
1525
                        break;
1526
                    case self::FIELD_TYPE_INTEGER:
1527
                        $form->addElement(
1528
                            'number',
1529
                            'extra_'.$field_details['variable'],
1530
                            $field_details['display_text'],
1531
                            ['class' => 'span1', 'step' => 1]
1532
                        );
1533
1534
                        $form->applyFilter('extra_'.$field_details['variable'], 'stripslashes');
1535
                        $form->applyFilter('extra_'.$field_details['variable'], 'trim');
1536
                        $form->applyFilter('extra_'.$field_details['variable'], 'intval');
1537
1538
                        if ($freezeElement) {
1539
                            $form->freeze('extra_'.$field_details['variable']);
1540
                        }
1541
                        break;
1542
                    case self::FIELD_TYPE_FILE_IMAGE:
1543
                        $fieldVariable = "extra_{$field_details['variable']}";
1544
                        $fieldTexts = [
1545
                            $field_details['display_text'],
1546
                        ];
1547
1548
                        if (is_array($extraData) && array_key_exists($fieldVariable, $extraData)) {
1549
                            if (file_exists(api_get_path(SYS_UPLOAD_PATH).$extraData[$fieldVariable])) {
1550
                                $fieldTexts[] = Display::img(
1551
                                    api_get_path(WEB_UPLOAD_PATH).$extraData[$fieldVariable],
1552
                                    $field_details['display_text'],
1553
                                    ['width' => '300']
1554
                                );
1555
                            }
1556
                        }
1557
1558
                        if ('Image' === $fieldTexts[0]) {
1559
                            $fieldTexts[0] = get_lang($fieldTexts[0]);
1560
                        }
1561
1562
                        $form->addFile(
1563
                            $fieldVariable,
1564
                            $fieldTexts,
1565
                            ['accept' => 'image/*', 'id' => 'extra_image', 'crop_image' => 'true']
1566
                        );
1567
1568
                        $form->applyFilter('extra_'.$field_details['variable'], 'stripslashes');
1569
                        $form->applyFilter('extra_'.$field_details['variable'], 'trim');
1570
1571
                        $allowedPictureTypes = ['jpg', 'jpeg', 'png', 'gif'];
1572
                        $form->addRule(
1573
                            'extra_'.$field_details['variable'],
1574
                            get_lang('OnlyImagesAllowed').' ('.implode(',', $allowedPictureTypes).')',
1575
                            'filetype',
1576
                            $allowedPictureTypes
1577
                        );
1578
1579
                        if ($freezeElement) {
1580
                            $form->freeze('extra_'.$field_details['variable']);
1581
                        }
1582
                        break;
1583
                    case self::FIELD_TYPE_FLOAT:
1584
                        $form->addElement(
1585
                            'number',
1586
                            'extra_'.$field_details['variable'],
1587
                            $field_details['display_text'],
1588
                            ['class' => 'span1', 'step' => '0.01']
1589
                        );
1590
1591
                        $form->applyFilter('extra_'.$field_details['variable'], 'stripslashes');
1592
                        $form->applyFilter('extra_'.$field_details['variable'], 'trim');
1593
                        $form->applyFilter('extra_'.$field_details['variable'], 'floatval');
1594
1595
                        if ($freezeElement) {
1596
                            $form->freeze('extra_'.$field_details['variable']);
1597
                        }
1598
                        break;
1599
                    case self::FIELD_TYPE_FILE:
1600
                        $fieldVariable = "extra_{$field_details['variable']}";
1601
                        $fieldTexts = [
1602
                            $field_details['display_text'],
1603
                        ];
1604
1605
                        if (is_array($extraData) &&
1606
                            array_key_exists($fieldVariable, $extraData)
1607
                        ) {
1608
                            if (file_exists(api_get_path(SYS_UPLOAD_PATH).$extraData[$fieldVariable])) {
1609
                                $linkToDelete = '';
1610
                                $divItemId = $field_details['variable'];
1611
                                if (api_is_platform_admin()) {
1612
                                    $url = api_get_path(WEB_AJAX_PATH).'extra_field.ajax.php?type='.$this->type;
1613
                                    $url .= '&a=delete_file&field_id='.$field_details['id'].'&item_id='.$itemId;
1614
1615
                                    $deleteId = $field_details['variable'].'_delete';
1616
                                    $form->addHtml(
1617
                                        "
1618
                                        <script>
1619
                                            $(function() {
1620
                                                $('#".$deleteId."').on('click', function() {
1621
                                                    $.ajax({
1622
                                                        type: 'GET',
1623
                                                        url: '".$url."',
1624
                                                        success: function(result) {
1625
                                                            if (result == 1) {
1626
                                                                $('#".$divItemId."').html('".get_lang('Deleted')."');
1627
                                                            }
1628
                                                        }
1629
                                                    });
1630
                                                });
1631
                                            });
1632
                                        </script>
1633
                                    "
1634
                                    );
1635
1636
                                    $linkToDelete = '&nbsp;'.Display::url(
1637
                                            Display::return_icon('delete.png', get_lang('Delete')),
1638
                                            'javascript:void(0)',
1639
                                            ['id' => $deleteId]
1640
                                        );
1641
                                }
1642
                                $fieldTexts[] = '<div id="'.$divItemId.'">'.Display::url(
1643
                                        basename($extraData[$fieldVariable]),
1644
                                        api_get_path(WEB_UPLOAD_PATH).$extraData[$fieldVariable],
1645
                                        [
1646
                                            'title' => $field_details['display_text'],
1647
                                            'target' => '_blank',
1648
                                        ]
1649
                                    ).$linkToDelete.'</div>';
1650
                            }
1651
                        }
1652
1653
                        $form->addElement(
1654
                            'file',
1655
                            $fieldVariable,
1656
                            $fieldTexts,
1657
                            []
1658
                        );
1659
1660
                        $form->applyFilter('extra_'.$field_details['variable'], 'stripslashes');
1661
                        $form->applyFilter('extra_'.$field_details['variable'], 'trim');
1662
1663
                        if ($freezeElement) {
1664
                            $form->freeze('extra_'.$field_details['variable']);
1665
                        }
1666
                        break;
1667
                    case self::FIELD_TYPE_VIDEO_URL:
1668
                        $form->addUrl(
1669
                            "extra_{$field_details['variable']}",
1670
                            $field_details['display_text'],
1671
                            false,
1672
                            ['placeholder' => 'https://']
1673
                        );
1674
                        if ($freezeElement) {
1675
                            $form->freeze('extra_'.$field_details['variable']);
1676
                        }
1677
                        break;
1678
                    case self::FIELD_TYPE_LETTERS_ONLY:
1679
                        $form->addTextLettersOnly(
1680
                            "extra_{$field_details['variable']}",
1681
                            $field_details['display_text']
1682
                        );
1683
                        $form->applyFilter('extra_'.$field_details['variable'], 'stripslashes');
1684
1685
                        if ($freezeElement) {
1686
                            $form->freeze('extra_'.$field_details['variable']);
1687
                        }
1688
                        break;
1689
                    case self::FIELD_TYPE_ALPHANUMERIC:
1690
                        $form->addTextAlphanumeric(
1691
                            "extra_{$field_details['variable']}",
1692
                            $field_details['display_text']
1693
                        );
1694
                        $form->applyFilter(
1695
                            'extra_'.$field_details['variable'],
1696
                            'stripslashes'
1697
                        );
1698
                        if ($freezeElement) {
1699
                            $form->freeze('extra_'.$field_details['variable']);
1700
                        }
1701
                        break;
1702
                    case self::FIELD_TYPE_LETTERS_SPACE:
1703
                        $form->addTextLettersAndSpaces(
1704
                            "extra_{$field_details['variable']}",
1705
                            $field_details['display_text']
1706
                        );
1707
                        $form->applyFilter('extra_'.$field_details['variable'], 'stripslashes');
1708
1709
                        if ($freezeElement) {
1710
                            $form->freeze('extra_'.$field_details['variable']);
1711
                        }
1712
                        break;
1713
                    case self::FIELD_TYPE_ALPHANUMERIC_SPACE:
1714
                        $form->addTextAlphanumericAndSpaces(
1715
                            "extra_{$field_details['variable']}",
1716
                            $field_details['display_text']
1717
                        );
1718
                        $form->applyFilter(
1719
                            'extra_'.$field_details['variable'],
1720
                            'stripslashes'
1721
                        );
1722
                        if ($freezeElement) {
1723
                            $form->freeze('extra_'.$field_details['variable']);
1724
                        }
1725
                        break;
1726
                    case self::FIELD_TYPE_GEOLOCALIZATION_COORDINATES:
1727
                    case self::FIELD_TYPE_GEOLOCALIZATION:
1728
                        $dataValue = isset($extraData['extra_'.$field_details['variable']])
1729
                            ? $extraData['extra_'.$field_details['variable']]
1730
                            : '';
1731
1732
                        $form->addGeoLocationMapField(
1733
                            'extra_'.$field_details['variable'],
1734
                            $field_details['display_text'],
1735
                            $dataValue,
1736
                            $hideGeoLocalizationDetails
1737
                        );
1738
1739
                        if ($freezeElement) {
1740
                            $form->freeze('extra_'.$field_details['variable']);
1741
                        }
1742
                        break;
1743
                    case self::FIELD_TYPE_SELECT_WITH_TEXT_FIELD:
1744
                        $jquery_ready_content .= $this->addSelectWithTextFieldElement(
1745
                            $form,
1746
                            $field_details,
1747
                            $freezeElement
1748
                        );
1749
                        break;
1750
                    case self::FIELD_TYPE_TRIPLE_SELECT:
1751
                        $jquery_ready_content .= $this->addTripleSelectElement(
1752
                            $form,
1753
                            $field_details,
1754
                            is_array($extraData) ? $extraData : [],
1755
                            $freezeElement
1756
                        );
1757
                        break;
1758
                }
1759
            }
1760
        }
1761
1762
        $return = [];
1763
        $return['jquery_ready_content'] = $jquery_ready_content;
1764
1765
        return $return;
1766
    }
1767
1768
    /**
1769
     * @param array $options
1770
     *
1771
     * @return array
1772
     */
1773
    public static function extra_field_double_select_convert_array_to_ordered_array($options)
1774
    {
1775
        $optionsParsed = [];
1776
        if (!empty($options)) {
1777
            foreach ($options as $option) {
1778
                if (0 == $option['option_value']) {
1779
                    $optionsParsed[$option['id']][] = $option;
1780
                } else {
1781
                    $optionsParsed[$option['option_value']][] = $option;
1782
                }
1783
            }
1784
        }
1785
1786
        return $optionsParsed;
1787
    }
1788
1789
    /**
1790
     * @return array
1791
     */
1792
    public static function tripleSelectConvertArrayToOrderedArray(array $options)
1793
    {
1794
        $level1 = self::getOptionsFromTripleSelect($options, 0);
1795
        $level2 = [];
1796
        $level3 = [];
1797
1798
        foreach ($level1 as $item1) {
1799
            $level2 += self::getOptionsFromTripleSelect($options, $item1['id']);
1800
        }
1801
1802
        foreach ($level2 as $item2) {
1803
            $level3 += self::getOptionsFromTripleSelect($options, $item2['id']);
1804
        }
1805
1806
        return ['level1' => $level1, 'level2' => $level2, 'level3' => $level3];
1807
    }
1808
1809
    /**
1810
     * @param string $type
1811
     *
1812
     * @return array
1813
     */
1814
    public function get_all_extra_field_by_type($type)
1815
    {
1816
        // all the information of the field
1817
        $sql = "SELECT * FROM {$this->table}
1818
                WHERE
1819
                    field_type = '".Database::escape_string($type)."' AND
1820
                    extra_field_type = $this->extraFieldType
1821
                ";
1822
        $result = Database::query($sql);
1823
1824
        $return = [];
1825
        while ($row = Database::fetch_array($result)) {
1826
            $return[] = $row['id'];
1827
        }
1828
1829
        return $return;
1830
    }
1831
1832
    /**
1833
     * @param int $id
1834
     */
1835
    public function get_field_type_by_id($id)
1836
    {
1837
        $types = $this->get_field_types();
1838
        if (isset($types[$id])) {
1839
            return $types[$id];
1840
        }
1841
1842
        return null;
1843
    }
1844
1845
    /**
1846
     * @return array
1847
     */
1848
    public function get_field_types()
1849
    {
1850
        return $this->get_extra_fields_by_handler($this->type);
1851
    }
1852
1853
    /**
1854
     * @param string $handler
1855
     *
1856
     * @return array
1857
     */
1858
    public static function get_extra_fields_by_handler($handler)
1859
    {
1860
        $types = [];
1861
        $types[self::FIELD_TYPE_TEXT] = get_lang('FieldTypeText');
1862
        $types[self::FIELD_TYPE_TEXTAREA] = get_lang('FieldTypeTextarea');
1863
        $types[self::FIELD_TYPE_RADIO] = get_lang('FieldTypeRadio');
1864
        $types[self::FIELD_TYPE_SELECT] = get_lang('FieldTypeSelect');
1865
        $types[self::FIELD_TYPE_SELECT_MULTIPLE] = get_lang('FieldTypeSelectMultiple');
1866
        $types[self::FIELD_TYPE_DATE] = get_lang('FieldTypeDate');
1867
        $types[self::FIELD_TYPE_DATETIME] = get_lang('FieldTypeDatetime');
1868
        $types[self::FIELD_TYPE_DOUBLE_SELECT] = get_lang('FieldTypeDoubleSelect');
1869
        $types[self::FIELD_TYPE_DIVIDER] = get_lang('FieldTypeDivider');
1870
        $types[self::FIELD_TYPE_TAG] = get_lang('FieldTypeTag');
1871
        $types[self::FIELD_TYPE_TIMEZONE] = get_lang('FieldTypeTimezone');
1872
        $types[self::FIELD_TYPE_SOCIAL_PROFILE] = get_lang('FieldTypeSocialProfile');
1873
        $types[self::FIELD_TYPE_MOBILE_PHONE_NUMBER] = get_lang('FieldTypeMobilePhoneNumber');
1874
        $types[self::FIELD_TYPE_CHECKBOX] = get_lang('FieldTypeCheckbox');
1875
        $types[self::FIELD_TYPE_INTEGER] = get_lang('FieldTypeInteger');
1876
        $types[self::FIELD_TYPE_FILE_IMAGE] = get_lang('FieldTypeFileImage');
1877
        $types[self::FIELD_TYPE_FLOAT] = get_lang('FieldTypeFloat');
1878
        $types[self::FIELD_TYPE_FILE] = get_lang('FieldTypeFile');
1879
        $types[self::FIELD_TYPE_VIDEO_URL] = get_lang('FieldTypeVideoUrl');
1880
        $types[self::FIELD_TYPE_LETTERS_ONLY] = get_lang('FieldTypeOnlyLetters');
1881
        $types[self::FIELD_TYPE_ALPHANUMERIC] = get_lang('FieldTypeAlphanumeric');
1882
        $types[self::FIELD_TYPE_LETTERS_SPACE] = get_lang('FieldTypeLettersSpaces');
1883
        $types[self::FIELD_TYPE_ALPHANUMERIC_SPACE] = get_lang('FieldTypeAlphanumericSpaces');
1884
        $types[self::FIELD_TYPE_GEOLOCALIZATION] = get_lang('Geolocalization');
1885
        $types[self::FIELD_TYPE_GEOLOCALIZATION_COORDINATES] = get_lang('GeolocalizationCoordinates');
1886
        $types[self::FIELD_TYPE_SELECT_WITH_TEXT_FIELD] = get_lang('FieldTypeSelectWithTextField');
1887
        $types[self::FIELD_TYPE_TRIPLE_SELECT] = get_lang('FieldTypeTripleSelect');
1888
1889
        switch ($handler) {
1890
            case 'course':
1891
            case 'session':
1892
            case 'user':
1893
            case 'skill':
1894
                break;
1895
        }
1896
1897
        return $types;
1898
    }
1899
1900
    /**
1901
     * @param array $params
1902
     * @param bool  $show_query
1903
     *
1904
     * @return int|bool
1905
     */
1906
    public function save($params, $show_query = false)
1907
    {
1908
        $fieldInfo = self::get_handler_field_info_by_field_variable($params['variable']);
1909
        $params = $this->clean_parameters($params);
1910
        $params['extra_field_type'] = $this->extraFieldType;
1911
1912
        if ($fieldInfo) {
1913
            return $fieldInfo['id'];
1914
        } else {
1915
            $id = parent::save($params, $show_query);
1916
            if ($id) {
1917
                $fieldOption = new ExtraFieldOption($this->type);
1918
                $params['field_id'] = $id;
1919
                $fieldOption->save($params);
1920
            }
1921
1922
            return $id;
1923
        }
1924
    }
1925
1926
    /**
1927
     * Gets the set of values of an extra_field searching for the variable name.
1928
     *
1929
     * Example:
1930
     * <code>
1931
     * <?php
1932
     * $extraField = new ExtraField('lp_item');
1933
     * $extraFieldArray =  $extraField->get_handler_field_info_by_field_variable('authorlpitem');
1934
     * echo "<pre>".var_export($extraFieldArray,true)."</pre>";
1935
     * ?>
1936
     * </code>
1937
     *
1938
     * @param string $variable
1939
     *
1940
     * @return array|bool
1941
     */
1942
    public function get_handler_field_info_by_field_variable($variable)
1943
    {
1944
        $variable = Database::escape_string($variable);
1945
        $sql = "SELECT * FROM {$this->table}
1946
                WHERE
1947
                    variable = '$variable' AND
1948
                    extra_field_type = $this->extraFieldType";
1949
        $result = Database::query($sql);
1950
        if (Database::num_rows($result)) {
1951
            $row = Database::fetch_array($result, 'ASSOC');
1952
            if ($row) {
1953
                $row['display_text'] = self::translateDisplayName($row['variable'], $row['display_text']);
1954
1955
                // All the options of the field
1956
                $sql = "SELECT * FROM $this->table_field_options
1957
                    WHERE field_id='".intval($row['id'])."'
1958
                    ORDER BY option_order ASC";
1959
                $result = Database::query($sql);
1960
                while ($option = Database::fetch_array($result)) {
1961
                    $row['options'][$option['id']] = $option;
1962
                }
1963
1964
                return $row;
1965
            }
1966
        }
1967
1968
        return false;
1969
    }
1970
1971
    /**
1972
     * @param array $params
1973
     *
1974
     * @return array
1975
     */
1976
    public function clean_parameters($params)
1977
    {
1978
        if (!isset($params['variable']) || empty($params['variable'])) {
1979
            $params['variable'] = $params['display_text'];
1980
        }
1981
1982
        $params['variable'] = trim(strtolower(str_replace(' ', '_', $params['variable'])));
1983
1984
        if (!isset($params['field_order'])) {
1985
            $max_order = self::get_max_field_order();
1986
            $params['field_order'] = $max_order;
1987
        } else {
1988
            $params['field_order'] = (int) $params['field_order'];
1989
        }
1990
1991
        return $params;
1992
    }
1993
1994
    /**
1995
     * @return int
1996
     */
1997
    public function get_max_field_order()
1998
    {
1999
        $sql = "SELECT MAX(field_order)
2000
                FROM {$this->table}
2001
                WHERE
2002
                    extra_field_type = '.$this->extraFieldType.'";
2003
        $res = Database::query($sql);
2004
2005
        $order = 0;
2006
        if (Database::num_rows($res) > 0) {
2007
            $row = Database::fetch_row($res);
2008
            $order = $row[0] + 1;
2009
        }
2010
2011
        return $order;
2012
    }
2013
2014
    /**
2015
     * {@inheritdoc}
2016
     */
2017
    public function update($params, $showQuery = false)
2018
    {
2019
        $params = $this->clean_parameters($params);
2020
        if (isset($params['id'])) {
2021
            $fieldOption = new ExtraFieldOption($this->type);
2022
            $params['field_id'] = $params['id'];
2023
            if (empty($params['field_type'])) {
2024
                $params['field_type'] = $this->type;
2025
            }
2026
            $fieldOption->save($params, $showQuery);
2027
        }
2028
2029
        return parent::update($params, $showQuery);
2030
    }
2031
2032
    /**
2033
     * @param $id
2034
     *
2035
     * @return bool
2036
     */
2037
    public function delete($id)
2038
    {
2039
        $em = Database::getManager();
2040
        $items = $em->getRepository('ChamiloCoreBundle:ExtraFieldSavedSearch')->findBy(['field' => $id]);
2041
        if ($items) {
2042
            foreach ($items as $item) {
2043
                $em->remove($item);
2044
            }
2045
            $em->flush();
2046
        }
2047
        $field_option = new ExtraFieldOption($this->type);
2048
        $field_option->delete_all_options_by_field_id($id);
2049
2050
        $session_field_values = new ExtraFieldValue($this->type);
2051
        $session_field_values->delete_all_values_by_field_id($id);
2052
2053
        return parent::delete($id);
2054
    }
2055
2056
    /**
2057
     * @param $breadcrumb
2058
     * @param $action
2059
     */
2060
    public function setupBreadcrumb(&$breadcrumb, $action)
2061
    {
2062
        if ('add' === $action) {
2063
            $breadcrumb[] = ['url' => $this->pageUrl, 'name' => $this->pageName];
2064
            $breadcrumb[] = ['url' => '#', 'name' => get_lang('Add')];
2065
        } elseif ('edit' === $action) {
2066
            $breadcrumb[] = ['url' => $this->pageUrl, 'name' => $this->pageName];
2067
            $breadcrumb[] = ['url' => '#', 'name' => get_lang('Edit')];
2068
        } else {
2069
            $breadcrumb[] = ['url' => '#', 'name' => $this->pageName];
2070
        }
2071
    }
2072
2073
    /**
2074
     * Displays the title + grid.
2075
     */
2076
    public function display()
2077
    {
2078
        // action links
2079
        echo '<div class="actions">';
2080
        echo '<a href="../admin/index.php">';
2081
        echo Display::return_icon(
2082
            'back.png',
2083
            get_lang('BackTo').' '.get_lang('PlatformAdmin'),
2084
            '',
2085
            ICON_SIZE_MEDIUM
2086
        );
2087
        echo '</a>';
2088
        echo '<a href="'.api_get_self().'?action=add&type='.$this->type.'">';
2089
        echo Display::return_icon(
2090
            'add_user_fields.png',
2091
            get_lang('Add'),
2092
            '',
2093
            ICON_SIZE_MEDIUM
2094
        );
2095
        echo '</a>';
2096
        echo '</div>';
2097
        echo Display::grid_html($this->type.'_fields');
2098
    }
2099
2100
    /**
2101
     * @return array
2102
     */
2103
    public function getJqgridColumnNames()
2104
    {
2105
        return [
2106
            get_lang('Name'),
2107
            get_lang('FieldLabel'),
2108
            get_lang('Type'),
2109
            get_lang('FieldChangeability'),
2110
            get_lang('VisibleToSelf'),
2111
            get_lang('VisibleToOthers'),
2112
            get_lang('Filter'),
2113
            get_lang('FieldOrder'),
2114
            get_lang('Actions'),
2115
        ];
2116
    }
2117
2118
    /**
2119
     * @return array
2120
     */
2121
    public function getJqgridColumnModel()
2122
    {
2123
        return [
2124
            [
2125
                'name' => 'display_text',
2126
                'index' => 'display_text',
2127
                'width' => '140',
2128
                'align' => 'left',
2129
            ],
2130
            [
2131
                'name' => 'variable',
2132
                'index' => 'variable',
2133
                'width' => '90',
2134
                'align' => 'left',
2135
                'sortable' => 'true',
2136
            ],
2137
            [
2138
                'name' => 'field_type',
2139
                'index' => 'field_type',
2140
                'width' => '70',
2141
                'align' => 'left',
2142
                'sortable' => 'true',
2143
            ],
2144
            [
2145
                'name' => 'changeable',
2146
                'index' => 'changeable',
2147
                'width' => '35',
2148
                'align' => 'left',
2149
                'sortable' => 'true',
2150
            ],
2151
            [
2152
                'name' => 'visible_to_self',
2153
                'index' => 'visible_to_self',
2154
                'width' => '45',
2155
                'align' => 'left',
2156
                'sortable' => 'true',
2157
            ],
2158
            [
2159
                'name' => 'visible_to_others',
2160
                'index' => 'visible_to_others',
2161
                'width' => '35',
2162
                'align' => 'left',
2163
                'sortable' => 'true',
2164
            ],
2165
            [
2166
                'name' => 'filter',
2167
                'index' => 'filter',
2168
                'width' => '30',
2169
                'align' => 'left',
2170
                'sortable' => 'true',
2171
            ],
2172
            [
2173
                'name' => 'field_order',
2174
                'index' => 'field_order',
2175
                'width' => '25',
2176
                'align' => 'left',
2177
                'sortable' => 'true',
2178
            ],
2179
            [
2180
                'name' => 'actions',
2181
                'index' => 'actions',
2182
                'width' => '40',
2183
                'align' => 'left',
2184
                'formatter' => 'action_formatter',
2185
                'sortable' => 'false',
2186
            ],
2187
        ];
2188
    }
2189
2190
    /**
2191
     * @param string $url
2192
     * @param string $action
2193
     *
2194
     * @return FormValidator
2195
     */
2196
    public function return_form($url, $action)
2197
    {
2198
        $form = new FormValidator($this->type.'_field', 'post', $url);
2199
2200
        $form->addElement('hidden', 'type', $this->type);
2201
        $id = isset($_GET['id']) ? (int) $_GET['id'] : null;
2202
        $form->addElement('hidden', 'id', $id);
2203
2204
        // Setting the form elements
2205
        $header = get_lang('Add');
2206
        $defaults = [];
2207
2208
        if ('edit' === $action) {
2209
            $header = get_lang('Modify');
2210
            // Setting the defaults
2211
            $defaults = $this->get($id, false);
2212
        }
2213
2214
        $form->addElement('header', $header);
2215
2216
        if ('edit' === $action) {
2217
            $translateUrl = api_get_path(WEB_CODE_PATH).'extrafield/translate.php?'
2218
                .http_build_query(['extra_field' => $id]);
2219
            $translateButton = Display::toolbarButton(get_lang('TranslateThisTerm'), $translateUrl, 'language', 'link');
2220
2221
            $form->addText(
2222
                'display_text',
2223
                [get_lang('Name'), $translateButton]
2224
            );
2225
        } else {
2226
            $form->addElement('text', 'display_text', get_lang('Name'));
2227
        }
2228
2229
        // Field type
2230
        $types = self::get_field_types();
2231
2232
        $form->addElement(
2233
            'select',
2234
            'field_type',
2235
            get_lang('FieldType'),
2236
            $types,
2237
            ['id' => 'field_type']
2238
        );
2239
        $form->addElement('label', get_lang('Example'), '<div id="example">-</div>');
2240
        $form->addElement('text', 'variable', get_lang('FieldLabel'), ['class' => 'span5']);
2241
        $form->addElement(
2242
            'text',
2243
            'field_options',
2244
            get_lang('FieldPossibleValues'),
2245
            ['id' => 'field_options', 'class' => 'span6']
2246
        );
2247
2248
        $fieldWithOptions = [
2249
            self::FIELD_TYPE_RADIO,
2250
            self::FIELD_TYPE_SELECT_MULTIPLE,
2251
            self::FIELD_TYPE_SELECT,
2252
            self::FIELD_TYPE_TAG,
2253
            self::FIELD_TYPE_DOUBLE_SELECT,
2254
            self::FIELD_TYPE_SELECT_WITH_TEXT_FIELD,
2255
            self::FIELD_TYPE_TRIPLE_SELECT,
2256
        ];
2257
2258
        if ('edit' == $action) {
2259
            if (in_array($defaults['field_type'], $fieldWithOptions)) {
2260
                $url = Display::url(
2261
                    get_lang('EditExtraFieldOptions'),
2262
                    'extra_field_options.php?type='.$this->type.'&field_id='.$id
2263
                );
2264
                $form->addElement('label', null, $url);
2265
2266
                if (self::FIELD_TYPE_SELECT == $defaults['field_type']) {
2267
                    $urlWorkFlow = Display::url(
2268
                        get_lang('EditExtraFieldWorkFlow'),
2269
                        'extra_field_workflow.php?type='.$this->type.'&field_id='.$id
2270
                    );
2271
                    $form->addElement('label', null, $urlWorkFlow);
2272
                }
2273
2274
                $form->freeze('field_options');
2275
            }
2276
        }
2277
        $form->addElement(
2278
            'text',
2279
            'default_value',
2280
            get_lang('FieldDefaultValue'),
2281
            ['id' => 'default_value']
2282
        );
2283
2284
        $group = [];
2285
        $group[] = $form->createElement('radio', 'visible_to_self', null, get_lang('Yes'), 1);
2286
        $group[] = $form->createElement('radio', 'visible_to_self', null, get_lang('No'), 0);
2287
        $form->addGroup($group, '', get_lang('VisibleToSelf'), null, false);
2288
2289
        $group = [];
2290
        $group[] = $form->createElement('radio', 'visible_to_others', null, get_lang('Yes'), 1);
2291
        $group[] = $form->createElement('radio', 'visible_to_others', null, get_lang('No'), 0);
2292
        $form->addGroup($group, '', get_lang('VisibleToOthers'), null, false);
2293
2294
        $group = [];
2295
        $group[] = $form->createElement('radio', 'changeable', null, get_lang('Yes'), 1);
2296
        $group[] = $form->createElement('radio', 'changeable', null, get_lang('No'), 0);
2297
        $form->addGroup($group, '', get_lang('FieldChangeability'), null, false);
2298
2299
        $group = [];
2300
        $group[] = $form->createElement('radio', 'filter', null, get_lang('Yes'), 1);
2301
        $group[] = $form->createElement('radio', 'filter', null, get_lang('No'), 0);
2302
        $form->addGroup($group, '', get_lang('FieldFilter'), null, false);
2303
2304
        /* Enable this when field_loggeable is introduced as a table field (2.0)
2305
        $group   = array();
2306
        $group[] = $form->createElement('radio', 'field_loggeable', null, get_lang('Yes'), 1);
2307
        $group[] = $form->createElement('radio', 'field_loggeable', null, get_lang('No'), 0);
2308
        $form->addGroup($group, '', get_lang('FieldLoggeable'), '', false);
2309
        */
2310
2311
        $form->addElement('text', 'field_order', get_lang('FieldOrder'));
2312
2313
        if ('edit' == $action) {
2314
            $option = new ExtraFieldOption($this->type);
2315
            $defaults['field_options'] = $option->get_field_options_by_field_to_string($id);
2316
            $form->addButtonUpdate(get_lang('Modify'));
2317
        } else {
2318
            $defaults['visible_to_self'] = 0;
2319
            $defaults['visible_to_others'] = 0;
2320
            $defaults['changeable'] = 0;
2321
            $defaults['filter'] = 0;
2322
            $form->addButtonCreate(get_lang('Add'));
2323
        }
2324
2325
        /*if (!empty($defaults['created_at'])) {
2326
            $defaults['created_at'] = api_convert_and_format_date($defaults['created_at']);
2327
        }
2328
        if (!empty($defaults['updated_at'])) {
2329
            $defaults['updated_at'] = api_convert_and_format_date($defaults['updated_at']);
2330
        }*/
2331
        $form->setDefaults($defaults);
2332
2333
        // Setting the rules
2334
        $form->addRule('display_text', get_lang('ThisFieldIsRequired'), 'required');
2335
        $form->addRule('field_type', get_lang('ThisFieldIsRequired'), 'required');
2336
2337
        return $form;
2338
    }
2339
2340
    /**
2341
     * Gets an element.
2342
     *
2343
     * @param int  $id
2344
     * @param bool $translateDisplayText Optional
2345
     *
2346
     * @return array
2347
     */
2348
    public function get($id, $translateDisplayText = true)
2349
    {
2350
        $info = parent::get($id);
2351
2352
        if ($translateDisplayText) {
2353
            $info['display_text'] = self::translateDisplayName($info['variable'], $info['display_text']);
2354
        }
2355
2356
        return $info;
2357
    }
2358
2359
    /**
2360
     * @param $token
2361
     *
2362
     * @return string
2363
     */
2364
    public function getJqgridActionLinks($token)
2365
    {
2366
        //With this function we can add actions to the jgrid (edit, delete, etc)
2367
        $editIcon = Display::return_icon('edit.png', get_lang('Edit'), '', ICON_SIZE_SMALL);
2368
        $deleteIcon = Display::return_icon('delete.png', get_lang('Delete'), '', ICON_SIZE_SMALL);
2369
        $confirmMessage = addslashes(
2370
            api_htmlentities(get_lang('ConfirmYourChoice'), ENT_QUOTES)
2371
        );
2372
2373
        $editButton = <<<JAVASCRIPT
2374
            <a href="?action=edit&type={$this->type}&id=' + options.rowId + '" class="btn btn-link btn-xs">\
2375
                $editIcon\
2376
            </a>
2377
JAVASCRIPT;
2378
        $deleteButton = <<<JAVASCRIPT
2379
            <a \
2380
                onclick="if (!confirm(\'$confirmMessage\')) {return false;}" \
2381
                href="?sec_token=$token&type={$this->type}&id=' + options.rowId + '&action=delete" \
2382
                class="btn btn-link btn-xs">\
2383
                $deleteIcon\
2384
            </a>
2385
JAVASCRIPT;
2386
2387
        return "function action_formatter(cellvalue, options, rowObject) {
2388
            return '$editButton $deleteButton';
2389
        }";
2390
    }
2391
2392
    /**
2393
     * @param array $columns
2394
     * @param array $column_model
2395
     * @param array $extraFields
2396
     *
2397
     * @return array
2398
     */
2399
    public function getRules(&$columns, &$column_model, $extraFields = [], $checkExtraFieldExistence = false)
2400
    {
2401
        $fields = $this->get_all(
2402
            [
2403
                'visible_to_self = ? AND filter = ?' => [1, 1],
2404
            ],
2405
            'display_text'
2406
        );
2407
        $extraFieldOption = new ExtraFieldOption($this->type);
2408
2409
        $rules = [];
2410
        if (!empty($fields)) {
2411
            foreach ($fields as $field) {
2412
                $search_options = [];
2413
                $type = 'text';
2414
                if (in_array($field['field_type'], [self::FIELD_TYPE_SELECT, self::FIELD_TYPE_DOUBLE_SELECT])) {
2415
                    $type = 'select';
2416
                    $search_options['sopt'] = ['eq', 'ne']; //equal not equal
2417
                } else {
2418
                    $search_options['sopt'] = ['cn', 'nc']; //contains not contains
2419
                }
2420
2421
                $search_options['searchhidden'] = 'true';
2422
                $search_options['defaultValue'] = isset($search_options['field_default_value'])
2423
                    ? $search_options['field_default_value']
2424
                    : null;
2425
2426
                if (self::FIELD_TYPE_DOUBLE_SELECT == $field['field_type']) {
2427
                    // Add 2 selects
2428
                    $options = $extraFieldOption->get_field_options_by_field($field['id']);
2429
                    $options = self::extra_field_double_select_convert_array_to_ordered_array($options);
2430
2431
                    $first_options = [];
2432
                    if (!empty($options)) {
2433
                        foreach ($options as $option) {
2434
                            foreach ($option as $sub_option) {
2435
                                if (0 == $sub_option['option_value']) {
2436
                                    $first_options[] = $sub_option['field_id'].'#'.$sub_option['id'].':'
2437
                                        .$sub_option['display_text'];
2438
                                }
2439
                            }
2440
                        }
2441
                    }
2442
2443
                    $search_options['value'] = implode(';', $first_options);
2444
                    $search_options['dataInit'] = 'fill_second_select';
2445
2446
                    // First
2447
                    $column_model[] = [
2448
                        'name' => 'extra_'.$field['variable'],
2449
                        'index' => 'extra_'.$field['variable'],
2450
                        'width' => '100',
2451
                        'hidden' => 'true',
2452
                        'search' => 'true',
2453
                        'stype' => 'select',
2454
                        'searchoptions' => $search_options,
2455
                    ];
2456
                    $columns[] = $field['display_text'].' (1)';
2457
                    $rules[] = [
2458
                        'field' => 'extra_'.$field['variable'],
2459
                        'op' => 'cn',
2460
                    ];
2461
2462
                    // Second
2463
                    $search_options['value'] = $field['id'].':';
2464
                    $search_options['dataInit'] = 'register_second_select';
2465
2466
                    $column_model[] = [
2467
                        'name' => 'extra_'.$field['variable'].'_second',
2468
                        'index' => 'extra_'.$field['variable'].'_second',
2469
                        'width' => '100',
2470
                        'hidden' => 'true',
2471
                        'search' => 'true',
2472
                        'stype' => 'select',
2473
                        'searchoptions' => $search_options,
2474
                    ];
2475
                    $columns[] = $field['display_text'].' (2)';
2476
                    $rules[] = ['field' => 'extra_'.$field['variable'].'_second', 'op' => 'cn'];
2477
                    continue;
2478
                } else {
2479
                    $search_options['value'] = $extraFieldOption->getFieldOptionsToString(
2480
                        $field['id'],
2481
                        false,
2482
                        'display_text'
2483
                    );
2484
                }
2485
                $column_model[] = [
2486
                    'name' => 'extra_'.$field['variable'],
2487
                    'index' => 'extra_'.$field['variable'],
2488
                    'width' => '100',
2489
                    'hidden' => 'true',
2490
                    'search' => 'true',
2491
                    'stype' => $type,
2492
                    'searchoptions' => $search_options,
2493
                ];
2494
                $columns[] = $field['display_text'];
2495
                $rules[] = [
2496
                    'field' => 'extra_'.$field['variable'],
2497
                    'op' => 'cn',
2498
                    'data' => '',
2499
                ];
2500
            }
2501
        }
2502
2503
        return $rules;
2504
    }
2505
2506
    public function processExtraFieldSearch($values, $form, $alias, $condition = 'OR')
2507
    {
2508
        // Parse params.
2509
        $fields = [];
2510
        foreach ($values as $key => $value) {
2511
            if (substr($key, 0, 6) !== 'extra_' &&
2512
                substr($key, 0, 7) !== '_extra_'
2513
            ) {
2514
                continue;
2515
            }
2516
            if (!empty($value)) {
2517
                $fields[$key] = $value;
2518
            }
2519
        }
2520
2521
        $extraFieldsAll = $this->get_all(['visible_to_self = ? AND filter = ?' => [1, 1]], 'option_order');
2522
        $extraFieldsType = array_column($extraFieldsAll, 'field_type', 'variable');
2523
        $extraFields = array_column($extraFieldsAll, 'variable');
2524
        $filter = new stdClass();
2525
        $defaults = [];
2526
        foreach ($fields as $variable => $col) {
2527
            $variableNoExtra = str_replace('extra_', '', $variable);
2528
            if (isset($values[$variable]) && !empty($values[$variable]) &&
2529
                in_array($variableNoExtra, $extraFields)
2530
            ) {
2531
                $rule = new stdClass();
2532
                $rule->field = $variable;
2533
                $rule->op = 'in';
2534
                $data = $col;
2535
                if (is_array($data) && array_key_exists($variable, $data)) {
2536
                    $data = $col;
2537
                }
2538
                $rule->data = $data;
2539
                $filter->rules[] = $rule;
2540
                $filter->groupOp = 'AND';
2541
2542
                if ($extraFieldsType[$variableNoExtra] == ExtraField::FIELD_TYPE_TAG) {
2543
                    $tagElement = $form->getElement($variable);
2544
                    $tags = [];
2545
                    foreach ($values[$variable] as $tag) {
2546
                        $tag = Security::remove_XSS($tag);
2547
                        $tags[] = $tag;
2548
                        $tagElement->addOption(
2549
                            $tag,
2550
                            $tag
2551
                        );
2552
                    }
2553
                    $defaults[$variable] = $tags;
2554
                } else {
2555
                    if (is_array($data)) {
2556
                        $defaults[$variable] = array_map(['Security', 'remove_XSS'], $data);
2557
                    } else {
2558
                        $defaults[$variable] = Security::remove_XSS($data);
2559
                    }
2560
                }
2561
            }
2562
        }
2563
2564
        $result = $this->getExtraFieldRules($filter, 'extra_', $condition);
2565
        $conditionArray = $result['condition_array'];
2566
2567
        $whereCondition = '';
2568
        $extraCondition = '';
2569
        if (!empty($conditionArray)) {
2570
            $extraCondition = ' ( ';
2571
            $extraCondition .= implode(' AND ', $conditionArray);
2572
            $extraCondition .= ' ) ';
2573
        }
2574
        $whereCondition .= $extraCondition;
2575
        $conditions = $this->parseConditions(
2576
            [
2577
                'where' => $whereCondition,
2578
                'extra' => $result['extra_fields'],
2579
            ],
2580
            $alias
2581
        );
2582
2583
        return ['condition' => $conditions, 'fields' => $fields, 'defaults' => $defaults];
2584
    }
2585
2586
    /**
2587
     * @param        $filters
2588
     * @param string $stringToSearch
2589
     *
2590
     * @return array
2591
     */
2592
    public function getExtraFieldRules($filters, $stringToSearch = 'extra_', $condition = 'OR')
2593
    {
2594
        $extraFields = [];
2595
        $conditionArray = [];
2596
2597
        // Getting double select if exists
2598
        $double_select = [];
2599
        if (is_object($filters) &&
2600
            property_exists($filters, 'rules') &&
2601
            is_array($filters->rules) &&
2602
            !empty($filters->rules)
2603
        ) {
2604
            foreach ($filters->rules as $rule) {
2605
                if (empty($rule)) {
2606
                    continue;
2607
                }
2608
                if (false === strpos($rule->field, '_second')) {
2609
                } else {
2610
                    $my_field = str_replace('_second', '', $rule->field);
2611
                    $double_select[$my_field] = $rule->data;
2612
                }
2613
            }
2614
2615
            foreach ($filters->rules as $rule) {
2616
                if (empty($rule)) {
2617
                    continue;
2618
                }
2619
                if (false === strpos($rule->field, $stringToSearch)) {
2620
                    // normal fields
2621
                    $field = $rule->field;
2622
                    if (isset($rule->data) && is_string($rule->data) && -1 != $rule->data) {
2623
                        $conditionArray[] = $this->get_where_clause($field, $rule->op, $rule->data);
2624
                    }
2625
                } else {
2626
                    // Extra fields
2627
                    $ruleField = Database::escapeField($rule->field);
2628
                    if (false === strpos($rule->field, '_second')) {
2629
                        // No _second
2630
                        $original_field = str_replace($stringToSearch, '', $rule->field);
2631
                        $field_option = $this->get_handler_field_info_by_field_variable($original_field);
2632
2633
                        switch ($field_option['field_type']) {
2634
                            case self::FIELD_TYPE_DOUBLE_SELECT:
2635
                                if (isset($double_select[$rule->field])) {
2636
                                    $data = explode('#', $rule->data);
2637
                                    $rule->data = $data[1].'::'.$double_select[$rule->field];
2638
                                } else {
2639
                                    // only was sent 1 select
2640
                                    if (is_string($rule->data)) {
2641
                                        $data = explode('#', $rule->data);
2642
                                        $rule->data = $data[1];
2643
                                    }
2644
                                }
2645
2646
                                if (!isset($rule->data)) {
2647
                                    $conditionArray[] = ' ('
2648
                                        .$this->get_where_clause($rule->field, $rule->op, $rule->data)
2649
                                        .') ';
2650
                                    $extraFields[] = ['field' => $ruleField, 'id' => $field_option['id']];
2651
                                }
2652
                                break;
2653
                            case self::FIELD_TYPE_TAG:
2654
                                if (isset($rule->data)) {
2655
                                    if (is_int($rule->data) && -1 == $rule->data) {
2656
                                        break;
2657
                                    }
2658
                                    // Where will be injected in the parseConditions()
2659
                                    //$where = $this->get_where_clause($rule->field, $rule->op, $rule->data, 'OR');
2660
                                    //$conditionArray[] = " ( $where ) ";
2661
                                    $extraFields[] = [
2662
                                        'field' => $ruleField,
2663
                                        'id' => $field_option['id'],
2664
                                        'data' => $rule->data,
2665
                                    ];
2666
                                }
2667
                                break;
2668
                            default:
2669
                                if (isset($rule->data)) {
2670
                                    if (is_int($rule->data) && -1 == $rule->data) {
2671
                                        break;
2672
                                    }
2673
                                    $where = $this->get_where_clause($rule->field, $rule->op, $rule->data, 'OR');
2674
                                    $conditionArray[] = " ( $where ) ";
2675
                                    $extraFields[] = [
2676
                                        'field' => $ruleField,
2677
                                        'id' => $field_option['id'],
2678
                                        'data' => $rule->data,
2679
                                    ];
2680
                                }
2681
                                break;
2682
                        }
2683
                    } else {
2684
                        $my_field = str_replace('_second', '', $rule->field);
2685
                        $original_field = str_replace($stringToSearch, '', $my_field);
2686
                        $field_option = $this->get_handler_field_info_by_field_variable($original_field);
2687
                        $extraFields[] = [
2688
                            'field' => $ruleField,
2689
                            'id' => $field_option['id'],
2690
                        ];
2691
                    }
2692
                }
2693
            }
2694
        }
2695
2696
        return ['extra_fields' => $extraFields, 'condition_array' => $conditionArray];
2697
    }
2698
2699
    /**
2700
     * @param $col
2701
     * @param $oper
2702
     * @param $val
2703
     * @param $conditionBetweenOptions
2704
     *
2705
     * @return string
2706
     */
2707
    public function get_where_clause($col, $oper, $val, $conditionBetweenOptions = 'OR')
2708
    {
2709
        $col = Database::escapeField($col);
2710
2711
        if (empty($col)) {
2712
            return '';
2713
        }
2714
2715
        $conditionBetweenOptions = in_array($conditionBetweenOptions, ['OR', 'AND']) ? $conditionBetweenOptions : 'OR';
2716
        if ('bw' === $oper || 'bn' === $oper) {
2717
            $val .= '%';
2718
        }
2719
        if ('ew' === $oper || 'en' === $oper) {
2720
            $val = '%'.$val;
2721
        }
2722
        if ('cn' === $oper || 'nc' === $oper || 'in' === $oper || 'ni' === $oper) {
2723
            if (is_array($val)) {
2724
                $result = '"%'.implode(';', $val).'%"';
2725
                foreach ($val as $item) {
2726
                    $item = trim($item);
2727
                    $result .= ' '.$conditionBetweenOptions.' '.$col.' LIKE "%'.$item.'%"';
2728
                }
2729
                $val = $result;
2730
2731
                return " $col {$this->ops[$oper]} $val ";
2732
            } else {
2733
                if (is_string($val)) {
2734
                    $val = '%'.$val.'%';
2735
                } else {
2736
                    $val = '';
2737
                }
2738
            }
2739
        }
2740
        $val = \Database::escape_string($val);
2741
2742
        return " $col {$this->ops[$oper]} '$val' ";
2743
    }
2744
2745
    /**
2746
     * @param array  $options
2747
     * @param string $alias
2748
     *
2749
     * @return array
2750
     */
2751
    public function parseConditions($options, $alias = 's')
2752
    {
2753
        $inject_extra_fields = null;
2754
        $extraFieldOption = new ExtraFieldOption($this->type);
2755
        $double_fields = [];
2756
2757
        if (isset($options['extra'])) {
2758
            $extra_fields = $options['extra'];
2759
            if (!empty($extra_fields)) {
2760
                $counter = 1;
2761
                $extra_field_obj = new ExtraField($this->type);
2762
                foreach ($extra_fields as &$extra) {
2763
                    if (!isset($extra['id'])) {
2764
                        continue;
2765
                    }
2766
                    $extra_field_info = $extra_field_obj->get($extra['id']);
2767
                    if (empty($extra_field_info)) {
2768
                        continue;
2769
                    }
2770
                    $extra['extra_field_info'] = $extra_field_info;
2771
2772
                    switch ($extra_field_info['field_type']) {
2773
                        case self::FIELD_TYPE_SELECT:
2774
                        case self::FIELD_TYPE_DOUBLE_SELECT:
2775
                            $inject_extra_fields .= " fvo$counter.display_text as {$extra['field']}, ";
2776
                            break;
2777
                        case self::FIELD_TYPE_TAG:
2778
                            // If using OR
2779
                            // If using AND
2780
                            $newCounter = 1;
2781
                            $fields = [];
2782
                            $tagAlias = $extra['field'];
2783
                            foreach ($extra['data'] as $data) {
2784
                                $fields[] = "tag$counter$newCounter.tag";
2785
                                $newCounter++;
2786
                            }
2787
2788
                            if (!empty($fields)) {
2789
                                $tags = implode(' , " ", ', $fields);
2790
                                $inject_extra_fields .= " CONCAT($tags) as $tagAlias, ";
2791
                            }
2792
                            break;
2793
                        default:
2794
                            $inject_extra_fields .= " fv$counter.value as {$extra['field']}, ";
2795
                            break;
2796
                    }
2797
2798
                    if (isset($extra_fields_info[$extra['id']])) {
2799
                        $info = $extra_fields_info[$extra['id']];
2800
                    } else {
2801
                        $info = $this->get($extra['id']);
2802
                        $extra_fields_info[$extra['id']] = $info;
2803
                    }
2804
                    if (isset($info['field_type']) && self::FIELD_TYPE_DOUBLE_SELECT == $info['field_type']) {
2805
                        $double_fields[$info['id']] = $info;
2806
                    }
2807
                    $counter++;
2808
                }
2809
            }
2810
        }
2811
2812
        $options_by_double = [];
2813
        foreach ($double_fields as $double) {
2814
            $my_options = $extraFieldOption->get_field_options_by_field($double['id'], true);
2815
            $options_by_double['extra_'.$double['variable']] = $my_options;
2816
        }
2817
2818
        $field_value_to_join = [];
2819
        //filter can be all/any = and/or
2820
        $inject_joins = null;
2821
        $inject_where = null;
2822
        $where = null;
2823
2824
        //if (!empty($options['where'])) {
2825
        if (!empty($options['extra']) && !empty($extra_fields)) {
2826
            // Removing double 1=1
2827
            if (empty($options['where'])) {
2828
                $options['where'] = ' 1 = 1 ';
2829
            }
2830
            $options['where'] = str_replace(' 1 = 1  AND', '', $options['where']);
2831
            // Always OR
2832
            $counter = 1;
2833
            foreach ($extra_fields as $extra_info) {
2834
                $extra_field_info = $extra_info['extra_field_info'];
2835
                $inject_joins .= " INNER JOIN $this->table_field_values fv$counter
2836
                                       ON ($alias.".$this->primaryKey." = fv$counter.".$this->handler_id.') ';
2837
                // Add options
2838
                switch ($extra_field_info['field_type']) {
2839
                        case self::FIELD_TYPE_SELECT:
2840
                        case self::FIELD_TYPE_DOUBLE_SELECT:
2841
                            $options['where'] = str_replace(
2842
                                $extra_info['field'],
2843
                                'fv'.$counter.'.field_id = '.$extra_info['id'].' AND fvo'.$counter.'.option_value',
2844
                                $options['where']
2845
                            );
2846
                            $inject_joins .= "
2847
                                 INNER JOIN $this->table_field_options fvo$counter
2848
                                 ON (
2849
                                    fv$counter.field_id = fvo$counter.field_id AND
2850
                                    fv$counter.value = fvo$counter.option_value
2851
                                 )
2852
                                ";
2853
                            break;
2854
                        case self::FIELD_TYPE_TAG:
2855
                            $newCounter = 1;
2856
                            if (isset($extra_info['data']) && !empty($extra_info['data'])) {
2857
                                $whereTag = [];
2858
                                foreach ($extra_info['data'] as $data) {
2859
                                    $data = Database::escape_string($data);
2860
                                    $key = $counter.$newCounter;
2861
                                    $whereTag[] = ' tag'.$key.'.tag LIKE "%'.$data.'%" ';
2862
                                    $inject_joins .= "
2863
                                    INNER JOIN $this->table_field_rel_tag tag_rel$key
2864
                                    ON (
2865
                                        tag_rel$key.field_id = ".$extra_info['id']." AND
2866
                                        tag_rel$key.item_id = $alias.".$this->primaryKey."
2867
                                    )
2868
                                    INNER JOIN $this->table_field_tag tag$key
2869
                                    ON (tag$key.id = tag_rel$key.tag_id)
2870
                                ";
2871
                                    $newCounter++;
2872
                                }
2873
                                if (!empty($whereTag)) {
2874
                                    $options['where'] .= ' AND  ('.implode(' AND ', $whereTag).') ';
2875
                                }
2876
                            }
2877
                            break;
2878
                        default:
2879
                            // text, textarea, etc
2880
                            $options['where'] = str_replace(
2881
                                $extra_info['field'],
2882
                                'fv'.$counter.'.field_id = '.$extra_info['id'].' AND fv'.$counter.'.value',
2883
                                $options['where']
2884
                            );
2885
                            break;
2886
                    }
2887
                $field_value_to_join[] = " fv$counter.$this->handler_id ";
2888
                $counter++;
2889
            }
2890
        }
2891
2892
        if (!empty($options['where'])) {
2893
            $where .= ' AND '.$options['where'];
2894
        }
2895
2896
        $order = '';
2897
        if (!empty($options['order'])) {
2898
            $order = " ORDER BY ".$options['order']." ";
2899
        }
2900
        $limit = '';
2901
        if (!empty($options['limit'])) {
2902
            $limit = ' LIMIT '.$options['limit'];
2903
        }
2904
2905
        return [
2906
            'order' => $order,
2907
            'limit' => $limit,
2908
            'where' => $where,
2909
            'inject_where' => $inject_where,
2910
            'inject_joins' => $inject_joins,
2911
            'field_value_to_join' => $field_value_to_join,
2912
            'inject_extra_fields' => $inject_extra_fields,
2913
        ];
2914
    }
2915
2916
    /**
2917
     * Get the extra fields and their formatted values.
2918
     *
2919
     * @param int|string $itemId   The item ID (It could be a session_id, course_id or user_id)
2920
     * @param bool       $filter
2921
     * @param array      $onlyShow (list of extra fields variables to show)
2922
     *
2923
     * @return array The extra fields data
2924
     */
2925
    public function getDataAndFormattedValues($itemId, $filter = false, $onlyShow = [])
2926
    {
2927
        $valuesData = [];
2928
        $fields = $this->get_all();
2929
        $em = Database::getManager();
2930
2931
        $repoTag = $em->getRepository('ChamiloCoreBundle:ExtraFieldRelTag');
2932
2933
        foreach ($fields as $field) {
2934
            if ('1' != $field['visible_to_self']) {
2935
                continue;
2936
            }
2937
2938
            if ($filter && $field['filter'] != 1) {
2939
                continue;
2940
            }
2941
2942
            if (!empty($onlyShow) && !in_array($field['variable'], $onlyShow)) {
2943
                continue;
2944
            }
2945
2946
            $valueAsArray = [];
2947
            $fieldValue = new ExtraFieldValue($this->type);
2948
            $valueData = $fieldValue->get_values_by_handler_and_field_id(
2949
                $itemId,
2950
                $field['id'],
2951
                true
2952
            );
2953
            if (ExtraField::FIELD_TYPE_TAG == $field['field_type']) {
2954
                $tags = $repoTag->findBy(['fieldId' => $field['id'], 'itemId' => $itemId]);
2955
                if ($tags) {
2956
                    /** @var ExtraFieldRelTag $tag */
2957
                    $data = [];
2958
                    foreach ($tags as $extraFieldTag) {
2959
                        /** @var Tag $tag */
2960
                        $tag = $em->find('ChamiloCoreBundle:Tag', $extraFieldTag->getTagId());
2961
                        $data[] = $tag->getTag();
2962
                    }
2963
                    $valueData = implode(', ', $data);
2964
                    $valueAsArray = $data;
2965
                }
2966
            }
2967
2968
            if (!$valueData) {
2969
                continue;
2970
            }
2971
            $displayedValue = get_lang('None');
2972
2973
            switch ($field['field_type']) {
2974
                case self::FIELD_TYPE_CHECKBOX:
2975
                    if (false !== $valueData && '1' == $valueData['value']) {
2976
                        $displayedValue = get_lang('Yes');
2977
                    } else {
2978
                        $displayedValue = get_lang('No');
2979
                    }
2980
                    break;
2981
                case self::FIELD_TYPE_DATE:
2982
                    if (false !== $valueData && !empty($valueData['value'])) {
2983
                        $displayedValue = api_format_date($valueData['value'], DATE_FORMAT_LONG_NO_DAY);
2984
                    }
2985
                    break;
2986
                case self::FIELD_TYPE_TAG:
2987
                    if (!empty($valueData)) {
2988
                        $displayedValue = $valueData;
2989
                    }
2990
                    break;
2991
                case self::FIELD_TYPE_FILE_IMAGE:
2992
                    if (false === $valueData || empty($valueData['value'])) {
2993
                        break;
2994
                    }
2995
2996
                    if (!file_exists(api_get_path(SYS_UPLOAD_PATH).$valueData['value'])) {
2997
                        break;
2998
                    }
2999
3000
                    $image = Display::img(
3001
                        api_get_path(WEB_UPLOAD_PATH).$valueData['value'],
3002
                        $field['display_text'],
3003
                        ['width' => '300']
3004
                    );
3005
3006
                    $displayedValue = Display::url(
3007
                        $image,
3008
                        api_get_path(WEB_UPLOAD_PATH).$valueData['value'],
3009
                        ['target' => '_blank']
3010
                    );
3011
                    break;
3012
                case self::FIELD_TYPE_FILE:
3013
                    if (false === $valueData || empty($valueData['value'])) {
3014
                        break;
3015
                    }
3016
3017
                    if (!file_exists(api_get_path(SYS_UPLOAD_PATH).$valueData['value'])) {
3018
                        break;
3019
                    }
3020
3021
                    $displayedValue = Display::url(
3022
                        get_lang('Download'),
3023
                        api_get_path(WEB_UPLOAD_PATH).$valueData['value'],
3024
                        [
3025
                            'title' => $field['display_text'],
3026
                            'target' => '_blank',
3027
                            'class' => 'download_extra_field',
3028
                        ]
3029
                    );
3030
                    break;
3031
                default:
3032
                    $displayedValue = $valueData['value'];
3033
                    break;
3034
            }
3035
3036
            $valuesData[] = [
3037
                'variable' => $field['variable'],
3038
                'text' => $field['display_text'],
3039
                'value' => $displayedValue,
3040
                'value_as_array' => $valueAsArray,
3041
            ];
3042
        }
3043
3044
        return $valuesData;
3045
    }
3046
3047
    /**
3048
     * @param int    $fieldId
3049
     * @param string $tag
3050
     *
3051
     * @return array
3052
     */
3053
    public function getAllUserPerTag($fieldId, $tag)
3054
    {
3055
        $tagRelUserTable = Database::get_main_table(TABLE_MAIN_USER_REL_TAG);
3056
        $tag = Database::escape_string($tag);
3057
        $fieldId = (int) $fieldId;
3058
3059
        $sql = "SELECT user_id
3060
                FROM {$this->table_field_tag} f INNER JOIN $tagRelUserTable ft
3061
                ON tag_id = f.id
3062
                WHERE tag = '$tag' AND f.field_id = $fieldId;
3063
        ";
3064
3065
        $result = Database::query($sql);
3066
3067
        return Database::store_result($result, 'ASSOC');
3068
    }
3069
3070
    /**
3071
     * @param int $fieldId
3072
     * @param int $tagId
3073
     *
3074
     * @return array
3075
     */
3076
    public function getAllSkillPerTag($fieldId, $tagId)
3077
    {
3078
        $skillTable = Database::get_main_table(TABLE_MAIN_SKILL);
3079
        $tagRelExtraTable = Database::get_main_table(TABLE_MAIN_EXTRA_FIELD_REL_TAG);
3080
        $fieldId = (int) $fieldId;
3081
        $tagId = (int) $tagId;
3082
3083
        $sql = "SELECT s.id
3084
                FROM $skillTable s INNER JOIN $tagRelExtraTable t
3085
                ON t.item_id = s.id
3086
                WHERE tag_id = $tagId AND t.field_id = $fieldId;
3087
        ";
3088
3089
        $result = Database::query($sql);
3090
        $result = Database::store_result($result, 'ASSOC');
3091
3092
        $skillList = [];
3093
        foreach ($result as $index => $value) {
3094
            $skillList[$value['id']] = $value['id'];
3095
        }
3096
3097
        return $skillList;
3098
    }
3099
3100
    /**
3101
     * @param string $from
3102
     * @param string $search
3103
     * @param array  $options
3104
     *
3105
     * @return array
3106
     */
3107
    public function searchOptionsFromTags($from, $search, $options)
3108
    {
3109
        $extraFieldInfo = $this->get_handler_field_info_by_field_variable(
3110
            str_replace('extra_', '', $from)
3111
        );
3112
        $extraFieldInfoTag = $this->get_handler_field_info_by_field_variable(
3113
            str_replace('extra_', '', $search)
3114
        );
3115
3116
        if (empty($extraFieldInfo) || empty($extraFieldInfoTag)) {
3117
            return [];
3118
        }
3119
3120
        $id = $extraFieldInfo['id'];
3121
        $tagId = $extraFieldInfoTag['id'];
3122
3123
        $table = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
3124
        $tagRelExtraTable = Database::get_main_table(TABLE_MAIN_EXTRA_FIELD_REL_TAG);
3125
        $tagTable = Database::get_main_table(TABLE_MAIN_TAG);
3126
        $optionsTable = Database::get_main_table(TABLE_EXTRA_FIELD_OPTIONS);
3127
3128
        $cleanOptions = [];
3129
        foreach ($options as $option) {
3130
            $cleanOptions[] = Database::escape_string($option);
3131
        }
3132
        $cleanOptions = array_filter($cleanOptions);
3133
3134
        if (empty($cleanOptions)) {
3135
            return [];
3136
        }
3137
3138
        $value = implode("','", $cleanOptions);
3139
3140
        $sql = "SELECT DISTINCT t.*, v.value, o.display_text
3141
                FROM $tagRelExtraTable te
3142
                INNER JOIN $tagTable t
3143
                ON (t.id = te.tag_id AND te.field_id = t.field_id AND te.field_id = $tagId)
3144
                INNER JOIN $table v
3145
                ON (te.item_id = v.item_id AND v.field_id = $id)
3146
                INNER JOIN $optionsTable o
3147
                ON (o.option_value = v.value)
3148
                WHERE v.value IN ('".$value."')
3149
                ORDER BY o.option_order, t.tag
3150
               ";
3151
3152
        $result = Database::query($sql);
3153
        $result = Database::store_result($result);
3154
3155
        return $result;
3156
    }
3157
3158
    /**
3159
     * @param \FormValidator $form
3160
     * @param int            $defaultValueId
3161
     * @param bool           $freezeElement
3162
     */
3163
    private function addSelectElement(FormValidator $form, array $fieldDetails, $defaultValueId, $freezeElement = false)
3164
    {
3165
        $get_lang_variables = false;
3166
        if (in_array(
3167
            $fieldDetails['variable'],
3168
            ['mail_notify_message', 'mail_notify_invitation', 'mail_notify_group_message']
3169
        )) {
3170
            $get_lang_variables = true;
3171
        }
3172
3173
        // Get extra field workflow
3174
        $addOptions = [];
3175
        $optionsExists = false;
3176
        $options = [];
3177
3178
        $optionList = [];
3179
        if (!empty($fieldDetails['options'])) {
3180
            foreach ($fieldDetails['options'] as $option_details) {
3181
                $optionList[$option_details['id']] = $option_details;
3182
                if ($get_lang_variables) {
3183
                    $options[$option_details['option_value']] = $option_details['display_text'];
3184
                } else {
3185
                    if ($optionsExists) {
3186
                        // Adding always the default value
3187
                        if ($option_details['id'] == $defaultValueId) {
3188
                            $options[$option_details['option_value']] = $option_details['display_text'];
3189
                        } else {
3190
                            if (isset($addOptions) && !empty($addOptions)) {
3191
                                // Parsing filters
3192
                                if (in_array($option_details['id'], $addOptions)) {
3193
                                    $options[$option_details['option_value']] = $option_details['display_text'];
3194
                                }
3195
                            }
3196
                        }
3197
                    } else {
3198
                        // Normal behaviour
3199
                        $options[$option_details['option_value']] = $option_details['display_text'];
3200
                    }
3201
                }
3202
            }
3203
3204
            // Setting priority message
3205
            if (isset($optionList[$defaultValueId])
3206
                && isset($optionList[$defaultValueId]['priority'])
3207
            ) {
3208
                if (!empty($optionList[$defaultValueId]['priority'])) {
3209
                    $priorityId = $optionList[$defaultValueId]['priority'];
3210
                    $option = new ExtraFieldOption($this->type);
3211
                    $messageType = $option->getPriorityMessageType($priorityId);
3212
                    $form->addElement(
3213
                        'label',
3214
                        null,
3215
                        Display::return_message(
3216
                            $optionList[$defaultValueId]['priority_message'],
3217
                            $messageType
3218
                        )
3219
                    );
3220
                }
3221
            }
3222
        }
3223
3224
        /** @var \HTML_QuickForm_select $slct */
3225
        $slct = $form->addElement(
3226
            'select',
3227
            'extra_'.$fieldDetails['variable'],
3228
            $fieldDetails['display_text'],
3229
            [],
3230
            ['id' => 'extra_'.$fieldDetails['variable']]
3231
        );
3232
3233
        if (empty($defaultValueId)) {
3234
            $slct->addOption(get_lang('SelectAnOption'), '');
3235
        }
3236
3237
        foreach ($options as $value => $text) {
3238
            if (empty($value)) {
3239
                $slct->addOption($text, $value);
3240
                continue;
3241
            }
3242
3243
            $valueParts = explode('#', $text);
3244
            $dataValue = count($valueParts) > 1 ? array_shift($valueParts) : '';
3245
3246
            $slct->addOption(implode('', $valueParts), $value, ['data-value' => $dataValue]);
3247
        }
3248
3249
        if ($freezeElement) {
3250
            $form->freeze('extra_'.$fieldDetails['variable']);
3251
        }
3252
    }
3253
3254
    /**
3255
     * @param \FormValidator $form
3256
     * @param array          $fieldDetails
3257
     * @param array          $extraData
3258
     * @param bool           $freezeElement
3259
     *
3260
     * @return string JavaScript code
3261
     */
3262
    private function addDoubleSelectElement(FormValidator $form, $fieldDetails, $extraData, $freezeElement = false)
3263
    {
3264
        $firstSelectId = 'first_extra_'.$fieldDetails['variable'];
3265
        $secondSelectId = 'second_extra_'.$fieldDetails['variable'];
3266
3267
        $jqueryReadyContent = "
3268
            $('#$firstSelectId').on('change', function() {
3269
                var id = $(this).val();
3270
3271
                if (!id) {
3272
                    $('#$secondSelectId').empty().selectpicker('refresh');
3273
3274
                    return;
3275
                }
3276
3277
                $.getJSON(_p.web_ajax + 'extra_field.ajax.php?1=1&a=get_second_select_options', {
3278
                    'type': '{$this->type}',
3279
                    'field_id': {$fieldDetails['id']},
3280
                    'option_value_id': id
3281
                })
3282
                    .done(function(data) {
3283
                        $('#$secondSelectId').empty();
3284
                        $.each(data, function(index, value) {
3285
                            $('#second_extra_{$fieldDetails['variable']}').append(
3286
                                $('<option>', {value: index, text: value})
3287
                            );
3288
                        });
3289
                        $('#$secondSelectId').selectpicker('refresh');
3290
                    });
3291
            });
3292
        ";
3293
3294
        $firstId = null;
3295
        if (!empty($extraData)) {
3296
            if (isset($extraData['extra_'.$fieldDetails['variable']])) {
3297
                $firstId = $extraData['extra_'.$fieldDetails['variable']]['extra_'.$fieldDetails['variable']];
3298
            }
3299
        }
3300
3301
        $options = $this->extra_field_double_select_convert_array_to_ordered_array($fieldDetails['options']);
3302
        $values = ['' => get_lang('Select')];
3303
3304
        $second_values = [];
3305
        if (!empty($options)) {
3306
            foreach ($options as $option) {
3307
                foreach ($option as $sub_option) {
3308
                    if ('0' == $sub_option['option_value']) {
3309
                        $values[$sub_option['id']] = $sub_option['display_text'];
3310
3311
                        continue;
3312
                    }
3313
3314
                    if ($firstId === $sub_option['option_value']) {
3315
                        $second_values[$sub_option['id']] = $sub_option['display_text'];
3316
                    }
3317
                }
3318
            }
3319
        }
3320
3321
        $form
3322
            ->defaultRenderer()
3323
            ->setGroupElementTemplate('<p>{element}</p>', 'extra_'.$fieldDetails['variable']);
3324
        $group = [];
3325
        $group[] = $form->createElement(
3326
            'select',
3327
            'extra_'.$fieldDetails['variable'],
3328
            null,
3329
            $values,
3330
            ['id' => $firstSelectId]
3331
        );
3332
        $group[] = $form->createElement(
3333
            'select',
3334
            'extra_'.$fieldDetails['variable'].'_second',
3335
            null,
3336
            $second_values,
3337
            ['id' => $secondSelectId]
3338
        );
3339
        $form->addGroup(
3340
            $group,
3341
            'extra_'.$fieldDetails['variable'],
3342
            $fieldDetails['display_text']
3343
        );
3344
3345
        if ($freezeElement) {
3346
            $form->freeze('extra_'.$fieldDetails['variable']);
3347
        }
3348
3349
        return $jqueryReadyContent;
3350
    }
3351
3352
    /**
3353
     * @param \FormValidator $form
3354
     * @param bool           $freezeElement Optional
3355
     *
3356
     * @return string JavaScript code
3357
     */
3358
    private function addSelectWithTextFieldElement(
3359
        FormValidator $form,
3360
        array $fieldDetails,
3361
        $freezeElement = false
3362
    ) {
3363
        $firstSelectId = 'slct_extra_'.$fieldDetails['variable'];
3364
        $txtSelectId = 'txt_extra_'.$fieldDetails['variable'];
3365
3366
        $jqueryReadyContent = "
3367
            $('#$firstSelectId').on('change', function() {
3368
                var id = $(this).val();
3369
3370
                if (!id) {
3371
                    $('#$txtSelectId').val('');
3372
                }
3373
            });
3374
        ";
3375
3376
        $options = $this->extra_field_double_select_convert_array_to_ordered_array($fieldDetails['options']);
3377
        $values = ['' => get_lang('Select')];
3378
3379
        if (!empty($options)) {
3380
            foreach ($options as $option) {
3381
                foreach ($option as $sub_option) {
3382
                    if ('0' == $sub_option['option_value']) {
3383
                        continue;
3384
                    }
3385
3386
                    $values[$sub_option['id']] = $sub_option['display_text'];
3387
                }
3388
            }
3389
        }
3390
3391
        $form
3392
            ->defaultRenderer()
3393
            ->setGroupElementTemplate('<p>{element}</p>', 'extra_'.$fieldDetails['variable']);
3394
        $group = [];
3395
        $group[] = $form->createElement(
3396
            'select',
3397
            'extra_'.$fieldDetails['variable'],
3398
            null,
3399
            $values,
3400
            ['id' => $firstSelectId]
3401
        );
3402
        $group[] = $form->createElement(
3403
            'text',
3404
            'extra_'.$fieldDetails['variable'].'_second',
3405
            null,
3406
            ['id' => $txtSelectId]
3407
        );
3408
        $form->addGroup(
3409
            $group,
3410
            'extra_'.$fieldDetails['variable'],
3411
            $fieldDetails['display_text']
3412
        );
3413
3414
        if ($freezeElement) {
3415
            $form->freeze('extra_'.$fieldDetails['variable']);
3416
        }
3417
3418
        return $jqueryReadyContent;
3419
    }
3420
3421
    /**
3422
     * @param \FormValidator $form
3423
     * @param bool           $freezeElement
3424
     *
3425
     * @return string
3426
     */
3427
    private function addTripleSelectElement(
3428
        FormValidator $form,
3429
        array $fieldDetails,
3430
        array $extraData,
3431
        $freezeElement
3432
    ) {
3433
        $variable = $fieldDetails['variable'];
3434
        $id = $fieldDetails['id'];
3435
        $slctFirstId = "first_extra$variable";
3436
        $slctSecondId = "second_extra$variable";
3437
        $slctThirdId = "third_extra$variable";
3438
        $langSelect = get_lang('Select');
3439
3440
        $js = "
3441
            (function () {
3442
                var slctFirst = $('#$slctFirstId'),
3443
                    slctSecond = $('#$slctSecondId'),
3444
                    slctThird = $('#$slctThirdId');
3445
3446
                slctFirst.on('change', function () {
3447
                    slctSecond.empty().selectpicker('refresh');
3448
                    slctThird.empty().selectpicker('refresh');
3449
3450
                    var level = $(this).val();
3451
3452
                    if (!level) {
3453
                        return;
3454
                    }
3455
3456
                    $.getJSON(_p.web_ajax + 'extra_field.ajax.php', {
3457
                        'a': 'get_second_select_options',
3458
                        'type': '$this->type',
3459
                        'field_id': $id,
3460
                        'option_value_id': level
3461
                    })
3462
                        .done(function (data) {
3463
                            slctSecond.append(
3464
                                $('<option>', {value: '', text: '$langSelect'})
3465
                            );
3466
3467
                            $.each(data, function (index, value) {
3468
                                var valueParts = value.split('#'),
3469
                                    dataValue = valueParts.length > 1 ? valueParts.shift() : '';
3470
3471
                                slctSecond.append(
3472
                                    $('<option>', {value: index, text: valueParts.join(''), 'data-value': dataValue})
3473
                                );
3474
                            });
3475
3476
                            slctSecond.selectpicker('refresh');
3477
                        });
3478
                });
3479
                slctSecond.on('change', function () {
3480
                    slctThird.empty().selectpicker('refresh');
3481
3482
                    var level = $(this).val();
3483
3484
                    if (!level) {
3485
                        return;
3486
                    }
3487
3488
                    $.getJSON(_p.web_ajax + 'extra_field.ajax.php', {
3489
                        'a': 'get_second_select_options',
3490
                        'type': '$this->type',
3491
                        'field_id': $id,
3492
                        'option_value_id': level
3493
                    })
3494
                        .done(function (data) {
3495
                            slctThird.append(
3496
                                $('<option>', {value: '', text: '$langSelect'})
3497
                            );
3498
3499
                            $.each(data, function (index, value) {
3500
                                var valueParts = value.split('#'),
3501
                                    dataValue = valueParts.length > 1 ? valueParts.shift() : '';
3502
3503
                                slctThird.append(
3504
                                    $('<option>', {value: index, text: valueParts.join(''), 'data-value': dataValue})
3505
                                );
3506
                            });
3507
3508
                            slctThird.selectpicker('refresh');
3509
                        });
3510
                });
3511
            })();
3512
        ";
3513
3514
        $firstId = isset($extraData["extra_$variable"]["extra_$variable"])
3515
            ? $extraData["extra_$variable"]["extra_$variable"]
3516
            : '';
3517
        $secondId = isset($extraData["extra_$variable"]["extra_{$variable}_second"])
3518
            ? $extraData["extra_$variable"]["extra_{$variable}_second"]
3519
            : '';
3520
3521
        $options = $this->tripleSelectConvertArrayToOrderedArray($fieldDetails['options']);
3522
        $values1 = ['' => $langSelect];
3523
        $values2 = ['' => $langSelect];
3524
        $values3 = ['' => $langSelect];
3525
        $level1 = $this->getOptionsFromTripleSelect($options['level1'], 0);
3526
        $level2 = $this->getOptionsFromTripleSelect($options['level2'], $firstId);
3527
        $level3 = $this->getOptionsFromTripleSelect($options['level3'], $secondId);
3528
        /** @var \HTML_QuickForm_select $slctFirst */
3529
        $slctFirst = $form->createElement('select', "extra_$variable", null, $values1, ['id' => $slctFirstId]);
3530
        /** @var \HTML_QuickForm_select $slctFirst */
3531
        $slctSecond = $form->createElement(
3532
            'select',
3533
            "extra_{$variable}_second",
3534
            null,
3535
            $values2,
3536
            ['id' => $slctSecondId]
3537
        );
3538
        /** @var \HTML_QuickForm_select $slctFirst */
3539
        $slctThird = $form->createElement('select', "extra_{$variable}_third", null, $values3, ['id' => $slctThirdId]);
3540
3541
        foreach ($level1 as $item1) {
3542
            $valueParts = explode('#', $item1['display_text']);
3543
            $dataValue = count($valueParts) > 1 ? array_shift($valueParts) : '';
3544
            $slctFirst->addOption(implode('', $valueParts), $item1['id'], ['data-value' => $dataValue]);
3545
        }
3546
3547
        foreach ($level2 as $item2) {
3548
            $valueParts = explode('#', $item2['display_text']);
3549
            $dataValue = count($valueParts) > 1 ? array_shift($valueParts) : '';
3550
            $slctSecond->addOption(implode('', $valueParts), $item2['id'], ['data-value' => $dataValue]);
3551
        }
3552
3553
        foreach ($level3 as $item3) {
3554
            $valueParts = explode('#', $item3['display_text']);
3555
            $dataValue = count($valueParts) > 1 ? array_shift($valueParts) : '';
3556
            $slctThird->addOption(implode('', $valueParts), $item3['id'], ['data-value' => $dataValue]);
3557
        }
3558
3559
        $form
3560
            ->defaultRenderer()
3561
            ->setGroupElementTemplate('<p>{element}</p>', "extra_$variable");
3562
        $form->addGroup([$slctFirst, $slctSecond, $slctThird], "extra_$variable", $fieldDetails['display_text']);
3563
3564
        if ($freezeElement) {
3565
            $form->freeze('extra_'.$fieldDetails['variable']);
3566
        }
3567
3568
        return $js;
3569
    }
3570
3571
    /**
3572
     * @param int $parentId
3573
     *
3574
     * @return array
3575
     */
3576
    private static function getOptionsFromTripleSelect(array $options, $parentId)
3577
    {
3578
        return array_filter(
3579
            $options,
3580
            function ($option) use ($parentId) {
3581
                return $option['option_value'] == $parentId;
3582
            }
3583
        );
3584
    }
3585
}
3586