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

ExtraField::set_extra_fields_in_form()   F

Complexity

Conditions 127
Paths 3

Size

Total Lines 786
Code Lines 503

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 127
eloc 503
nc 3
nop 16
dl 0
loc 786
rs 3.3333
c 0
b 0
f 0

How to fix   Long Method    Complexity    Many Parameters   

Long Method

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

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

Commonly applied refactorings include:

Many Parameters

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

There are several approaches to avoid long parameter lists:

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

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

1232
                        $jquery_ready_content .= self::/** @scrutinizer ignore-call */ addDoubleSelectElement(
Loading history...
1233
                            $form,
1234
                            $field_details,
1235
                            $extraData,
1236
                            $freezeElement
1237
                        );
1238
                        break;
1239
                    case self::FIELD_TYPE_DIVIDER:
1240
                        $form->addHtml('
1241
                            <div class="form-group ">
1242
                                <div class="col-sm-12">
1243
                                    <div class="panel-separator">
1244
                                       <h4 id="'.$variable.'" class="form-separator">'
1245
                                            .$field_details['display_text'].'
1246
                                       </h4>
1247
                                    </div>
1248
                                </div>
1249
                            </div>
1250
                        ');
1251
                        break;
1252
                    case self::FIELD_TYPE_TAG:
1253
                        $field_id = $field_details['id'];
1254
                        $separateValue = 0;
1255
                        if (isset($separateExtraMultipleSelect[$variable])) {
1256
                            $separateValue = $separateExtraMultipleSelect[$variable];
1257
                        }
1258
1259
                        $selectedOptions = [];
1260
                        if ($separateValue > 0) {
1261
                            $em = Database::getManager();
1262
                            $fieldTags = $em
1263
                                ->getRepository(ExtraFieldRelTag::class)
1264
                                ->findBy(
1265
                                    [
1266
                                        'fieldId' => $field_id,
1267
                                        'itemId' => $itemId,
1268
                                    ]
1269
                                );
1270
                            // ofaj.
1271
                            for ($i = 0; $i < $separateValue; $i++) {
1272
                                $tagsSelect = $form->addSelect(
1273
                                    'extra_'.$variable.'['.$i.']',
1274
                                    $customLabelsExtraMultipleSelect[$variable][$i], //$field_details['display_text'],
1275
                                    null,
1276
                                    ['id' => 'extra_'.$variable.'_'.$i]
1277
                                );
1278
1279
                                if ($addEmptyOptionSelects) {
1280
                                    $tagsSelect->addOption(
1281
                                        '',
1282
                                        ''
1283
                                    );
1284
                                }
1285
1286
                                foreach ($fieldTags as $fieldTag) {
1287
                                    $tag = $em->find(Tag::class, $fieldTag->getTagId());
1288
1289
                                    if (empty($tag)) {
1290
                                        continue;
1291
                                    }
1292
1293
                                    $tagsSelect->addOption(
1294
                                        $tag->getTag(),
1295
                                        $tag->getTag()
1296
                                    );
1297
                                }
1298
                            }
1299
                        } else {
1300
                            $tagsSelect = $form->addSelect(
1301
                                "extra_{$variable}",
1302
                                $field_details['display_text'],
1303
                                [],
1304
                                ['style' => 'width: 100%;']
1305
                            );
1306
1307
                            if (false === $useTagAsSelect) {
1308
                                $tagsSelect->setAttribute('class', null);
1309
                            }
1310
1311
                            $tagsSelect->setAttribute(
1312
                                'id',
1313
                                "extra_{$variable}"
1314
                            );
1315
                            $tagsSelect->setMultiple(true);
1316
1317
                            $selectedOptions = [];
1318
                            if ('user' === $this->type) {
1319
                                // The magic should be here
1320
                                $user_tags = UserManager::get_user_tags(
1321
                                    $itemId,
1322
                                    $field_details['id']
1323
                                );
1324
1325
                                if (is_array($user_tags) && count($user_tags) > 0) {
1326
                                    foreach ($user_tags as $tag) {
1327
                                        if (empty($tag['tag'])) {
1328
                                            continue;
1329
                                        }
1330
                                        $tagsSelect->addOption(
1331
                                            $tag['tag'],
1332
                                            $tag['tag'],
1333
                                            [
1334
                                                'selected' => 'selected',
1335
                                                'class' => 'selected',
1336
                                            ]
1337
                                        );
1338
                                        $selectedOptions[] = $tag['tag'];
1339
                                    }
1340
                                }
1341
                                $url = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php';
1342
                            } else {
1343
                                $em = Database::getManager();
1344
                                $fieldTags = $em->getRepository(
1345
                                    ExtraFieldRelTag::class
1346
                                )
1347
                                ->findBy(
1348
                                    [
1349
                                        'fieldId' => $field_id,
1350
                                        'itemId' => $itemId,
1351
                                    ]
1352
                                );
1353
1354
                                /** @var ExtraFieldRelTag $fieldTag */
1355
                                foreach ($fieldTags as $fieldTag) {
1356
                                    /** @var Tag $tag */
1357
                                    $tag = $em->find(Tag::class, $fieldTag->getTagId());
1358
                                    if (empty($tag)) {
1359
                                        continue;
1360
                                    }
1361
                                    $tagsSelect->addOption(
1362
                                        $tag->getTag(),
1363
                                        $tag->getTag()
1364
                                    );
1365
                                    $selectedOptions[] = $tag->getTag();
1366
                                }
1367
1368
                                if (!empty($extraData) && isset($extraData['extra_'.$variable])) {
1369
                                    $data = $extraData['extra_'.$variable];
1370
                                    if (!empty($data)) {
1371
                                        foreach ($data as $option) {
1372
                                            $tagsSelect->addOption(
1373
                                                $option,
1374
                                                $option
1375
                                            );
1376
                                        }
1377
                                    }
1378
                                }
1379
1380
                                if ($useTagAsSelect) {
1381
                                    $fieldTags = $em->getRepository(ExtraFieldRelTag::class)
1382
                                        ->findBy(
1383
                                            [
1384
                                                'fieldId' => $field_id,
1385
                                            ]
1386
                                        );
1387
                                    $tagsAdded = [];
1388
                                    foreach ($fieldTags as $fieldTag) {
1389
                                        $tag = $em->find(Tag::class, $fieldTag->getTagId());
1390
1391
                                        if (empty($tag)) {
1392
                                            continue;
1393
                                        }
1394
1395
                                        $tagText = $tag->getTag();
1396
1397
                                        if (in_array($tagText, $tagsAdded)) {
1398
                                            continue;
1399
                                        }
1400
1401
                                        $tagsSelect->addOption(
1402
                                            $tag->getTag(),
1403
                                            $tag->getTag(),
1404
                                            []
1405
                                        );
1406
1407
                                        $tagsAdded[] = $tagText;
1408
                                    }
1409
                                }
1410
                                $url = api_get_path(WEB_AJAX_PATH).'extra_field.ajax.php';
1411
                            }
1412
1413
                            $form->setDefaults(
1414
                                [
1415
                                    'extra_'.$variable => $selectedOptions,
1416
                                ]
1417
                            );
1418
1419
                            if (false == $useTagAsSelect) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

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

Loading history...
1420
                                $jquery_ready_content .= "
1421
                                $('#extra_$variable').select2({
1422
                                    ajax: {
1423
                                        url: '$url?a=search_tags&field_id=$field_id&type={$this->type}',
1424
                                        processResults: function (data) {
1425
                                            return {
1426
                                                results: data.items
1427
                                            }
1428
                                        }
1429
                                    },
1430
                                    cache: false,
1431
                                    tags: true,
1432
                                    tokenSeparators: [','],
1433
                                    placeholder: '".get_lang('Start to type, then click on this bar to validate tag')."'
1434
                                });
1435
                            ";
1436
                            }
1437
                        }
