ExtraFieldValue::getExtraField()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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

191
                        self::/** @scrutinizer ignore-call */ 
192
                              save($newParams, $showQuery);
Loading history...
192
                    }
193
                    break;
194
                case ExtraField::FIELD_TYPE_TAG:
195
                    if (EntityExtraField::USER_FIELD_TYPE == $type) {
196
                        UserManager::delete_user_tags(
197
                            $params['item_id'],
198
                            $extraFieldInfo['id']
199
                        );
200
                        UserManager::process_tags(
201
                            $value,
202
                            $params['item_id'],
203
                            $extraFieldInfo['id']
204
                        );
205
                        break;
206
                    }
207
208
                    $currentTags = $em
209
                        ->getRepository(ExtraFieldRelTag::class)
210
                        ->findBy([
211
                            'field' => $extraFieldInfo['id'],
212
                            'itemId' => $params['item_id'],
213
                        ]);
214
215
                    foreach ($currentTags as $extraFieldtag) {
216
                        $em->remove($extraFieldtag);
217
                    }
218
                    $em->flush();
219
220
                    /** @var \Chamilo\CoreBundle\Entity\ExtraField $fieldEntity */
221
                    $fieldEntity = Container::getExtraFieldRepository()->find($extraFieldInfo['id']);
222
                    $tagRepo = Container::getTagRepository();
223
                    $tagValues = is_array($value) ? $value : [$value];
224
225
                    $tags = [];
226
                    foreach ($tagValues as $tagValue) {
227
                        if (is_array($tagValue)) {
228
                            $tagValue = reset($tagValue);
229
                        }
230
231
                        if (empty($tagValue)) {
232
                            continue;
233
                        }
234
235
                        $tagsResult = $tagRepo->findOneBy(['tag' => $tagValue, 'field' => $fieldEntity]);
236
                        if (null === $tagsResult) {
237
                            $tag = (new Tag())
238
                                ->setField($fieldEntity)
239
                                ->setTag($tagValue)
240
                            ;
241
                            $em->persist($tag);
242
                            $tags[] = $tag;
243
                        } else {
244
                            $tags[] = $tagsResult;
245
                        }
246
                    }
247
                    $em->flush();
248
249
                    if (!empty($tags)) {
250
                        foreach ($tags as $tag) {
251
                            $tagUses = $em
252
                                ->getRepository(ExtraFieldRelTag::class)
253
                                ->findBy([
254
                                    'tag' => $tag,
255
                                ]);
256
257
                            $tag->setCount(count($tagUses) + 1);
258
                            $em->persist($tag);
259
                        }
260
                    }
261
                    $em->flush();
262
263
                    foreach ($tags as $tag) {
264
                        $fieldRelTag = (new ExtraFieldRelTag())
265
                            ->setField($fieldEntity)
266
                            ->setItemId($params['item_id'])
267
                            ->setTag($tag)
268
                        ;
269
                        $em->persist($fieldRelTag);
270
                    }
271
272
                    $em->flush();
273
                    break;
274
                case ExtraField::FIELD_TYPE_FILE_IMAGE:
275
                    $fileName = ExtraField::FIELD_TYPE_FILE_IMAGE."_{$params['item_id']}.png";
276
                    if (!empty($value['tmp_name']) && isset($value['error']) && 0 === (int) $value['error']) {
277
                        $repo = Container::getAssetRepository();
278
                        $asset = (new Asset())
279
                            ->setCategory(Asset::EXTRA_FIELD)
280
                            ->setTitle($fileName)
281
                        ;
282
                        $cropVariable = 'extra_'.$field_variable.'_crop_result';
283
                        if (isset($params[$cropVariable])) {
284
                            $asset->setCrop($params[$cropVariable]);
285
                        }
286
                        $asset = $repo->createFromRequest($asset, $value);
287
                        if ($asset) {
288
                            $field = Container::getExtraFieldRepository()->find($extraFieldInfo['id']);
289
                            $extraFieldValues = (new ExtraFieldValues())
290
                                ->setItemId((int) $params['item_id'])
291
                                ->setField($field)
292
                                ->setFieldValue(1)
293
                                ->setAsset($asset)
294
                                ->setComment($comment ?? '')
295
                            ;
296
                            $em->persist($extraFieldValues);
297
                            $em->flush();
298
                        }
299
                    }
300
                    break;
301
                case ExtraField::FIELD_TYPE_FILE:
302
                    if (isset($value['name']) && !empty($value['tmp_name']) && isset($value['error']) && 0 == $value['error']) {
303
                        $cleanedName = api_replace_dangerous_char($value['name']);
304
                        $cleanedName = disable_dangerous_file($cleanedName);
305
                        $fileName = ExtraField::FIELD_TYPE_FILE."_{$params['item_id']}_$cleanedName";
306
307
                        $mimeType = mime_content_type($value['tmp_name']);
308
                        $file = new UploadedFile($value['tmp_name'], $fileName, $mimeType, null, true);
309
                        $asset = (new Asset())
310
                            ->setCategory(Asset::EXTRA_FIELD)
311
                            ->setTitle($fileName)
312
                            ->setFile($file);
313
314
                        $em->persist($asset);
315
                        $em->flush();
316
                        $assetId = $asset->getId();
317
318
                        if ($assetId) {
319
                            $field = Container::getExtraFieldRepository()->find($extraFieldInfo['id']);
320
                            $extraFieldValues = (new ExtraFieldValues())
321
                                ->setItemId((int) $params['item_id'])
322
                                ->setField($field)
323
                                ->setFieldValue(1)
324
                                ->setAsset($asset)
325
                                ->setComment($comment ?? '')
326
                            ;
327
                            $em->persist($extraFieldValues);
328
                            $em->flush();
329
                        }
330
                    }
331
                    break;
332
                case ExtraField::FIELD_TYPE_CHECKBOX:
333
                    $fieldToSave = 0;
334
                    if (is_array($value)) {
335
                        if (isset($value['extra_'.$field_variable])) {
336
                            $fieldToSave = 1;
337
                        }
338
                    }
339
340
                    $newParams = [
341
                        'item_id' => $params['item_id'],
342
                        'field_id' => $extraFieldInfo['id'],
343
                        'field_value' => $fieldToSave,
344
                        'comment' => $comment,
345
                    ];
346
                    $this->save($newParams);
347
348
                    break;
349
                case ExtraField::FIELD_TYPE_DATE:
350
                    if (is_array($value)) {
351
                        if (empty($value)) {
352
                            break;
353
                        }
354
                        $value = reset($value);
355
                    }
356
357
                    if (is_string($value) && !empty($value)) {
358
                        $d = DateTime::createFromFormat('Y-m-d', $value);
359
                        $valid = $d && $d->format('Y-m-d') === $value;
360
361
                        if ($valid) {
362
                            $newParams = [
363
                                'item_id' => $params['item_id'],
364
                                'field_id' => $extraFieldInfo['id'],
365
                                'field_value' => $value,
366
                                'comment' => $comment,
367
                            ];
368
                            $this->save($newParams, $showQuery);
369
                        }
370
                    }
371
                    break;
372
                case ExtraField::FIELD_TYPE_DATETIME:
373
                    $d = DateTime::createFromFormat('Y-m-d H:i', $value);
374
                    $valid = $d && $d->format('Y-m-d H:i') === $value;
375
                    if ($valid) {
376
                        $newParams = [
377
                            'item_id' => $params['item_id'],
378
                            'field_id' => $extraFieldInfo['id'],
379
                            'field_value' => $value,
380
                            'comment' => $comment,
381
                        ];
382
                        $this->save($newParams, $showQuery);
383
                    }
384
                    break;
385
                default:
386
                    $newParams = [
387
                        'item_id' => $params['item_id'],
388
                        'field_id' => $extraFieldInfo['id'],
389
                        'field_value' => $value,
390
                        'comment' => $comment,
391
                    ];
392
                    $this->save($newParams, $showQuery);
393
            }
394
        }
395
396
        // ofaj
397
        // Set user.profile_completed = 1
398
        /*if ('user' === $this->type) {
399
            if ('true' === api_get_setting('show_terms_if_profile_completed')) {
400
                $justTermResults = [];
401
                foreach ($resultsExist as $term => $value) {
402
                    if (false !== strpos($term, 'terms_')) {
403
                        $justTermResults[$term] = $value;
404
                    }
405
                }
406
407
                $profileCompleted = 0;
408
                if (!in_array(false, $justTermResults)) {
409
                    $profileCompleted = 1;
410
                }
411
412
                $userId = $params['item_id'];
413
414
                // Check if user has a photo
415
                $userInfo = api_get_user_info($userId);
416
                if (empty($userInfo['picture_uri'])) {
417
                    $profileCompleted = 0;
418
                }
419
420
                $table = Database::get_main_table(TABLE_MAIN_USER);
421
                $sql = "UPDATE $table SET profile_completed = $profileCompleted WHERE id = $userId";
422
                Database::query($sql);
423
                Session::write('profile_completed_result', $justTermResults);
424
            }
425
        }*/
426
    }
427
428
    /**
429
     * Save values in the *_field_values table.
430
     *
431
     * @param array $params    Structured array with the values to save
432
     * @param bool  $showQuery Whether to show the insert query (passed to the parent save() method)
433
     *
434
     * @return mixed The result sent from the parent method
435
     * @assert (array()) === false
436
     */
437
    public function save($params, $showQuery = false)
