Passed
Push — 1.11.x ( 859289...9e1dc9 )
by Angel Fernando Quiroz
09:54
created

ExtraFieldValue::formatValues()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 16
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 8
c 0
b 0
f 0
dl 0
loc 16
rs 10
cc 2
nc 2
nop 1
1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
use Chamilo\CoreBundle\Entity\ExtraField as EntityExtraField;
6
use Chamilo\CoreBundle\Entity\ExtraFieldRelTag;
7
use Chamilo\CoreBundle\Entity\ExtraFieldValues;
8
use Chamilo\CoreBundle\Entity\Tag;
9
use ChamiloSession as Session;
10
11
/**
12
 * Class ExtraFieldValue
13
 * Declaration for the ExtraFieldValue class, managing the values in extra
14
 * fields for any data type.
15
 */
16
class ExtraFieldValue extends Model
17
{
18
    public $type = '';
19
    public $columns = [
20
        'id',
21
        'field_id',
22
        'value',
23
        'comment',
24
        'item_id',
25
        'created_at',
26
        'updated_at',
27
    ];
28
    /** @var ExtraField */
29
    public $extraField;
30
31
    /**
32
     * Formats the necessary elements for the given datatype.
33
     *
34
     * @param string $type The type of data to which this extra field
35
     *                     applies (user, course, session, ...)
36
     *
37
     * @assert (-1) === false
38
     */
39
    public function __construct($type)
40
    {
41
        parent::__construct();
42
        $this->type = $type;
43
        $extraField = new ExtraField($this->type);
44
        $this->extraField = $extraField;
45
        $this->table = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
46
        $this->table_handler_field = Database::get_main_table(TABLE_EXTRA_FIELD);
47
    }
48
49
    /**
50
     * @return ExtraField
51
     */
52
    public function getExtraField()
53
    {
54
        return $this->extraField;
55
    }
56
57
    /**
58
     * Gets the number of values stored in the table (all fields together)
59
     * for this type of resource.
60
     *
61
     * @return int Number of rows in the table
62
     * @assert () !== false
63
     */
64
    public function get_count()
65
    {
66
        $em = Database::getManager();
67
        $query = $em->getRepository('ChamiloCoreBundle:ExtraFieldValues')->createQueryBuilder('e');
68
        $query->select('count(e.id)');
69
        $query->where('e.extraFieldType = :type');
70
        $query->setParameter('type', $this->getExtraField()->getExtraFieldType());
71
72
        return $query->getQuery()->getSingleScalarResult();
73
    }
74
75
    /**
76
     * Save the extra fields values
77
     * In order to save this function needs a item_id (user id, course id, etc)
78
     * This function is used with $extraField->addElements().
79
     *
80
     * @param array $params              array for the insertion into the *_field_values table (each label must be prefixed by 'extra_')
81
     * @param bool  $onlySubmittedFields Only save parameters in the $param array
82
     * @param bool  $showQuery
83
     * @param array $saveOnlyThisFields
84
     * @param array $avoidFields         do not insert/modify this field
85
     * @param bool  $forceSave
86
     *
87
     * @return mixed false on empty params, void otherwise
88
     * @assert (array()) === false
89
     */
90
    public function saveFieldValues(
91
        $params,
92
        $onlySubmittedFields = false,
93
        $showQuery = false,
94
        $saveOnlyThisFields = [],
95
        $avoidFields = [],
96
        $forceSave = false,
97
        $deleteOldValues = true
98
    ) {
99
        foreach ($params as $key => $value) {
100
            $found = strpos($key, '__persist__');
101
102
            if (false === $found) {
103
                continue;
104
            }
105
106
            $tempKey = str_replace('__persist__', '', $key);
107
            if (!isset($params[$tempKey])) {
108
                $params[$tempKey] = [];
109
            }
110
        }
111
112
        if (empty($params['item_id'])) {
113
            return false;
114
        }
115
116
        $type = $this->getExtraField()->getExtraFieldType();
117
118
        $extraField = new ExtraField($this->type);
119
        $extraFields = $extraField->get_all(null, 'option_order');
120
121
        // Parse params.
122
        foreach ($extraFields as $fieldDetails) {
123
            if (false === $forceSave) {
124
                // if the field is not visible to the user in the end, we need to apply special rules.
125
                if (1 != $fieldDetails['visible_to_self']) {
126
                    if (isset($params['origin']) && 'profile' == $params['origin']) {
127
                        continue;
128
                    } else {
129
                        //only admins should be able to add those values
130
                        if (!api_is_platform_admin(true, true)) {
131
                            // although if not admin but sent through a CLI script, we should accept it as well
132
                            if (PHP_SAPI != 'cli') {
133
                                continue; //not a CLI script, so don't write the value to DB
134
                            }
135
                        }
136
                    }
137
                }
138
            }
139
140
            $field_variable = $fieldDetails['variable'];
141
142
            if ($onlySubmittedFields && !isset($params['extra_'.$field_variable])) {
143
                continue;
144
            }
145
146
            if (!empty($avoidFields)) {
147
                if (in_array($field_variable, $avoidFields)) {
148
                    continue;
149
                }
150
            }
151
152
            if (!empty($saveOnlyThisFields)) {
153
                if (!in_array($field_variable, $saveOnlyThisFields)) {
154
                    continue;
155
                }
156
            }
157
158
            $value = '';
159
            if (isset($params['extra_'.$field_variable])) {
160
                $value = $params['extra_'.$field_variable];
161
            }
162
            $extraFieldInfo = $this->getExtraField()->get_handler_field_info_by_field_variable($field_variable);
163
164
            if (!$extraFieldInfo) {
165
                continue;
166
            }
167
168
            $commentVariable = 'extra_'.$field_variable.'_comment';
169
            $comment = isset($params[$commentVariable]) ? $params[$commentVariable] : null;
170
            $dirPermissions = api_get_permissions_for_new_directories();
171
172
            switch ($extraFieldInfo['field_type']) {
173
                case ExtraField::FIELD_TYPE_GEOLOCALIZATION_COORDINATES:
174
                case ExtraField::FIELD_TYPE_GEOLOCALIZATION:
175
                    if (!empty($value)) {
176
                        if (isset($params['extra_'.$extraFieldInfo['variable'].'_coordinates'])) {
177
                            $value = $value.'::'.$params['extra_'.$extraFieldInfo['variable'].'_coordinates'];
178
                        }
179
                        $newParams = [
180
                            'item_id' => $params['item_id'],
181
                            'field_id' => $extraFieldInfo['id'],
182
                            'value' => $value,
183
                            'comment' => $comment,
184
                        ];
185
                        self::save($newParams, $showQuery);
0 ignored issues
show
Bug Best Practice introduced by
The method ExtraFieldValue::save() 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

185
                        self::/** @scrutinizer ignore-call */ 
186
                              save($newParams, $showQuery);
Loading history...
186
                    }
187
                    break;
188
                case ExtraField::FIELD_TYPE_TAG:
189
                    if (EntityExtraField::USER_FIELD_TYPE == $type) {
190
                        UserManager::delete_user_tags(
191
                            $params['item_id'],
192
                            $extraFieldInfo['id']
193
                        );
194
195
                        UserManager::process_tags(
196
                            $value,
197
                            $params['item_id'],
198
                            $extraFieldInfo['id']
199
                        );
200
                        break;
201
                    }
202
203
                    $em = Database::getManager();
204
205
                    $currentTags = $em
206
                        ->getRepository('ChamiloCoreBundle:ExtraFieldRelTag')
207
                        ->findBy([
208
                            'fieldId' => $extraFieldInfo['id'],
209
                            'itemId' => $params['item_id'],
210
                        ]);
211
212
                    if ($deleteOldValues) {
213
                        foreach ($currentTags as $extraFieldtag) {
214
                            $em->remove($extraFieldtag);
215
                        }
216
                    }
217
                    $em->flush();
218
                    $tagValues = is_array($value) ? $value : [$value];
219
                    $tags = [];
220
221
                    foreach ($tagValues as $tagValue) {
222
                        if (empty($tagValue)) {
223
                            continue;
224
                        }
225
226
                        $tagsResult = $em->getRepository('ChamiloCoreBundle:Tag')
227
                            ->findBy([
228
                                'tag' => $tagValue,
229
                                'fieldId' => $extraFieldInfo['id'],
230
                            ]);
231
232
                        if (empty($tagsResult)) {
233
                            $tag = new Tag();
234
                            $tag->setFieldId($extraFieldInfo['id']);
235
                            $tag->setTag($tagValue);
236
237
                            $tags[] = $tag;
238
                        } else {
239
                            $tags = array_merge($tags, $tagsResult);
240
                        }
241
                    }
242
243
                    foreach ($tags as $tag) {
244
                        $tagUses = $em
245
                            ->getRepository('ChamiloCoreBundle:ExtraFieldRelTag')
246
                            ->findBy([
247
                                'tagId' => $tag->getId(),
248
                            ]);
249
250
                        $tag->setCount(count($tagUses) + 1);
251
                        $em->persist($tag);
252
                    }
253
254
                    $em->flush();
255
256
                    foreach ($tags as $tag) {
257
                        $fieldRelTag = new ExtraFieldRelTag();
258
                        $fieldRelTag->setFieldId($extraFieldInfo['id']);
259
                        $fieldRelTag->setItemId($params['item_id']);
260
                        $fieldRelTag->setTagId($tag->getId());
261
                        $em->persist($fieldRelTag);
262
                    }
263
264
                    $em->flush();
265
                    break;
266
                case ExtraField::FIELD_TYPE_FILE_IMAGE:
267
                    $fileDir = $fileDirStored = '';
268
                    switch ($this->type) {
269
                        case 'course':
270
                            $fileDir = api_get_path(SYS_UPLOAD_PATH)."courses/";
271
                            $fileDirStored = "courses/";
272
                            break;
273
                        case 'session':
274
                            $fileDir = api_get_path(SYS_UPLOAD_PATH)."sessions/";
275
                            $fileDirStored = "sessions/";
276
                            break;
277
                        case 'user':
278
                            $fileDir = UserManager::getUserPathById($params['item_id'], 'system');
279
                            $fileDirStored = UserManager::getUserPathById($params['item_id'], 'last');
280
                            break;
281
                        case 'work':
282
                            $fileDir = api_get_path(SYS_UPLOAD_PATH).'work/';
283
                            $fileDirStored = 'work/';
284
                            break;
285
                    }
286
287
                    $fileName = ExtraField::FIELD_TYPE_FILE_IMAGE."_{$params['item_id']}.png";
288
289
                    if (!file_exists($fileDir)) {
290
                        mkdir($fileDir, $dirPermissions, true);
291
                    }
292
293
                    if (!empty($value['tmp_name']) && isset($value['error']) && $value['error'] == 0) {
294
                        // Crop the image to adjust 16:9 ratio
295
                        if (isset($params['extra_'.$field_variable.'_crop_result'])) {
296
                            $crop = new Image($value['tmp_name']);
297
                            $crop->crop($params['extra_'.$field_variable.'_crop_result']);
298
                        }
299
300
                        $imageExtraField = new Image($value['tmp_name']);
301
                        $imageExtraField->resize(400);
302
                        $imageExtraField->send_image($fileDir.$fileName, -1, 'png');
303
                        $newParams = [
304
                            'item_id' => $params['item_id'],
305
                            'field_id' => $extraFieldInfo['id'],
306
                            'value' => $fileDirStored.$fileName,
307
                            'comment' => $comment,
308
                        ];
309
                        $this->save($newParams);
310
                    }
311
                    break;
312
                case ExtraField::FIELD_TYPE_FILE:
313
                    $fileDir = $fileDirStored = '';
314
                    switch ($this->type) {
315
                        case 'course':
316
                            $fileDir = api_get_path(SYS_UPLOAD_PATH).'courses/';
317
                            $fileDirStored = "courses/";
318
                            break;
319
                        case 'session':
320
                            $fileDir = api_get_path(SYS_UPLOAD_PATH).'sessions/';
321
                            $fileDirStored = "sessions/";
322
                            break;
323
                        case 'user':
324
                            $fileDir = UserManager::getUserPathById($params['item_id'], 'system');
325
                            $fileDirStored = UserManager::getUserPathById($params['item_id'], 'last');
326
                            break;
327
                        case 'work':
328
                            $fileDir = api_get_path(SYS_UPLOAD_PATH).'work/';
329
                            $fileDirStored = "work/";
330
                            break;
331
                        case 'scheduled_announcement':
332
                            $fileDir = api_get_path(SYS_UPLOAD_PATH).'scheduled_announcement/';
333
                            $fileDirStored = 'scheduled_announcement/';
334
                            break;
335
                    }
336
337
                    if (!file_exists($fileDir)) {
338
                        mkdir($fileDir, $dirPermissions, true);
339
                    }
340
341
                    if (!empty($value['tmp_name']) && isset($value['error']) && $value['error'] == 0) {
342
                        $cleanedName = api_replace_dangerous_char($value['name']);
343
                        $cleanedName = disable_dangerous_file($cleanedName);
344
                        $fileName = ExtraField::FIELD_TYPE_FILE."_{$params['item_id']}_$cleanedName";
345
                        moveUploadedFile($value, $fileDir.$fileName);
346
347
                        $new_params = [
348
                            'item_id' => $params['item_id'],
349
                            'field_id' => $extraFieldInfo['id'],
350
                            'value' => $fileDirStored.$fileName,
351
                        ];
352
353
                        if ('session' !== $this->type && 'course' !== $this->type) {
354
                            $new_params['comment'] = $comment;
355
                        }
356
357
                        $this->save($new_params);
358
                    }
359
                    break;
360
                case ExtraField::FIELD_TYPE_CHECKBOX:
361
                    $fieldToSave = 0;
362
                    if (is_array($value)) {
363
                        if (isset($value['extra_'.$field_variable])) {
364
                            $fieldToSave = 1;
365
                        }
366
                    }
367
368
                    $newParams = [
369
                        'item_id' => $params['item_id'],
370
                        'field_id' => $extraFieldInfo['id'],
371
                        'value' => $fieldToSave,
372
                        'comment' => $comment,
373
                    ];
374
                    $this->save($newParams);
375
376
                    break;
377
                case ExtraField::FIELD_TYPE_DATE:
378
                    $d = DateTime::createFromFormat('Y-m-d', $value);
379
                    $valid = $d && $d->format('Y-m-d') === $value;
380
                    if ($valid) {
381
                        $newParams = [
382
                            'item_id' => $params['item_id'],
383
                            'field_id' => $extraFieldInfo['id'],
384
                            'value' => $value,
385
                            'comment' => $comment,
386
                        ];
387
                        $this->save($newParams, $showQuery);
388
                    }
389
                    break;
390
                case ExtraField::FIELD_TYPE_DATETIME:
391
                    $d = DateTime::createFromFormat('Y-m-d H:i', $value);
392
                    $valid = $d && $d->format('Y-m-d H:i') === $value;
393
                    if (!$valid && EntityExtraField::LP_ITEM_FIELD_TYPE === (int) $extraFieldInfo['extra_field_type']) {
394
                        $valid = empty($value);
395
                    }
396
                    if ($valid) {
397
                        $newParams = [
398
                            'item_id' => $params['item_id'],
399
                            'field_id' => $extraFieldInfo['id'],
400
                            'value' => $value,
401
                            'comment' => $comment,
402
                        ];
403
                        $this->save($newParams, $showQuery);
404
                    }
405
                    break;
406
                default:
407
                    $newParams = [
408
                        'item_id' => $params['item_id'],
409
                        'field_id' => $extraFieldInfo['id'],
410
                        'value' => $value,
411
                        'comment' => $comment,
412
                    ];
413
                    $this->save($newParams, $showQuery);
414
            }
415
        }
416
    }
417
418
    /**
419
     * Save values in the *_field_values table.
420
     *
421
     * @param array $params    Structured array with the values to save
422
     * @param bool  $showQuery Whether to show the insert query (passed to the parent save() method)
423
     *
424
     * @return mixed The result sent from the parent method
425
     * @assert (array()) === false
426
     */
427
    public function save($params, $showQuery = false)
428
    {
429
        $extra_field = $this->getExtraField();
430
431
        // Setting value to insert.
432
        $value = $params['value'];
433
        $value_to_insert = null;
434
435
        if (is_array($value)) {
436
            $value_to_insert = implode(';', $value);
437
        } else {
438
            $value_to_insert = $value;
439
        }
440
441
        $params['value'] = $value_to_insert;
442
443
        // If field id exists
444
        if (isset($params['field_id'])) {
445
            $extraFieldInfo = $extra_field->get($params['field_id']);
446
        } else {
447
            // Try the variable
448
            $extraFieldInfo = $extra_field->get_handler_field_info_by_field_variable(
449
                $params['variable']
450
            );
451
            if ($extraFieldInfo) {
452
                $params['field_id'] = $extraFieldInfo['id'];
453
            }
454
        }
455
456
        if ($extraFieldInfo) {
457
            switch ($extraFieldInfo['field_type']) {
458
                case ExtraField::FIELD_TYPE_RADIO:
459
                case ExtraField::FIELD_TYPE_SELECT:
460
                    break;
461
                case ExtraField::FIELD_TYPE_SELECT_MULTIPLE:
462
                    //$field_options = $session_field_option->get_field_options_by_field($params['field_id']);
463
                    //$params['field_value'] = split(';', $value_to_insert);
464
                    /*
465
                        if ($field_options) {
466
                            $check = false;
467
                            foreach ($field_options as $option) {
468
                                if (in_array($option['option_value'], $values)) {
469
                                    $check = true;
470
                                    break;
471
                                }
472
                           }
473
                           if (!$check) {
474
                               return false; //option value not found
475
                           }
476
                       } else {
477
                           return false; //enumerated type but no option found
478
                       }*/
479
                    break;
480
                case ExtraField::FIELD_TYPE_TEXT:
481
                case ExtraField::FIELD_TYPE_TEXTAREA:
482
                    break;
483
                case ExtraField::FIELD_TYPE_DOUBLE_SELECT:
484
                case ExtraField::FIELD_TYPE_SELECT_WITH_TEXT_FIELD:
485
                    if (is_array($value)) {
486
                        $value_to_insert = null;
487
                        if (isset($value['extra_'.$extraFieldInfo['variable']]) &&
488
                            isset($value['extra_'.$extraFieldInfo['variable'].'_second'])
489
                        ) {
490
                            $value_to_insert = $value['extra_'.$extraFieldInfo['variable']].'::'.$value['extra_'.$extraFieldInfo['variable'].'_second'];
491
                        }
492
                    }
493
                    break;
494
                default:
495
                    break;
496
            }
497
498
            if (ExtraField::FIELD_TYPE_TAG == $extraFieldInfo['field_type']) {
499
                $field_values = self::getAllValuesByItemAndFieldAndValue(
0 ignored issues
show
Bug Best Practice introduced by
The method ExtraFieldValue::getAllV...yItemAndFieldAndValue() 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

499
                /** @scrutinizer ignore-call */ 
500
                $field_values = self::getAllValuesByItemAndFieldAndValue(
Loading history...
500
                    $params['item_id'],
501
                    $params['field_id'],
502
                    $value
503
                );
504
            } else {
505
                $field_values = self::get_values_by_handler_and_field_id(
0 ignored issues
show
Bug Best Practice introduced by
The method ExtraFieldValue::get_val..._handler_and_field_id() 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

505
                /** @scrutinizer ignore-call */ 
506
                $field_values = self::get_values_by_handler_and_field_id(
Loading history...
506
                    $params['item_id'],
507
                    $params['field_id']
508
                );
509
            }
510
511
            $params['value'] = $value_to_insert;
512
            //$params['author_id'] = api_get_user_id();
513
514
            // Insert
515
            if (empty($field_values)) {
516
                /* Enable this when field_loggeable is introduced as a table field (2.0)
517
                if ($extraFieldInfo['field_loggeable'] == 1) {
518
                */
519
                if (false) {
520
                    global $app;
521
                    switch ($this->type) {
522
                        case 'question':
523
                            $extraFieldValue = new ChamiloLMS\Entity\QuestionFieldValues();
524
                            $extraFieldValue->setUserId(api_get_user_id());
525
                            $extraFieldValue->setQuestionId($params[$this->handler_id]);
0 ignored issues
show
Bug Best Practice introduced by
The property handler_id does not exist on ExtraFieldValue. Did you maybe forget to declare it?
Loading history...
526
                            break;
527
                        case 'course':
528
                            $extraFieldValue = new ChamiloLMS\Entity\CourseFieldValues();
529
                            $extraFieldValue->setUserId(api_get_user_id());
530
                            $extraFieldValue->setQuestionId($params[$this->handler_id]);
531
                            break;
532
                        case 'user':
533
                            $extraFieldValue = new ChamiloLMS\Entity\UserFieldValues();
534
                            $extraFieldValue->setUserId($params[$this->handler_id]);
535
                            $extraFieldValue->setAuthorId(api_get_user_id());
536
                            break;
537
                        case 'session':
538
                            $extraFieldValue = new ChamiloLMS\Entity\SessionFieldValues();
539
                            $extraFieldValue->setUserId(api_get_user_id());
540
                            $extraFieldValue->setSessionId($params[$this->handler_id]);
541
                            break;
542
                    }
543
                    if (isset($extraFieldValue)) {
544
                        if (!empty($params['value'])) {
545
                            $extraFieldValue->setComment($params['comment']);
546
                            $extraFieldValue->setFieldValue($params['value']);
547
                            $extraFieldValue->setFieldId($params['field_id']);
548
                            $extraFieldValue->setTms(api_get_utc_datetime(null, false, true));
549
                            $app['orm.ems']['db_write']->persist($extraFieldValue);
550
                            $app['orm.ems']['db_write']->flush();
551
                        }
552
                    }
553
                } else {
554
                    if ($extraFieldInfo['field_type'] == ExtraField::FIELD_TYPE_TAG) {
555
                        $option = new ExtraFieldOption($this->type);
556
                        $optionExists = $option->get($params['value']);
557
                        if (empty($optionExists)) {
558
                            $optionParams = [
559
                                'field_id' => $params['field_id'],
560
                                'option_value' => $params['value'],
561
                            ];
562
                            $optionId = $option->saveOptions($optionParams);
563
                        } else {
564
                            $optionId = $optionExists['id'];
565
                        }
566
567
                        $params['value'] = $optionId;
568
                        if ($optionId) {
569
                            return parent::save($params, $showQuery);
570
                        }
571
                    } else {
572
                        return parent::save($params, $showQuery);
573
                    }
574
                }
575
            } else {
576
                // Update
577
                /* Enable this when field_loggeable is introduced as a table field (2.0)
578
                if ($extraFieldInfo['field_loggeable'] == 1) {
579
                */
580
                if (false) {
581
                    global $app;
582
                    switch ($this->type) {
583
                        case 'question':
584
                            $extraFieldValue = $app['orm.ems']['db_write']->getRepository('ChamiloLMS\Entity\QuestionFieldValues')->find($field_values['id']);
585
                            $extraFieldValue->setUserId(api_get_user_id());
586
                            $extraFieldValue->setQuestionId($params[$this->handler_id]);
587
                            break;
588
                        case 'course':
589
                            $extraFieldValue = $app['orm.ems']['db_write']->getRepository('ChamiloLMS\Entity\CourseFieldValues')->find($field_values['id']);
590
                            $extraFieldValue->setUserId(api_get_user_id());
591
                            $extraFieldValue->setCourseCode($params[$this->handler_id]);
592
                            break;
593
                        case 'user':
594
                            $extraFieldValue = $app['orm.ems']['db_write']->getRepository('ChamiloLMS\Entity\UserFieldValues')->find($field_values['id']);
595
                            $extraFieldValue->setUserId(api_get_user_id());
596
                            $extraFieldValue->setAuthorId(api_get_user_id());
597
                            break;
598
                        case 'session':
599
                            $extraFieldValue = $app['orm.ems']['db_write']->getRepository('ChamiloLMS\Entity\SessionFieldValues')->find($field_values['id']);
600
                            $extraFieldValue->setUserId(api_get_user_id());
601
                            $extraFieldValue->setSessionId($params[$this->handler_id]);
602
                            break;
603
                    }
604
605
                    if (isset($extraFieldValue)) {
606
                        if (!empty($params['value'])) {
607
                            /*
608
                             *  If the field value is similar to the previous value then the comment will be the same
609
                                in order to no save in the log an empty record
610
                            */
611
                            if ($extraFieldValue->getFieldValue() == $params['value']) {
612
                                if (empty($params['comment'])) {
613
                                    $params['comment'] = $extraFieldValue->getComment();
614
                                }
615
                            }
616
617
                            $extraFieldValue->setComment($params['comment']);
618
                            $extraFieldValue->setFieldValue($params['value']);
619
                            $extraFieldValue->setFieldId($params['field_id']);
620
                            $extraFieldValue->setTms(api_get_utc_datetime(null, false, true));
621
                            $app['orm.ems']['db_write']->persist($extraFieldValue);
622
                            $app['orm.ems']['db_write']->flush();
623
                        }
624
                    }
625
                } else {
626
                    $params['id'] = $field_values['id'];
627
628
                    return parent::update($params, $showQuery);
629
                }
630
            }
631
        }
632
    }
633
634
    /**
635
     * Returns the value of the given extra field on the given resource.
636
     *
637
     * @param int  $item_id   Item ID (It could be a session_id, course_id or user_id)
638
     * @param int  $field_id  Field ID (the ID from the *_field table)
639
     * @param bool $transform Whether to transform the result to a human readable strings
640
     *
641
     * @return mixed A structured array with the field_id and field_value, or false on error
642
     * @assert (-1,-1) === false
643
     */
644
    public function get_values_by_handler_and_field_id($item_id, $field_id, $transform = false)
645
    {
646
        $field_id = (int) $field_id;
647
        $item_id = Database::escape_string($item_id);
648
649
        $sql = "SELECT s.*, field_type FROM {$this->table} s
650
                INNER JOIN {$this->table_handler_field} sf ON (s.field_id = sf.id)
651
                WHERE
652
                    item_id = $item_id AND
653
                    field_id = $field_id AND
654
                    sf.extra_field_type = ".$this->getExtraField()->getExtraFieldType()."
655
                ORDER BY id";
656
        $result = Database::query($sql);
657
        if (Database::num_rows($result)) {
658
            $result = Database::fetch_array($result, 'ASSOC');
659
            if ($transform) {
660
                if (!empty($result['value'])) {
661
                    switch ($result['field_type']) {
662
                        case ExtraField::FIELD_TYPE_DOUBLE_SELECT:
663
                            $field_option = new ExtraFieldOption($this->type);
664
                            $options = explode('::', $result['value']);
665
                            // only available for PHP 5.4  :( $result['field_value'] = $field_option->get($options[0])['id'].' -> ';
666
                            $result = $field_option->get($options[0]);
667
                            $result_second = $field_option->get($options[1]);
668
                            if (!empty($result)) {
669
                                $result['value'] = $result['display_text'].' -> ';
670
                                $result['value'] .= $result_second['display_text'];
671
                            }
672
                            break;
673
                        case ExtraField::FIELD_TYPE_SELECT:
674
                            $field_option = new ExtraFieldOption($this->type);
675
                            $extra_field_option_result = $field_option->get_field_option_by_field_and_option(
676
                                $result['field_id'],
677
                                $result['value']
678
                            );
679
680
                            if (isset($extra_field_option_result[0])) {
681
                                $result['value'] = $extra_field_option_result[0]['display_text'];
682
                            }
683
                            break;
684
                        case ExtraField::FIELD_TYPE_SELECT_WITH_TEXT_FIELD:
685
                            $options = explode('::', $result['value']);
686
687
                            $field_option = new ExtraFieldOption($this->type);
688
                            $result = $field_option->get($options[0]);
689
690
                            if (!empty($result)) {
691
                                $result['value'] = $result['display_text']
692
                                    .'&rarr;'
693
                                    .$options[1];
694
                            }
695
                            break;
696
                        case ExtraField::FIELD_TYPE_TRIPLE_SELECT:
697
                            $optionIds = explode(';', $result['value']);
698
                            $optionValues = [];
699
700
                            foreach ($optionIds as $optionId) {
701
                                $objEfOption = new ExtraFieldOption('user');
702
                                $optionInfo = $objEfOption->get($optionId);
703
704
                                $optionValues[] = $optionInfo['display_text'];
705
                            }
706
707
                            $result['value'] = implode(' / ', $optionValues);
708
                            break;
709
                    }
710
                }
711
            }
712
713
            return $result;
714
        }
715
716
        return false;
717
    }
718
719
    /**
720
     * @param string $tag
721
     * @param int    $field_id
722
     * @param int    $limit
723
     *
724
     * @return array
725
     */
726
    public function searchValuesByField($tag, $field_id, $limit = 10)
727
    {
728
        $field_id = (int) $field_id;
729
        $limit = (int) $limit;
730
        $extraFieldType = $this->getExtraField()->getExtraFieldType();
731
732
        $tag = Database::escape_string($tag);
733
        $sql = "SELECT DISTINCT s.value, s.field_id
734
                FROM {$this->table} s
735
                INNER JOIN {$this->table_handler_field} sf
736
                ON (s.field_id = sf.id)
737
                WHERE
738
                    field_id = $field_id AND
739
                    value LIKE '%$tag%' AND
740
                    sf.extra_field_type = $extraFieldType
741
                ORDER BY value
742
                LIMIT 0, $limit
743
                ";
744
        $result = Database::query($sql);
745
        $values = [];
746
        if (Database::num_rows($result)) {
747
            $values = Database::store_result($result, 'ASSOC');
748
        }
749
750
        return $values;
751
    }
752
753
    /**
754
     * Gets a structured array of the original item and its extra values, using
755
     * a specific original item and a field name (like "branch", or "birthdate").
756
     *
757
     * @param int    $item_id            Item ID from the original table
758
     * @param string $field_variable     The name of the field we are looking for
759
     * @param bool   $transform
760
     * @param bool   $filterByVisibility
761
     * @param int    $visibility
762
     *
763
     * @return mixed Array of results, or false on error or not found
764
     * @assert (-1,'') === false
765
     */
766
    public function get_values_by_handler_and_field_variable(
767
        $item_id,
768
        $field_variable,
769
        $transform = false,
770
        $filterByVisibility = false,
771
        $visibility = 0
772
    ) {
773
        $item_id = (int) $item_id;
774
        $field_variable = Database::escape_string($field_variable);
775
        $extraFieldType = $this->getExtraField()->getExtraFieldType();
776
777
        $sql = "SELECT s.*, field_type
778
                FROM {$this->table} s
779
                INNER JOIN {$this->table_handler_field} sf
780
                ON (s.field_id = sf.id)
781
                WHERE
782
                    item_id = $item_id  AND
783
                    variable = '$field_variable' AND
784
                    sf.extra_field_type = $extraFieldType
785
                ";
786
        if ($filterByVisibility) {
787
            $visibility = (int) $visibility;
788
            $sql .= " AND visible_to_self = $visibility ";
789
        }
790
        $sql .= ' ORDER BY id';
791
792
        $result = Database::query($sql);
793
        if (Database::num_rows($result)) {
794
            $result = Database::fetch_array($result, 'ASSOC');
795
            if ($transform) {
796
                if ($result['field_type'] == ExtraField::FIELD_TYPE_DOUBLE_SELECT) {
797
                    if (!empty($result['value'])) {
798
                        $field_option = new ExtraFieldOption($this->type);
799
                        $options = explode('::', $result['value']);
800
                        $result = $field_option->get($options[0]);
801
                        $result_second = $field_option->get($options[1]);
802
                        if (!empty($result)) {
803
                            $result['value'] = $result['display_text'].' -> ';
804
                            $result['value'] .= $result_second['display_text'];
805
                        }
806
                    }
807
                }
808
                if ($result['field_type'] == ExtraField::FIELD_TYPE_SELECT_WITH_TEXT_FIELD) {
809
                    if (!empty($result['value'])) {
810
                        $options = explode('::', $result['value']);
811
                        $field_option = new ExtraFieldOption($this->type);
812
                        $result = $field_option->get($options[0]);
813
                        if (!empty($result)) {
814
                            $result['value'] = $result['display_text'].'&rarr;'.$options[1];
815
                        }
816
                    }
817
                }
818
                if ($result['field_type'] == ExtraField::FIELD_TYPE_TRIPLE_SELECT) {
819
                    if (!empty($result['value'])) {
820
                        $optionIds = explode(';', $result['value']);
821
                        $optionValues = [];
822
823
                        foreach ($optionIds as $optionId) {
824
                            $objEfOption = new ExtraFieldOption('user');
825
                            $optionInfo = $objEfOption->get($optionId);
826
                            $optionValues[] = $optionInfo['display_text'];
827
                        }
828
829
                        $result['value'] = implode(' / ', $optionValues);
830
                    }
831
                }
832
833
                if ($result['field_type'] == Extrafield::FIELD_TYPE_SELECT && !empty($result['value'])) {
834
                    $fopt = (new ExtraFieldOption('user'))
835
                        ->get_field_option_by_field_and_option($result['field_id'], $result['value']);
836
                    $fopt = current(is_array($fopt) ? $fopt : []);
837
838
                    $result['value'] = $fopt['display_text'] ?? $result['value'];
839
                }
840
            }
841
842
            return $result;
843
        }
844
845
        return false;
846
    }
847
848
    /**
849
     * Gets the ID from the item (course, session, etc) for which
850
     * the given field is defined with the given value.
851
     *
852
     * @param string $variable  Field (type of data) we want to check
853
     * @param string $value     Data we are looking for in the given field
854
     * @param bool   $transform Whether to transform the result to a human readable strings
855
     * @param bool   $last      Whether to return the last element or simply the first one we get
856
     * @param bool   $useLike
857
     *
858
     * @return mixed Give the ID if found, or false on failure or not found
859
     * @assert (-1,-1) === false
860
     */
861
    public function get_item_id_from_field_variable_and_field_value(
862
        $variable,
863
        $value,
864
        $transform = false,
865
        $last = false,
866
        $all = false,
867
        $useLike = false
868
    ) {
869
        $value = Database::escape_string($value);
870
        $variable = Database::escape_string($variable);
871
872
        $valueCondition = " value  = '$value' AND ";
873
        if ($useLike) {
874
            $valueCondition = " value LIKE '%".$value."%' AND ";
875
        }
876
        $extraFieldType = $this->getExtraField()->getExtraFieldType();
877
878
        $sql = "SELECT item_id FROM {$this->table} s
879
                INNER JOIN {$this->table_handler_field} sf
880
                ON (s.field_id = sf.id)
881
                WHERE
882
                    $valueCondition
883
                    variable = '".$variable."' AND
884
                    sf.extra_field_type = $extraFieldType
885
                ORDER BY item_id
886
                ";
887
888
        if ($last) {
889
            // If we want the last element instead of the first
890
            // This is useful in special cases where there might
891
            // (erroneously) be more than one row for an item
892
            $sql .= ' DESC';
893
        }
894
        $result = Database::query($sql);
895
        if ($result !== false && Database::num_rows($result)) {
896
            if ($all) {
897
                $result = Database::store_result($result, 'ASSOC');
898
            } else {
899
                $result = Database::fetch_array($result, 'ASSOC');
900
            }
901
902
            return $result;
903
        }
904
905
        return false;
906
    }
907
908
    /**
909
     * Get all the values stored for one specific field.
910
     *
911
     * @param int $fieldId
912
     *
913
     * @return array|bool
914
     */
915
    public function getValuesByFieldId($fieldId)
916
    {
917
        $fieldId = (int) $fieldId;
918
        $extraFieldType = $this->getExtraField()->getExtraFieldType();
919
920
        $sql = "SELECT s.* FROM {$this->table} s
921
                INNER JOIN {$this->table_handler_field} sf
922
                ON (s.field_id = sf.id)
923
                WHERE
924
                    field_id = $fieldId AND
925
                    sf.extra_field_type = $extraFieldType
926
                ORDER BY s.value";
927
        $result = Database::query($sql);
928
929
        if (Database::num_rows($result)) {
930
            return Database::store_result($result, 'ASSOC');
931
        }
932
933
        return false;
934
    }
935
936
    /**
937
     * @param int $itemId
938
     * @param int $fieldId
939
     *
940
     * @return array
941
     */
942
    public function getAllValuesByItemAndField($itemId, $fieldId)
943
    {
944
        $fieldId = (int) $fieldId;
945
        $itemId = (int) $itemId;
946
        $extraFieldType = $this->getExtraField()->getExtraFieldType();
947
948
        $sql = "SELECT s.* FROM {$this->table} s
949
                INNER JOIN {$this->table_handler_field} sf
950
                ON (s.field_id = sf.id)
951
                WHERE
952
                    field_id = $fieldId AND
953
                    item_id = $itemId AND
954
                    sf.extra_field_type = $extraFieldType
955
                ORDER BY s.value";
956
        $result = Database::query($sql);
957
958
        if (Database::num_rows($result)) {
959
            return Database::store_result($result, 'ASSOC');
960
        }
961
962
        return false;
963
    }
964
965
    /**
966
     * Return extra fields details for an item if the extra field is marked as filter.
967
     */
968
    public function getAllValuesByItem(int $itemId): array
969
    {
970
        $itemId = (int) $itemId;
971
        $extraFieldType = $this->getExtraField()->getExtraFieldType();
972
973
        $sql = "SELECT s.value, sf.variable, sf.field_type, sf.id, sf.display_text
974
                FROM {$this->table} s
975
                INNER JOIN {$this->table_handler_field} sf
976
                ON (s.field_id = sf.id)
977
                WHERE
978
                    item_id = $itemId AND
979
                    sf.extra_field_type = $extraFieldType
980
                ORDER BY s.value";
981
982
        $result = Database::query($sql);
983
        $idList = [];
984
        $finalResult = [];
985
        if (Database::num_rows($result)) {
986
            $result = Database::store_result($result, 'ASSOC');
987
            foreach ($result as $item) {
988
                $finalResult[$item['id']] = $item;
989
            }
990
            $idList = array_column($result, 'id');
991
        }
992
993
        $em = Database::getManager();
994
995
        $extraField = new ExtraField($this->type);
996
        $allData = $extraField->get_all(['filter = ?' => 1]);
997
        $allResults = [];
998
        foreach ($allData as $field) {
999
            if (in_array($field['id'], $idList)) {
1000
                $allResults[] = $finalResult[$field['id']];
1001
            } else {
1002
                if ($field['field_type'] == ExtraField::FIELD_TYPE_TAG) {
1003
                    $tagResult = [];
1004
                    $tags = $em->getRepository('ChamiloCoreBundle:ExtraFieldRelTag')
1005
                        ->findBy(
1006
                            [
1007
                                'fieldId' => $field['id'],
1008
                                'itemId' => $itemId,
1009
                            ]
1010
                        );
1011
                    if ($tags) {
1012
                        /** @var ExtraFieldRelTag $extraFieldTag */
1013
                        foreach ($tags as $extraFieldTag) {
1014
                            /** @var \Chamilo\CoreBundle\Entity\Tag $tag */
1015
                            $tag = $em->find('ChamiloCoreBundle:Tag', $extraFieldTag->getTagId());
1016
                            $tagResult[] = [
1017
                                'id' => $extraFieldTag->getTagId(),
1018
                                'value' => $tag->getTag(),
1019
                            ];
1020
                        }
1021
                    }
1022
                    $allResults[] = [
1023
                        'value' => $tagResult,
1024
                        'variable' => $field['variable'],
1025
                        'field_type' => $field['field_type'],
1026
                        'id' => $field['id'],
1027
                    ];
1028
                }
1029
            }
1030
        }
1031
1032
        return $allResults;
1033
    }
1034
1035
    /**
1036
     * @param int    $itemId
1037
     * @param int    $fieldId
1038
     * @param string $fieldValue
1039
     *
1040
     * @return array|bool
1041
     */
1042
    public function getAllValuesByItemAndFieldAndValue($itemId, $fieldId, $fieldValue)
1043
    {
1044
        $fieldId = (int) $fieldId;
1045
        $itemId = (int) $itemId;
1046
        $extraFieldType = $this->getExtraField()->getExtraFieldType();
1047
1048
        $fieldValue = Database::escape_string($fieldValue);
1049
        $sql = "SELECT s.* FROM {$this->table} s
1050
                INNER JOIN {$this->table_handler_field} sf
1051
                ON (s.field_id = sf.id)
1052
                WHERE
1053
                    field_id = $fieldId AND
1054
                    item_id = $itemId AND
1055
                    value = '$fieldValue' AND
1056
                    sf.extra_field_type = $extraFieldType
1057
                ORDER BY value";
1058
1059
        $result = Database::query($sql);
1060
        if (Database::num_rows($result)) {
1061
            return Database::store_result($result, 'ASSOC');
1062
        }
1063
1064
        return false;
1065
    }
1066
1067
    /**
1068
     * Deletes all the values related to a specific field ID.
1069
     *
1070
     * @param int $field_id
1071
     *
1072
     * @assert ('a') == null
1073
     */
1074
    public function delete_all_values_by_field_id($field_id)
1075
    {
1076
        $field_id = (int) $field_id;
1077
        $sql = "DELETE FROM {$this->table}
1078
                WHERE
1079
                    field_id = $field_id ";
1080
        Database::query($sql);
1081
    }
1082
1083
    /**
1084
     * Deletes all values from an item.
1085
     *
1086
     * @param int $itemId (session id, course id, etc)
1087
     * @assert (-1,-1) == null
1088
     */
1089
    public function deleteValuesByItem($itemId)
1090
    {
1091
        $itemId = (int) $itemId;
1092
        $extraFieldType = $this->getExtraField()->getExtraFieldType();
1093
1094
        $sql = "DELETE FROM {$this->table}
1095
                WHERE
1096
                    item_id = $itemId AND
1097
                    field_id IN (
1098
                        SELECT id FROM {$this->table_handler_field}
1099
                        WHERE extra_field_type = $extraFieldType
1100
                    )
1101
                ";
1102
        Database::query($sql);
1103
    }
1104
1105
    /**
1106
     * @param int $itemId
1107
     * @param int $fieldId
1108
     * @param int $fieldValue
1109
     *
1110
     * @return bool
1111
     */
1112
    public function deleteValuesByHandlerAndFieldAndValue($itemId, $fieldId, $fieldValue)
1113
    {
1114
        $itemId = (int) $itemId;
1115
        $fieldId = (int) $fieldId;
1116
1117
        $fieldData = $this->getExtraField()->get($fieldId);
1118
        if ($fieldData) {
1119
            $fieldValue = Database::escape_string($fieldValue);
1120
1121
            $sql = "DELETE FROM {$this->table}
1122
                WHERE
1123
                    item_id = $itemId AND
1124
                    field_id = $fieldId AND
1125
                    value = '$fieldValue'
1126
                ";
1127
            Database::query($sql);
1128
1129
            // Delete file from uploads
1130
            if ($fieldData['field_type'] == ExtraField::FIELD_TYPE_FILE) {
1131
                api_remove_uploaded_file($this->type, basename($fieldValue));
1132
            }
1133
1134
            return true;
1135
        }
1136
1137
        return false;
1138
    }
1139
1140
    /**
1141
     * Get all values for an item.
1142
     *
1143
     * @param int  $itemId          The item ID
1144
     * @param bool $visibleToSelf   Get the visible extra field only
1145
     * @param bool $visibleToOthers
1146
     *
1147
     * @return array
1148
     */
1149
    public function getAllValuesForAnItem($itemId, $visibleToSelf = null, $visibleToOthers = null)
1150
    {
1151
        $em = Database::getManager();
1152
        $qb = $em->createQueryBuilder();
1153
        $qb = $qb->select('fv')
1154
            ->from('ChamiloCoreBundle:ExtraFieldValues', 'fv')
1155
            ->join('fv.field', 'f')
1156
            ->where(
1157
                $qb->expr()->eq('fv.itemId', ':item')
1158
            )
1159
            ->andWhere(
1160
                $qb->expr()->eq('f.extraFieldType', ':extra_field_type')
1161
            );
1162
1163
        if (is_bool($visibleToSelf)) {
1164
            $qb
1165
                ->andWhere($qb->expr()->eq('f.visibleToSelf', ':visibleToSelf'))
1166
                ->setParameter('visibleToSelf', $visibleToSelf);
1167
        }
1168
1169
        if (is_bool($visibleToOthers)) {
1170
            $qb
1171
                ->andWhere($qb->expr()->eq('f.visibleToOthers', ':visibleToOthers'))
1172
                ->setParameter('visibleToOthers', $visibleToOthers);
1173
        }
1174
1175
        $fieldValues = $qb
1176
            ->setParameter('item', $itemId)
1177
            ->setParameter('extra_field_type', $this->getExtraField()->getExtraFieldType())
1178
            ->getQuery()
1179
            ->getResult();
1180
1181
        $fieldOptionsRepo = $em->getRepository('ChamiloCoreBundle:ExtraFieldOptions');
1182
1183
        $valueList = [];
1184
        /** @var ExtraFieldValues $fieldValue */
1185
        foreach ($fieldValues as $fieldValue) {
1186
            $item = ['value' => $fieldValue];
1187
            switch ($fieldValue->getField()->getFieldType()) {
1188
                case ExtraField::FIELD_TYPE_SELECT:
1189
                    $item['option'] = $fieldOptionsRepo->findOneBy([
1190
                        'field' => $fieldValue->getField(),
1191
                        'value' => $fieldValue->getValue(),
1192
                    ]);
1193
                    break;
1194
            }
1195
            $valueList[] = $item;
1196
        }
1197
1198
        return $valueList;
1199
    }
1200
1201
    public function copy($sourceId, $destinationId)
1202
    {
1203
        if (empty($sourceId) || empty($destinationId)) {
1204
            return false;
1205
        }
1206
1207
        $extraField = new ExtraField($this->type);
1208
        $allFields = $extraField->get_all();
1209
        $extraFieldValue = new ExtraFieldValue($this->type);
1210
        foreach ($allFields as $field) {
1211
            $variable = $field['variable'];
1212
            $sourceValues = $extraFieldValue->get_values_by_handler_and_field_variable($sourceId, $variable);
1213
            if (!empty($sourceValues) && isset($sourceValues['value']) && $sourceValues['value'] != '') {
1214
                $params = [
1215
                    'extra_'.$variable => $sourceValues['value'],
1216
                    'item_id' => $destinationId,
1217
                ];
1218
                $extraFieldValue->saveFieldValues($params, true);
1219
            }
1220
        }
1221
1222
        return true;
1223
    }
1224
1225
    /**
1226
     * @return array<int, array<string, string>>
1227
     */
1228
    public static function formatValues(array $extraInfo): array
1229
    {
1230
        $formatted = [];
1231
1232
        foreach ($extraInfo as $extra) {
1233
            /** @var ExtraFieldValues $extraValue */
1234
            $extraValue = $extra['value'];
1235
1236
            $formatted[] = [
1237
                'variable' => $extraValue->getField()->getVariable(),
1238
                'title' => $extraValue->getField()->getDisplayText(),
1239
                'value' => $extraValue->getValue(),
1240
            ];
1241
        }
1242
1243
        return $formatted;
1244
    }
1245
}
1246