1438
1439
                        break;
1440
                    case self::FIELD_TYPE_TIMEZONE:
1441
                        $form->addElement(
1442
                            'select',
1443
                            'extra_'.$variable,
1444
                            $field_details['display_text'],
1445
                            api_get_timezones(),
1446
                            ''
1447
                        );
1448
                        if ($freezeElement) {
1449
                            $form->freeze('extra_'.$variable);
1450
                        }
1451
                        break;
1452
                    case self::FIELD_TYPE_SOCIAL_PROFILE:
1453
                        // get the social network's favicon
1454
                        $extra_data_variable = isset($extraData['extra_'.$variable]) ? $extraData['extra_'.$variable] : null;
1455
                        $field_default_value = isset($field_details['field_default_value']) ? $field_details['field_default_value'] : null;
1456
                        $icon_path = UserManager::get_favicon_from_url(
1457
                            $extra_data_variable,
1458
                            $field_default_value
1459
                        );
1460
                        // special hack for hi5
1461
                        $leftpad = '1.7';
1462
                        $top = '0.4';
1463
                        $domain = parse_url($icon_path, PHP_URL_HOST);
1464
                        if ('www.hi5.com' === $domain || 'hi5.com' === $domain) {
1465
                            $leftpad = '3';
1466
                            $top = '0';
1467
                        }