438
    {
439
        $extra_field = $this->getExtraField();
440
441
        // Setting value to insert.
442
        $value = $params['field_value'];
443
        $value_to_insert = null;
444
445
        if (is_array($value)) {
446
            $value_to_insert = implode(';', $value);
447
        } else {
448
            $value_to_insert = $value;
449
        }
450
451
        $params['field_value'] = $value_to_insert;
452
453
        // If field id exists
454
        if (isset($params['field_id'])) {
455
            $extraFieldInfo = $extra_field->get($params['field_id']);
456
        } else {
457
            // Try the variable
458
            $extraFieldInfo = $extra_field->get_handler_field_info_by_field_variable(
459
                $params['variable']
460
            );
461
            if ($extraFieldInfo) {
462
                $params['field_id'] = $extraFieldInfo['id'];
463
            }
464
        }
465
466
        if ($extraFieldInfo) {
467
            switch ($extraFieldInfo['value_type']) {
468
                case ExtraField::FIELD_TYPE_RADIO:
469
                case ExtraField::FIELD_TYPE_SELECT:
470
                    break;
471
                case ExtraField::FIELD_TYPE_SELECT_MULTIPLE:
472
                    //$field_options = $session_field_option->get_field_options_by_field($params['field_id']);
473
                    //$params['field_value'] = split(';', $value_to_insert);
474
                    /*
475
                        if ($field_options) {
476
                            $check = false;
477
                            foreach ($field_options as $option) {
478
                                if (in_array($option['option_value'], $values)) {
479
                                    $check = true;
480
                                    break;
481
                                }
482
                           }
483
                           if (!$check) {
484
                               return false; //option value not found
485
                           }
486
                       } else {
487
                           return false; //enumerated type but no option found
488
                       }*/
489
                    break;
490
                case ExtraField::FIELD_TYPE_TEXT:
491
                case ExtraField::FIELD_TYPE_TEXTAREA:
492
                    break;
493
                case ExtraField::FIELD_TYPE_DOUBLE_SELECT:
494
                case ExtraField::FIELD_TYPE_SELECT_WITH_TEXT_FIELD:
495
                    if (is_array($value)) {
496
                        $value_to_insert = null;
497
                        if (isset($value['extra_'.$extraFieldInfo['variable']]) &&
498
                            isset($value['extra_'.$extraFieldInfo['variable'].'_second'])
499
                        ) {
500
                            $value_to_insert = $value['extra_'.$extraFieldInfo['variable']].'::'.$value['extra_'.$extraFieldInfo['variable'].'_second'];
501
                        }
502
                    }
503
                    break;
504
                default:
505
                    break;
506
            }
507
508
            if (ExtraField::FIELD_TYPE_TAG == $extraFieldInfo['value_type']) {
509
                $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

509
                /** @scrutinizer ignore-call */ 
510
                $field_values = self::getAllValuesByItemAndFieldAndValue(
Loading history...
510
                    $params['item_id'],
511
                    $params['field_id'],
512
                    $value
513
                );
514
            } else {
515
                $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

515
                /** @scrutinizer ignore-call */ 
516
                $field_values = self::get_values_by_handler_and_field_id(
Loading history...
516
                    $params['item_id'],
517
                    $params['field_id']
518
                );
519
            }
520
521
            $params['field_value'] = $value_to_insert;
522
            //$params['author_id'] = api_get_user_id();
523
524
            // Insert
525
            if (empty($field_values)) {
526
                /* Enable this when field_loggeable is introduced as a table field (2.0)
527
                if ($extraFieldInfo['field_loggeable'] == 1) {
528
                */
529
                if (ExtraField::FIELD_TYPE_TAG == $extraFieldInfo['value_type']) {
530
                    $option = new ExtraFieldOption($this->type);
531
                    $optionExists = $option->get($params['field_value']);
532
                    if (empty($optionExists)) {
533
                        $optionParams = [
534
                            'field_id' => $params['field_id'],
535
                            'option_value' => $params['field_value'],
536
                        ];
537
                        $optionId = $option->saveOptions($optionParams);
538
                    } else {
539
                        $optionId = $optionExists['id'];
540
                    }
541
542
                    $params['field_value'] = $optionId;
543
                    if ($optionId) {
544
                        return parent::save($params, $showQuery);
545
                    }
546
                } else {
547
                    return parent::save($params, $showQuery);
548
                }
549
            } else {
550
                // Update
551
                /* Enable this when field_loggeable is introduced as a table field (2.0)
552
                if ($extraFieldInfo['field_loggeable'] == 1) {
553
                */
554
                $params['id'] = $field_values['id'];
555
556
                return parent::update($params, $showQuery);
557
            }
558
        }
559
    }
560
561
    /**
562
     * Returns the value of the given extra field on the given resource.
563
     *
564
     * @param int  $item_id   Item ID (It could be a session_id, course_id or user_id)
565
     * @param int  $field_id  Field ID (the ID from the *_field table)
566
     * @param bool $transform Whether to transform the result to a human readable strings
567
     *
568
     * @return mixed A structured array with the field_id and field_value, or false on error
569
     * @assert (-1,-1) === false
570
     *
571
     * @throws NotSupported
572
     */
573
    public function get_values_by_handler_and_field_id($item_id, $field_id, $transform = false)