1468
                        // print the input field
1469
                        $form->addElement(
1470
                            'text',
1471
                            'extra_'.$variable,
1472
                            $field_details['display_text'],
1473
                            [
1474
                                //'size' => 60,
1475
                                'size' => implode(
1476
                                    '; ',
1477
                                    [
1478
                                        "background-image: url('$icon_path')",
1479
                                        'background-repeat: no-repeat',
1480
                                        "background-position: 0.4em {$top}em",
1481
                                        "padding-left: {$leftpad}em",
1482
                                    ]
1483
                                ),
1484
                            ]
1485
                        );
1486
                        $form->applyFilter('extra_'.$variable, 'stripslashes');
1487
                        $form->applyFilter('extra_'.$variable, 'trim');
1488
                        if ($freezeElement) {
1489
                            $form->freeze('extra_'.$variable);
1490
                        }
1491
                        break;
1492
                    case self::FIELD_TYPE_MOBILE_PHONE_NUMBER:
1493
                        $form->addElement(
1494
                            'text',
1495
                            'extra_'.$variable,
1496
                            $field_details['display_text'].' ('.get_lang('Include the country dial code').')',
1497
                            ['size' => 40, 'placeholder' => '(xx)xxxxxxxxx']
1498
                        );
1499
                        $form->applyFilter('extra_'.$variable, 'stripslashes');
1500
                        $form->applyFilter('extra_'.$variable, 'trim');
1501
                        $form->applyFilter('extra_'.$variable, 'mobile_phone_number_filter');
1502
                        $form->addRule(
1503
                            'extra_'.$variable,
1504
                            get_lang('Mobile phone number is incomplete or contains invalid characters'),
1505
                            'mobile_phone_number'
1506
                        );
1507
                        if ($freezeElement) {
1508
                            $form->freeze('extra_'.$variable);
1509
                        }
1510
                        break;
1511
                    case self::FIELD_TYPE_INTEGER:
1512
                        $form->addElement(
1513
                            'number',
1514
                            'extra_'.$variable,
1515
                            $field_details['display_text'],
1516
                            ['class' => 'span1', 'step' => 1]
1517
                        );
1518
1519
                        $form->applyFilter('extra_'.$variable, 'stripslashes');
1520
                        $form->applyFilter('extra_'.$variable, 'trim');
1521
                        $form->applyFilter('extra_'.$variable, 'intval');
1522
1523
                        if ($freezeElement) {
1524
                            $form->freeze('extra_'.$variable);
1525
                        }
1526
                        break;
1527
                    case self::FIELD_TYPE_FLOAT:
1528
                        $form->addElement(
1529
                            'number',
1530
                            'extra_'.$variable,
1531
                            $field_details['display_text'],
1532
                            ['class' => 'span1', 'step' => '0.01']
1533
                        );
1534
1535
                        $form->applyFilter('extra_'.$variable, 'stripslashes');
1536
                        $form->applyFilter('extra_'.$variable, 'trim');
1537
                        $form->applyFilter('extra_'.$variable, 'floatval');
1538
1539
                        if ($freezeElement) {
1540
                            $form->freeze('extra_'.$variable);
1541
                        }
1542
                        break;
1543
                    case self::FIELD_TYPE_FILE_IMAGE:
1544
                        $fieldVariable = "extra_{$variable}";
1545
                        $fieldTexts = [
1546
                            $field_details['display_text'],
1547
                        ];
1548
1549
                        if (is_array($extraData) && array_key_exists($fieldVariable, $extraData)) {
1550
                            $assetId = $extraData[$fieldVariable];
1551
                            $assetRepo = Container::getAssetRepository();
1552
                            $asset = $assetRepo->find($assetId);
1553
                            if (null !== $asset) {
1554
                                $fieldTexts[] = Display::img(
1555
                                    $assetRepo->getAssetUrl($asset),
1556
                                    $field_details['display_text'],
1557
                                    ['width' => '300']
1558
                                );
1559
                            }
1560
                        }
1561
1562
                        if ('Image' === $fieldTexts[0]) {
1563
                            $fieldTexts[0] = get_lang($fieldTexts[0]);
1564
                        }
1565
1566
                        $form->addFile(
1567
                            $fieldVariable,
1568
                            $fieldTexts,
1569
                            ['accept' => 'image/*', 'id' => 'extra_image', 'crop_image' => 'true']
1570
                        );
1571
1572
                        $form->applyFilter('extra_'.$variable, 'stripslashes');
1573
                        $form->applyFilter('extra_'.$variable, 'trim');
1574
1575
                        $allowedPictureTypes = ['jpg', 'jpeg', 'png', 'gif'];
1576
                        $form->addRule(
1577
                            'extra_'.$variable,
1578
                            get_lang('Only PNG, JPG or GIF images allowed').' ('.implode(',', $allowedPictureTypes).')',
1579
                            'filetype',
1580
                            $allowedPictureTypes
1581
                        );
1582
1583
                        if ($freezeElement) {
1584
                            $form->freeze('extra_'.$variable);
1585
                        }
1586
                        break;
1587
                    case self::FIELD_TYPE_FILE:
1588
                        $fieldVariable = "extra_{$variable}";
1589
                        $fieldTexts = [
1590
                            $field_details['display_text'],
1591
                        ];
1592
1593
                        if (is_array($extraData) &&
1594
                            array_key_exists($fieldVariable, $extraData)
1595
                        ) {
1596
                            $assetId = $extraData[$fieldVariable];
1597
                            $assetRepo = Container::getAssetRepository();
1598
                            /** @var Asset $asset */
1599
                            $asset = $assetRepo->find($assetId);
1600
                            if (null !== $asset) {
1601
                                $fileName = $asset->getTitle();
1602
                                $linkUrl = $assetRepo->getAssetUrl($asset);
1603
                                $linkToDelete = '';
1604
                                if (api_is_platform_admin()) {
1605
                                    $url = api_get_path(WEB_AJAX_PATH).'extra_field.ajax.php?type='.$this->type;
1606
                                    $url .= '&a=delete_file&field_id='.$field_details['id'].'&item_id='.$itemId;
1607
                                    $deleteId = $variable.'_delete';
1608
                                    $form->addHtml(
1609
                                        "
1610
                                        <script>
1611
                                            $(function() {
1612
                                                $('#".$deleteId."').on('click', function() {
1613
                                                    $.ajax({
1614
                                                        type: 'GET',
1615
                                                        url: '".$url."',
1616
                                                        success: function(result) {
1617
                                                            if (result == 1) {
1618
                                                                $('#".$variable."').html('".get_lang('Deleted')."');
1619
                                                            }
1620
                                                        }
1621
                                                    });
1622
                                                });
1623
                                            });
1624
                                        </script>
1625
                                    "
1626
                                    );
1627
1628
                                    $linkToDelete = '&nbsp;'.Display::url(
1629
                                        Display::return_icon('delete.png', get_lang('Delete')),
1630
                                        'javascript:void(0)',
1631
                                        ['id' => $deleteId]
1632
                                    );
1633
                                }
1634
                                $anchor = Display::url(
1635
                                    $fileName,
1636
                                    $linkUrl,
1637
                                    [
1638
                                        'title' => $field_details['display_text'],
1639
                                        'target' => '_blank',
1640
                                    ]
1641
                                );
1642
                                $fieldTexts[] = '<div id="'.$variable.'">'.$anchor.$linkToDelete.'</div>';
1643
                            }
1644
                        }
1645
1646
                        $form->addElement(
1647
                            'file',
1648
                            $fieldVariable,
1649
                            $fieldTexts,
1650
                            []
1651
                        );
1652
1653
                        $form->applyFilter('extra_'.$variable, 'stripslashes');
1654
                        $form->applyFilter('extra_'.$variable, 'trim');
1655
1656
                        if ($freezeElement) {
1657
                            $form->freeze('extra_'.$variable);
1658
                        }
1659
                        break;
1660
                    case self::FIELD_TYPE_VIDEO_URL:
1661
                        $form->addUrl(
1662
                            "extra_{$variable}",
1663
                            $field_details['display_text'],
1664
                            false,
1665
                            ['placeholder' => 'https://']
1666
                        );
1667
                        if ($freezeElement) {
1668
                            $form->freeze('extra_'.$variable);
1669
                        }
1670
                        break;
1671
                    case self::FIELD_TYPE_LETTERS_ONLY:
1672
                        $form->addTextLettersOnly(
1673
                            "extra_{$variable}",
1674
                            $field_details['display_text']
1675
                        );
1676
                        $form->applyFilter('extra_'.$variable, 'stripslashes');
1677
1678
                        if ($freezeElement) {
1679
                            $form->freeze('extra_'.$variable);
1680
                        }
1681
                        break;
1682
                    case self::FIELD_TYPE_ALPHANUMERIC:
1683
                        $form->addTextAlphanumeric(
1684
                            "extra_{$variable}",
1685
                            $field_details['display_text']
1686
                        );
1687
                        $form->applyFilter(
1688
                            'extra_'.$variable,
1689
                            'stripslashes'
1690
                        );
1691
                        if ($freezeElement) {
1692
                            $form->freeze('extra_'.$variable);
1693
                        }
1694
                        break;
1695
                    case self::FIELD_TYPE_LETTERS_SPACE:
1696
                        $form->addTextLettersAndSpaces(
1697
                            "extra_{$variable}",
1698
                            $field_details['display_text']
1699
                        );
1700
                        $form->applyFilter('extra_'.$variable, 'stripslashes');
1701
1702
                        if ($freezeElement) {
1703
                            $form->freeze('extra_'.$variable);
1704
                        }
1705
                        break;
1706
                    case self::FIELD_TYPE_ALPHANUMERIC_SPACE:
1707
                        $form->addTextAlphanumericAndSpaces(
1708
                            "extra_{$variable}",
1709
                            $field_details['display_text']
1710
                        );
1711
                        $form->applyFilter(
1712
                            'extra_'.$variable,
1713
                            'stripslashes'
1714
                        );
1715
                        if ($freezeElement) {
1716
                            $form->freeze('extra_'.$variable);
1717
                        }
1718
                        break;
1719
                    case self::FIELD_TYPE_GEOLOCALIZATION_COORDINATES:
1720
                    case self::FIELD_TYPE_GEOLOCALIZATION:
1721
                        $dataValue = isset($extraData['extra_'.$variable]) ? $extraData['extra_'.$variable] : '';
1722
                        $form->addGeoLocationMapField(
1723
                            'extra_'.$variable,
1724
                            $field_details['display_text'],
1725
                            $dataValue,
1726
                            $hideGeoLocalizationDetails
1727
                        );
1728
1729
                        if ($freezeElement) {
1730
                            $form->freeze('extra_'.$variable);
1731
                        }
1732
                        break;
1733
                    case self::FIELD_TYPE_SELECT_WITH_TEXT_FIELD:
1734
                        $jquery_ready_content .= $this->addSelectWithTextFieldElement(
1735
                            $form,
1736
                            $field_details,
1737
                            $freezeElement
1738
                        );
1739
                        break;
1740
                    case self::FIELD_TYPE_TRIPLE_SELECT:
1741
                        $jquery_ready_content .= $this->addTripleSelectElement(
1742
                            $form,
1743
                            $field_details,
1744
                            is_array($extraData) ? $extraData : [],
1745
                            $freezeElement
1746
                        );
1747
                        break;
1748
                }
1749
            }
1750
        }
1751
1752
        $return = [];
1753
        $return['jquery_ready_content'] = $jquery_ready_content;
1754
1755
        return $return;
1756
    }
1757
1758
    /**
1759
     * @param array $options
1760
     *
1761
     * @return array
1762
     */
1763
    public static function extra_field_double_select_convert_array_to_ordered_array($options)
1764
    {
1765
        $optionsParsed = [];
1766
        if (!empty($options)) {
1767
            foreach ($options as $option) {
1768
                if (0 == $option['option_value']) {
1769
                    $optionsParsed[$option['id']][] = $option;
1770
                } else {
1771
                    $optionsParsed[$option['option_value']][] = $option;
1772
                }
1773
            }
1774
        }
1775
1776
        return $optionsParsed;
1777
    }
1778
1779
    /**
1780
     * @return array
1781
     */