574
    {
575
        /** @var ExtraFieldValuesRepository $efvRepo */
576
        $efvRepo = Database::getManager()->getRepository(ExtraFieldValues::class);
577
        /** @var ExtraFieldOptionsRepository $efoRepo */
578
        $efoRepo = Database::getManager()->getRepository(ExtraFieldOptions::class);
579
580
        $results = $efvRepo->getByHandlerAndFieldId(
581
            (int) $item_id,
582
            (int) $field_id,
583
            $this->getExtraField()->getItemType(),
584
            $transform
585
        );
586
587
        if ($results) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $results of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
588
            /** @var ExtraFieldValues $efv */
589
            $efv = current($results);
590
591
            $result = [
592
                'id' => $efv->getId(),
593
                'field_id' => $efv->getField()->getId(),
594
                'asset_id' => $efv->getAsset()?->getId(),
595
                'field_value' => $efv->getFieldValue(),
596
                'item_id' => $efv->getItemId(),
597
                'comment' => $efv->getComment(),
598
                'created_at' => $efv->getCreatedAt()->format('Y-m-d H:i:s'),
599
                'updated_at' => $efv->getUpdatedAt()->format('Y-m-d H:i:s'),
600
                'value_type' => $efv->getField()->getValueType(),
601
            ];
602
603
            if ($transform) {
604
                if (!empty($result['field_value'])) {
605
                    switch ($result['value_type']) {
606
                        case ExtraField::FIELD_TYPE_DOUBLE_SELECT:
607
                            $field_option = new ExtraFieldOption($this->type);
608
                            $options = explode('::', $result['field_value']);
609
                            // only available for PHP 5.4  :( $result['field_value'] = $field_option->get($options[0])['id'].' -> ';
610
                            $result = $field_option->get($options[0]);
611
                            $result_second = $field_option->get($options[1]);
612
                            if (!empty($result)) {
613
                                $result['value'] = $result['display_text'].' -> ';
614
                                $result['value'] .= $result_second['display_text'];
615
                            }
616
                            break;
617
                        case ExtraField::FIELD_TYPE_SELECT_MULTIPLE:
618
                            $optionIds = explode(';', $result['field_value']);
619
                            $optionValues = [];
620
                            $objEfOption = new ExtraFieldOption($this->type);
621
                            $options = $objEfOption->get_field_options_by_field($result['field_id']);
622
                            if (!empty($options)) {
623
                                $options = array_column($options, 'display_text', 'option_value');
624
                            }
625
                            foreach ($optionIds as $option) {
626
                                if (!empty($options) && isset($options[$option])) {
627
                                    $optionValues[] = $options[$option];
628
                                    continue;
629
                                }
630
                                $optionValues[] = $option;
631
                            }
632
633
                            $result['value'] = implode(' <br /> ', $optionValues);
634
                            break;
635
                        case ExtraField::FIELD_TYPE_SELECT:
636
                            $extra_field_option_result = $efoRepo->getFieldOptionByFieldAndOption(
637
                                (int) $result['field_id'],
638
                                (string) $result['field_value'],
639
                                $this->getExtraField()->getItemType()
640
                            );
641
642
                            if ($extra_field_option_result) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $extra_field_option_result of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
643
                                $result['value'] = $extra_field_option_result[0]->getDisplayText();
644
                            }
645
646
                            break;
647
                        case ExtraField::FIELD_TYPE_SELECT_WITH_TEXT_FIELD:
648
                            $options = explode('::', $result['field_value']);
649
                            $field_option = new ExtraFieldOption($this->type);
650
                            $result = $field_option->get($options[0]);
651
652
                            if (!empty($result)) {
653
                                $result['value'] = $result['display_text'].'&rarr;'.$options[1];
654
                            }
655
                            break;
656
                        case ExtraField::FIELD_TYPE_TRIPLE_SELECT:
657
                            $optionIds = explode(';', $result['field_value']);
658
                            $optionValues = [];
659
                            foreach ($optionIds as $optionId) {
660
                                $objEfOption = new ExtraFieldOption($this->type);
661
                                $optionInfo = $objEfOption->get($optionId);
662
                                $optionValues[] = $optionInfo['display_text'];
663
                            }
664
665
                            $result['value'] = implode(' / ', $optionValues);
666
                            break;
667
                    }
668
                }
669
            }
670
671
            return $result;
672
        }
673
674
        return false;
675
    }
676
677
    /**
678
     * @param string $tag
679
     * @param int    $field_id
680
     * @param int    $limit
681
     *
682
     * @return array
683
     */
684
    public function searchValuesByField($tag, $field_id, $limit = 10)