1782
    public static function tripleSelectConvertArrayToOrderedArray(array $options)
1783
    {
1784
        $level1 = self::getOptionsFromTripleSelect($options, 0);
1785
        $level2 = [];
1786
        $level3 = [];
1787
1788
        foreach ($level1 as $item1) {
1789
            $level2 += self::getOptionsFromTripleSelect($options, $item1['id']);
1790
        }
1791
1792
        foreach ($level2 as $item2) {
1793
            $level3 += self::getOptionsFromTripleSelect($options, $item2['id']);
1794
        }
1795
1796
        return ['level1' => $level1, 'level2' => $level2, 'level3' => $level3];
1797
    }
1798
1799
    /**
1800
     * @param string $type
1801
     *
1802
     * @return array
1803
     */
1804
    public function get_all_extra_field_by_type($type)
1805
    {
1806
        // all the information of the field
1807
        $sql = "SELECT * FROM {$this->table}
1808
                WHERE
1809
                    field_type = '".Database::escape_string($type)."' AND
1810
                    extra_field_type = $this->extraFieldType
1811
                ";
1812
        $result = Database::query($sql);
1813
1814
        $return = [];
1815
        while ($row = Database::fetch_array($result)) {
1816
            $return[] = $row['id'];
1817
        }
1818
1819
        return $return;
1820
    }
1821
1822
    /**
1823
     * @param int $id
1824
     */
1825
    public function get_field_type_by_id($id)
1826
    {
1827
        $types = $this->get_field_types();
1828
        if (isset($types[$id])) {
1829
            return $types[$id];
1830
        }
1831
1832
        return null;
1833
    }
1834
1835
    /**
1836
     * @return array
1837
     */
1838
    public function get_field_types()
1839
    {
1840
        return $this->get_extra_fields_by_handler($this->type);
1841
    }
1842
1843
    /**
1844
     * @param string $handler
1845
     *
1846
     * @return array
1847
     */
1848
    public static function get_extra_fields_by_handler($handler)
1849
    {
1850
        $types = [];
1851
        $types[self::FIELD_TYPE_TEXT] = get_lang('FieldTypeText');
1852
        $types[self::FIELD_TYPE_TEXTAREA] = get_lang('FieldTypeTextarea');
1853
        $types[self::FIELD_TYPE_RADIO] = get_lang('FieldTypeRadio');
1854
        $types[self::FIELD_TYPE_SELECT] = get_lang('FieldTypeSelect');
1855
        $types[self::FIELD_TYPE_SELECT_MULTIPLE] = get_lang('FieldTypeSelectMultiple');
1856
        $types[self::FIELD_TYPE_DATE] = get_lang('FieldTypeDate');
1857
        $types[self::FIELD_TYPE_DATETIME] = get_lang('FieldTypeDatetime');
1858
        $types[self::FIELD_TYPE_DOUBLE_SELECT] = get_lang('FieldTypeDoubleSelect');
1859
        $types[self::FIELD_TYPE_DIVIDER] = get_lang('FieldTypeDivider');
1860
        $types[self::FIELD_TYPE_TAG] = get_lang('FieldTypeTag');
1861
        $types[self::FIELD_TYPE_TIMEZONE] = get_lang('FieldTypeTimezone');
1862
        $types[self::FIELD_TYPE_SOCIAL_PROFILE] = get_lang('FieldTypeSocialProfile');
1863
        $types[self::FIELD_TYPE_MOBILE_PHONE_NUMBER] = get_lang('FieldTypeMobilePhoneNumber');
1864
        $types[self::FIELD_TYPE_CHECKBOX] = get_lang('FieldTypeCheckbox');
1865
        $types[self::FIELD_TYPE_INTEGER] = get_lang('FieldTypeInteger');
1866
        $types[self::FIELD_TYPE_FILE_IMAGE] = get_lang('FieldTypeFileImage');
1867
        $types[self::FIELD_TYPE_FLOAT] = get_lang('FieldTypeFloat');
1868
        $types[self::FIELD_TYPE_FILE] = get_lang('FieldTypeFile');
1869
        $types[self::FIELD_TYPE_VIDEO_URL] = get_lang('FieldTypeVideoUrl');
1870
        $types[self::FIELD_TYPE_LETTERS_ONLY] = get_lang('FieldTypeOnlyLetters');
1871
        $types[self::FIELD_TYPE_ALPHANUMERIC] = get_lang('FieldTypeAlphanumeric');
1872
        $types[self::FIELD_TYPE_LETTERS_SPACE] = get_lang('FieldTypeLettersSpaces');
1873
        $types[self::FIELD_TYPE_ALPHANUMERIC_SPACE] = get_lang('FieldTypeAlphanumericSpaces');
1874
        $types[self::FIELD_TYPE_GEOLOCALIZATION] = get_lang('Geolocalization');
1875
        $types[self::FIELD_TYPE_GEOLOCALIZATION_COORDINATES] = get_lang('GeolocalizationCoordinates');
1876
        $types[self::FIELD_TYPE_SELECT_WITH_TEXT_FIELD] = get_lang('FieldTypeSelectWithTextField');
1877
        $types[self::FIELD_TYPE_TRIPLE_SELECT] = get_lang('FieldTypeTripleSelect');
1878
1879
        switch ($handler) {
1880
            case 'course':
1881
            case 'session':
1882
            case 'user':
1883
            case 'skill':
1884
                break;
1885
        }
1886
1887
        return $types;
1888
    }
1889
1890
    /**
1891
     * @param array $params
1892
     * @param bool  $showQuery
1893
     *
1894
     * @return int|bool
1895
     */
1896
    public function save($params, $showQuery = false)
1897
    {
1898
        $fieldInfo = self::get_handler_field_info_by_field_variable($params['variable']);
0 ignored issues
show
Bug Best Practice introduced by
The method ExtraField::get_handler_...nfo_by_field_variable() is not static, but was called statically. ( Ignorable by Annotation )

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

1898
        /** @scrutinizer ignore-call */ 
1899
        $fieldInfo = self::get_handler_field_info_by_field_variable($params['variable']);
Loading history...
1899
        $params = $this->clean_parameters($params);
1900
        $params['extra_field_type'] = $this->extraFieldType;
1901
1902
        if ($fieldInfo) {
1903
            return $fieldInfo['id'];
1904
        } else {
1905
            $id = parent::save($params, $showQuery);
1906
            if ($id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $id of type false|integer is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.

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

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

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

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
1907
                $fieldOption = new ExtraFieldOption($this->type);
1908
                $params['field_id'] = $id;
1909
                $fieldOption->save($params);
1910
            }
1911
1912
            return $id;
1913
        }
1914
    }
1915
1916
    /**
1917
     * @param string $variable
1918
     *
1919
     * @return array|bool
1920
     */
1921
    public function get_handler_field_info_by_field_variable($variable)
1922
    {
1923
        $variable = Database::escape_string($variable);
1924
        $sql = "SELECT * FROM {$this->table}
1925
                WHERE
1926
                    variable = '$variable' AND
1927
                    extra_field_type = $this->extraFieldType";
1928
        $result = Database::query($sql);
1929
        if (Database::num_rows($result)) {
1930
            $row = Database::fetch_array($result, 'ASSOC');
1931
            if ($row) {
1932
                $row['display_text'] = $this->translateDisplayName(
1933
                    $row['variable'],
1934
                    $row['display_text']
1935
                );
1936
1937
                // All the options of the field
1938
                $sql = "SELECT * FROM $this->table_field_options
1939
                    WHERE field_id='".intval($row['id'])."'
1940
                    ORDER BY option_order ASC";
1941
                $result = Database::query($sql);
1942
                while ($option = Database::fetch_array($result)) {
1943
                    $row['options'][$option['id']] = $option;
1944
                }
1945
1946
                return $row;
1947
            }
1948
        }
1949
1950
        return false;
1951
    }
1952
1953
    /**
1954
     * @param array $params
1955
     *
1956
     * @return array
1957
     */
1958
    public function clean_parameters($params)
1959
    {
1960
        if (!isset($params['variable']) || empty($params['variable'])) {
1961
            $params['variable'] = $params['display_text'];
1962
        }
1963
1964
        $params['variable'] = trim(strtolower(str_replace(' ', '_', $params['variable'])));
1965
1966
        if (!isset($params['field_order'])) {
1967
            $max_order = self::get_max_field_order();
0 ignored issues
show
Bug Best Practice introduced by
The method ExtraField::get_max_field_order() is not static, but was called statically. ( Ignorable by Annotation )

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

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

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

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