685
    {
686
        $field_id = (int) $field_id;
687
        $limit = (int) $limit;
688
        $tag = Database::escape_string($tag);
689
690
        $extraFieldType = $this->getExtraField()->getItemType();
691
692
        $sql = "SELECT DISTINCT s.field_value, s.field_id
693
                FROM {$this->table} s
694
                INNER JOIN {$this->table_handler_field} sf
695
                ON (s.field_id = sf.id)
696
                WHERE
697
                    field_id = $field_id AND
698
                    field_value LIKE '%$tag%' AND
699
                    sf.item_type = ".$extraFieldType."
700
                ORDER BY field_value
701
                LIMIT 0, $limit
702
                ";
703
        $result = Database::query($sql);
704
        $values = [];
705
        if (Database::num_rows($result)) {
706
            $values = Database::store_result($result, 'ASSOC');
707
        }
708
709
        return $values;
710
    }
711
712
    /**
713
     * Gets a structured array of the original item and its extra values, using
714
     * a specific original item and a field name (like "branch", or "birthdate").
715
     *
716
     * @param int    $item_id            Item ID from the original table
717
     * @param string $field_variable     The name of the field we are looking for
718
     * @param bool   $transform
719
     * @param bool   $filterByVisibility
720
     * @param int    $visibility
721
     *
722
     * @return mixed Array of results, or false on error or not found
723
     * @assert (-1,'') === false
724
     */
725
    public function get_values_by_handler_and_field_variable(
726
        $item_id,
727
        $field_variable,
728
        $transform = false,
729
        $filterByVisibility = false,
730
        $visibility = 0
731
    ) {
732
        $item_id = (int) $item_id;
733
        $field_variable = Database::escape_string($field_variable);
734
        $extraFieldType = $this->getExtraField()->getItemType();
735
736
        $sql = "SELECT s.*, value_type
737
                FROM {$this->table} s
738
                INNER JOIN {$this->table_handler_field} sf
739
                ON (s.field_id = sf.id)
740
                WHERE
741
                    item_id = '$item_id'  AND
742
                    variable = '".$field_variable."' AND
743
                    sf.item_type = $extraFieldType
744
                ";
745
        if ($filterByVisibility) {
746
            $visibility = (int) $visibility;
747
            $sql .= " AND visible_to_self = $visibility ";
748
        }
749
        $sql .= ' ORDER BY id';
750
751
        $repo = Container::getAssetRepository();
752
753
        $result = Database::query($sql);
754
        if (Database::num_rows($result)) {
755
            $result = Database::fetch_assoc($result);
756
            $result['value'] = $result['field_value'];
757
            if ($transform) {
758
                $fieldType = $result['value_type'];
759
                if (ExtraField::FIELD_TYPE_DOUBLE_SELECT == $fieldType) {
760
                    if (!empty($result['field_value'])) {
761
                        $field_option = new ExtraFieldOption($this->type);
762
                        $options = explode('::', $result['field_value']);
763
                        $result = $field_option->get($options[0]);
764
                        $result_second = $field_option->get($options[1]);
765
                        if (!empty($result)) {
766
                            $result['value'] = $result['display_text'].' -> ';
767
                            $result['value'] .= $result_second['display_text'];
768
                        }
769
                    }
770
                }
771
                if (ExtraField::FIELD_TYPE_SELECT_WITH_TEXT_FIELD == $fieldType) {
772
                    if (!empty($result['field_value'])) {
773
                        $options = explode('::', $result['field_value']);
774
                        $field_option = new ExtraFieldOption($this->type);
775
                        $result = $field_option->get($options[0]);
776
                        if (!empty($result)) {
777
                            $result['value'] = $result['display_text']
778
                                .'&rarr;'
779
                                .$options[1];
780
                        }
781
                    }
782
                }
783
                if (ExtraField::FIELD_TYPE_TRIPLE_SELECT == $fieldType) {
784
                    if (!empty($result['field_value'])) {
785
                        $optionIds = explode(';', $result['field_value']);
786
                        $optionValues = [];
787
                        foreach ($optionIds as $optionId) {
788
                            $objEfOption = new ExtraFieldOption('user');
789
                            $optionInfo = $objEfOption->get($optionId);
790
791
                            $optionValues[] = $optionInfo['display_text'];
792
                        }
793
794
                        $result['value'] = implode(' / ', $optionValues);
795
                    }
796
                }
797
798
                if (in_array($result['value_type'], ExtraField::getExtraFieldTypesWithFiles())) {
799
                    $result['url'] = '';
800
                    if (!empty($result['asset_id'])) {
801
                        $asset = $repo->find($result['asset_id']);
802
                        if ($asset) {
803
                            $url = $repo->getAssetUrl($asset);
804
                            $result['url'] = $url;
805
                        }
806
                    }
807
                }
808
            }
809
810
            return $result;
811
        }
812
813
        return false;
814
    }
815
816
    /**
817
     * Gets the ID from the item (course, session, etc) for which
818
     * the given field is defined with the given value.
819
     *
820
     * @param string $variable  Field (type of data) we want to check
821
     * @param string $value     Data we are looking for in the given field
822
     * @param bool   $transform Whether to transform the result to a human readable strings
823
     * @param bool   $last      Whether to return the last element or simply the first one we get
824
     * @param bool   $useLike
825
     *
826
     * @return mixed Give the ID if found, or false on failure or not found
827
     * @assert (-1,-1) === false
828
     */
829
    public function get_item_id_from_field_variable_and_field_value(
830
        $variable,
831
        $value,
832
        $transform = false,
833
        $last = false,
834
        $all = false,
835
        $useLike = false
836
    ) {
837
        $value = Database::escape_string($value);
838
        $variable = Database::escape_string($variable);
839
840
        $valueCondition = " field_value  = '$value' AND ";
841
        if ($useLike) {
842
            $valueCondition = " field_value LIKE '%".$value."%' AND ";
843
        }
844
        $extraFieldType = $this->getExtraField()->getItemType();
845
846
        $sql = "SELECT item_id FROM {$this->table} s
847
                INNER JOIN {$this->table_handler_field} sf
848
                ON (s.field_id = sf.id)
849
                WHERE
850
                    $valueCondition
851
                    variable = '".$variable."' AND
852
                    sf.item_type = $extraFieldType
853
                ORDER BY item_id
854
                ";
855
856
        if ($last) {
857
            // If we want the last element instead of the first
858
            // This is useful in special cases where there might
859
            // (erroneously) be more than one row for an item
860
            $sql .= ' DESC';
861
        }
862
        $result = Database::query($sql);
863
        if (false !== $result && Database::num_rows($result)) {
864
            if ($all) {
865
                $result = Database::store_result($result, 'ASSOC');
866
            } else {
867
                $result = Database::fetch_assoc($result);
868
            }
869
870
            return $result;
871
        }
872
873
        return false;
874
    }
875
876
    /**
877
     * Get all the values stored for one specific field.
878
     *
879
     * @param int $fieldId
880
     *
881
     * @return array|bool
882
     */
883
    public function getValuesByFieldId($fieldId)
884
    {
885
        $fieldId = (int) $fieldId;
886
        $extraFieldType = $this->getExtraField()->getItemType();
887
888
        $sql = "SELECT s.* FROM {$this->table} s
889
                INNER JOIN {$this->table_handler_field} sf
890
                ON (s.field_id = sf.id)
891
                WHERE
892
                    field_id = '".$fieldId."' AND
893
                    sf.item_type = $extraFieldType
894
                ORDER BY s.field_value";
895
        $result = Database::query($sql);
896
897
        if (Database::num_rows($result)) {
898
            return Database::store_result($result, 'ASSOC');
899
        }
900
901
        return false;
902
    }
903
904
    /**
905
     * @param int $itemId
906
     * @param int $fieldId
907
     *
908
     * @return array
909
     */
910
    public function getAllValuesByItemAndField($itemId, $fieldId)
911
    {
912
        $fieldId = (int) $fieldId;
913
        $itemId = (int) $itemId;
914
        $extraFieldType = $this->getExtraField()->getItemType();
915
916
        $sql = "SELECT s.* FROM {$this->table} s
917
                INNER JOIN {$this->table_handler_field} sf
918
                ON (s.field_id = sf.id)
919
                WHERE
920
                    field_id = $fieldId AND
921
                    item_id = $itemId AND
922
                    sf.item_type = $extraFieldType
923
                ORDER BY s.field_value";
924
        $result = Database::query($sql);
925
926
        if (Database::num_rows($result)) {
927
            return Database::store_result($result, 'ASSOC');
928
        }
929
930
        return false;
931
    }
932
933
    /**
934
     * @param int $itemId
935
     *
936
     * @return array
937
     */
938
    public function getAllValuesByItem($itemId)
939
    {
940
        $itemId = (int) $itemId;
941
        $extraFieldType = $this->getExtraField()->getItemType();
942
943
        $sql = "SELECT s.field_value, s.field_value as value, sf.variable, sf.value_type, sf.id, sf.display_text, s.asset_id
944
                FROM {$this->table} s
945
                INNER JOIN {$this->table_handler_field} sf
946
                ON (s.field_id = sf.id)
947
                WHERE
948
                    item_id = '$itemId' AND
949
                    sf.item_type = $extraFieldType
950
                ORDER BY s.field_value";
951
952
        $result = Database::query($sql);
953
        $idList = [];
954
        if (Database::num_rows($result)) {
955
            $result = Database::store_result($result, 'ASSOC');
956
            $finalResult = [];
957
958
            $repo = Container::getAssetRepository();
959
            foreach ($result as $item) {
960
                $fieldType = (int) $item['value_type'];
961
                $item['url'] = '';
962
                if (!empty($item['asset_id']) &&
963
                    in_array($fieldType, ExtraField::getExtraFieldTypesWithFiles(), true)
964
                ) {
965
                    $asset = $repo->find($item['asset_id']);
966
                    if ($asset) {
967
                        $url = $repo->getAssetUrl($asset);
968
                        $item['url'] = $url;
969
                    }
970
                }
971
                $finalResult[$item['id']] = $item;
972
            }
973
            $idList = array_column($result, 'id');
974
        }
975
976
        $em = Database::getManager();
977
978
        $extraField = new ExtraField($this->type);
979
        $allData = $extraField->get_all(['filter = ?' => 1]);
980
        $allResults = [];
981
        foreach ($allData as $field) {
982
            $fieldType = (int) $field['value_type'];
983
            if (in_array($field['id'], $idList)) {
984
                $allResults[] = $finalResult[$field['id']];
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $finalResult does not seem to be defined for all execution paths leading up to this point.
Loading history...
985
            } else {
986
                if (ExtraField::FIELD_TYPE_TAG === $fieldType) {
987
                    $tagResult = [];
988
                    $tags = $em->getRepository(ExtraFieldRelTag::class)
989
                        ->findBy(
990
                            [
991
                                'field' => $field['id'],
992
                                'itemId' => $itemId,
993
                            ]
994
                        );
995
                    if ($tags) {
996
                        /** @var ExtraFieldRelTag $extraFieldTag */
997
                        foreach ($tags as $extraFieldTag) {
998
                            $tag = $extraFieldTag->getTag();
999
                            $tagResult[] = [
1000
                                'id' => $extraFieldTag->getTag()->getId(),
1001
                                'value' => $tag->getTag(),
1002
                            ];
1003
                        }
1004
                    }
1005
                    $allResults[] = [
1006
                        'value' => $tagResult,
1007
                        'variable' => $field['variable'],
1008
                        'value_type' => $field['value_type'],
1009
                        'id' => $field['id'],
1010
                    ];
1011
                }
1012
            }
1013
        }
1014
1015
        return $allResults;
1016
    }
1017
1018
    /**
1019
     * @param int    $itemId
1020
     * @param int    $fieldId
1021
     * @param string $fieldValue
1022
     *
1023
     * @return array|bool
1024
     */
1025
    public function getAllValuesByItemAndFieldAndValue($itemId, $fieldId, $fieldValue)
1026
    {
1027
        $fieldId = (int) $fieldId;
1028
        $itemId = (int) $itemId;
1029
        $extraFieldType = $this->getExtraField()->getItemType();
1030
1031
        $fieldValue = Database::escape_string($fieldValue);
1032
        $sql = "SELECT s.* FROM {$this->table} s
1033
                INNER JOIN {$this->table_handler_field} sf
1034
                ON (s.field_id = sf.id)
1035
                WHERE
1036
                    field_id = '$fieldId' AND
1037
                    item_id = '$itemId' AND
1038
                    field_value = '$fieldValue' AND
1039
                    sf.item_type = $extraFieldType
1040
                ORDER BY field_value";
1041
1042
        $result = Database::query($sql);
1043
        if (Database::num_rows($result)) {
1044
            return Database::store_result($result, 'ASSOC');
1045
        }
1046
1047
        return false;
1048
    }
1049
1050
    /**
1051
     * Deletes all the values related to a specific field ID.
1052
     *
1053
     * @param int $field_id
1054
     *
1055
     * @assert ('a') == null
1056
     */
1057
    public function delete_all_values_by_field_id($field_id)
1058
    {
1059
        $field_id = (int) $field_id;
1060
        $sql = "DELETE FROM {$this->table}
1061
                WHERE
1062
                    field_id = $field_id ";
1063
        Database::query($sql);
1064
    }
1065
1066
    /**
1067
     * Deletes all values from an item.
1068
     *
1069
     * @param int $itemId (session id, course id, etc)
1070
     * @assert (-1,-1) == null
1071
     */
1072
    public function deleteValuesByItem($itemId)
1073
    {
1074
        $itemId = (int) $itemId;
1075
        $extraFieldType = $this->getExtraField()->getItemType();
1076
        $sql = "SELECT DISTINCT fv.id, field_value, value_type FROM {$this->table} fv
1077
                INNER JOIN {$this->table_handler_field} f
1078
                ON (fv.field_id = f.id)
1079
                WHERE item_type = $extraFieldType AND item_id = $itemId";
1080
        $result = Database::query($sql);
1081
        $result = Database::store_result($result, 'ASSOC');
1082
        $em = Database::getManager();
1083
        $repo = Container::getAssetRepository();
1084
        foreach ($result as $item) {
1085
            $valueType = (int) $item['value_type'];
1086
            if (!empty($item['asset_id']) &&
1087
                in_array($valueType, ExtraField::getExtraFieldTypesWithFiles(), true)
1088
            ) {
1089
                $asset = $repo->find($item['asset_id']);
1090
                if ($asset) {
1091
                    $em->remove($asset);
1092
                }
1093
            }
1094
        }
1095
        $em->flush();
1096
1097
        $sql = "DELETE FROM {$this->table}
1098
                WHERE
1099
                    item_id = '$itemId' AND
1100
                    field_id IN (
1101
                        SELECT id FROM {$this->table_handler_field}
1102
                        WHERE item_type = $extraFieldType
1103
                    )
1104
                ";
1105
        Database::query($sql);
1106
    }
1107
1108
    /**
1109
     * @param int        $itemId
1110
     * @param int        $fieldId
1111
     * @param string|int $fieldValue
1112
     *
1113
     * @return bool
1114
     */
1115
    public function deleteValuesByHandlerAndFieldAndValue($itemId, $fieldId, $fieldValue)
1116
    {
1117
        $itemId = (int) $itemId;
1118
        $fieldId = (int) $fieldId;
1119
        $fieldData = $this->getExtraField()->get($fieldId);
1120
        if ($fieldData) {
1121
            $fieldValue = Database::escape_string($fieldValue);
1122
1123
            $sql = "DELETE FROM {$this->table}
1124
                    WHERE
1125
                        item_id = '$itemId' AND
1126
                        field_id = '$fieldId' AND
1127
                        field_value = '$fieldValue'
1128
                    ";
1129
            Database::query($sql);
1130
1131
            // Delete file from uploads.
1132
            if (isset($fieldData['asset_id']) &&
1133
                in_array($fieldData['value_type'], ExtraField::getExtraFieldTypesWithFiles())
1134
            ) {
1135
                $repo = Container::getAssetRepository();
1136
                $asset = $repo->find($fieldData['asset_id']);
1137
                if (null !== $asset) {
1138
                    $repo->delete($asset);
1139
                }
1140
            }
1141
1142
            return true;
1143
        }
1144
1145
        return false;
1146
    }
1147
1148
    /**
1149
     * Get all values for an item.
1150
     *
1151
     * @param int  $itemId          The item ID
1152
     * @param bool $visibleToSelf   Get the visible extra field only
1153
     * @param bool $visibleToOthers
1154
     *
1155
     * @return array
1156
     */
1157
    public function getAllValuesForAnItem($itemId, $visibleToSelf = null, $visibleToOthers = null)
1158
    {
1159
        $em = Database::getManager();
1160
        $qb = $em->createQueryBuilder();
1161
        $qb = $qb->select('fv')
1162
            ->from(ExtraFieldValues::class, 'fv')
1163
            ->join('fv.field', 'f')
1164
            ->where(
1165
                $qb->expr()->eq('fv.itemId', ':item')
1166
            )
1167
            ->andWhere(
1168
                $qb->expr()->eq('f.itemType', ':item_type')
1169
            );
1170
1171
        if (is_bool($visibleToSelf)) {
1172
            $qb
1173
                ->andWhere($qb->expr()->eq('f.visibleToSelf', ':visibleToSelf'))
1174
                ->setParameter('visibleToSelf', $visibleToSelf);
1175
        }
1176
1177
        if (is_bool($visibleToOthers)) {
1178
            $qb
1179
                ->andWhere($qb->expr()->eq('f.visibleToOthers', ':visibleToOthers'))
1180
                ->setParameter('visibleToOthers', $visibleToOthers);
1181
        }
1182
1183
        $fieldValues = $qb
1184
            ->setParameter('item', $itemId)
1185
            ->setParameter('item_type', $this->getExtraField()->getItemType())
1186
            ->getQuery()
1187
            ->getResult();
1188
1189
        $fieldOptionsRepo = $em->getRepository(ExtraFieldOptions::class);
1190
1191
        $valueList = [];
1192
        /** @var ExtraFieldValues $fieldValue */
1193
        foreach ($fieldValues as $fieldValue) {
1194
            $item = ['value' => $fieldValue];
1195
            switch ($fieldValue->getField()->getValueType()) {
1196
                case ExtraField::FIELD_TYPE_SELECT:
1197
                    $item['option'] = $fieldOptionsRepo->findOneBy([
1198
                        'field' => $fieldValue->getField(),
1199
                        'value' => $fieldValue->getFieldValue(),
1200
                    ]);
1201
                    break;
1202
            }
1203
            $valueList[] = $item;
1204
        }
1205
1206
        return $valueList;
1207
    }
1208
1209
    public function copy($sourceId, $destinationId)
1210
    {
1211
        if (empty($sourceId) || empty($destinationId)) {
1212
            return false;
1213
        }
1214
1215
        $extraField = new ExtraField($this->type);
1216
        $allFields = $extraField->get_all();
1217
        $extraFieldValue = new ExtraFieldValue($this->type);
1218
        foreach ($allFields as $field) {
1219
            $variable = $field['variable'];
1220
            $sourceValues = $extraFieldValue->get_values_by_handler_and_field_variable($sourceId, $variable);
1221
            if (!empty($sourceValues) && isset($sourceValues['value']) && '' != $sourceValues['value']) {
1222
                $params = [
1223
                    'extra_'.$variable => $sourceValues['value'],
1224
                    'item_id' => $destinationId,
1225
                ];
1226
                $extraFieldValue->saveFieldValues($params, true);
1227
            }
1228
        }
1229
1230
        return true;
1231
    }
1232
}
1233