Passed
Push — trunk ( 325349...f71779 )
by Christian
12:37 queued 16s
created

EsProductDefinition::buildTermQuery()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
nc 1
nop 2
dl 0
loc 3
rs 10
c 1
b 0
f 0
1
<?php declare(strict_types=1);
2
3
namespace Shopware\Elasticsearch\Product;
4
5
use Doctrine\DBAL\ArrayParameterType;
6
use Doctrine\DBAL\Connection;
7
use OpenSearchDSL\Query\Compound\BoolQuery;
8
use Psr\EventDispatcher\EventDispatcherInterface;
9
use Shopware\Core\Content\Product\ProductDefinition;
10
use Shopware\Core\Framework\Context;
11
use Shopware\Core\Framework\DataAbstractionLayer\EntityDefinition;
12
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
13
use Shopware\Core\Framework\Log\Package;
14
use Shopware\Core\Framework\Uuid\Uuid;
15
use Shopware\Core\System\CustomField\CustomFieldTypes;
16
use Shopware\Elasticsearch\Framework\AbstractElasticsearchDefinition;
17
use Shopware\Elasticsearch\Product\Event\ElasticsearchProductCustomFieldsMappingEvent;
18
19
/**
20
 * @internal
21
 *
22
 * @decrecated tag:v6.6.0 - Will be removed, please transfer getMapping and fetch method to ElasticsearchProductDefinition
23
 */
24
#[Package('core')]
25
class EsProductDefinition extends AbstractElasticsearchDefinition
26
{
27
    /**
28
     * @var array<string, string>|null
29
     */
30
    private ?array $customFieldsTypes = null;
31
32
    /**
33
     * @internal
34
     *
35
     * @param array<string, string> $customMapping
36
     */
37
    public function __construct(
38
        private readonly ProductDefinition $definition,
39
        private readonly Connection $connection,
40
        private readonly array $customMapping,
41
        private readonly EventDispatcherInterface $eventDispatcher,
42
        private readonly AbstractProductSearchQueryBuilder $searchQueryBuilder
43
    ) {
44
    }
45
46
    public function getEntityDefinition(): EntityDefinition
47
    {
48
        return $this->definition;
49
    }
50
51
    /**
52
     * {@inheritdoc}
53
     */
54
    public function getMapping(Context $context): array
55
    {
56
        $languageIds = $this->connection->fetchFirstColumn('SELECT LOWER(HEX(`id`)) FROM language');
57
58
        $languageFields = [];
59
        $customFieldsProperties = [];
60
61
        foreach ($languageIds as $languageId) {
62
            $languageFields[$languageId] = self::getTextFieldConfig();
63
            $customFieldsProperties[$languageId] = $this->getCustomFieldsMapping($context);
64
        }
65
66
        $properties = [
67
            'id' => self::KEYWORD_FIELD,
68
            'name' => [
69
                'properties' => $languageFields,
70
            ],
71
            'description' => [
72
                'properties' => $languageFields,
73
            ],
74
            'metaTitle' => [
75
                'properties' => $languageFields,
76
            ],
77
            'metaDescription' => [
78
                'properties' => $languageFields,
79
            ],
80
            'customSearchKeywords' => [
81
                'properties' => $languageFields,
82
            ],
83
            'categories' => [
84
                'type' => 'nested',
85
                'properties' => [
86
                    'id' => self::KEYWORD_FIELD,
87
                    '_count' => self::INT_FIELD,
88
                    'name' => [
89
                        'properties' => $languageFields,
90
                    ],
91
                ],
92
            ],
93
            'manufacturer' => [
94
                'type' => 'nested',
95
                'properties' => [
96
                    'id' => self::KEYWORD_FIELD,
97
                    '_count' => self::INT_FIELD,
98
                    'name' => [
99
                        'properties' => $languageFields,
100
                    ],
101
                ],
102
            ],
103
            'options' => [
104
                'type' => 'nested',
105
                'properties' => [
106
                    'id' => self::KEYWORD_FIELD,
107
                    'groupId' => self::KEYWORD_FIELD,
108
                    '_count' => self::INT_FIELD,
109
                    'name' => [
110
                        'properties' => $languageFields,
111
                    ],
112
                ],
113
            ],
114
            'properties' => [
115
                'type' => 'nested',
116
                'properties' => [
117
                    'id' => self::KEYWORD_FIELD,
118
                    'groupId' => self::KEYWORD_FIELD,
119
                    '_count' => self::INT_FIELD,
120
                    'name' => [
121
                        'properties' => $languageFields,
122
                    ],
123
                ],
124
            ],
125
            'parentId' => self::KEYWORD_FIELD,
126
            'active' => self::BOOLEAN_FIELD,
127
            'available' => self::BOOLEAN_FIELD,
128
            'isCloseout' => self::BOOLEAN_FIELD,
129
            'categoriesRo' => [
130
                'type' => 'nested',
131
                'properties' => [
132
                    'id' => self::KEYWORD_FIELD,
133
                    '_count' => self::INT_FIELD,
134
                ],
135
            ],
136
            'childCount' => self::INT_FIELD,
137
            'autoIncrement' => self::INT_FIELD,
138
            'manufacturerId' => self::KEYWORD_FIELD,
139
            'manufacturerNumber' => self::getTextFieldConfig(),
140
            'displayGroup' => self::KEYWORD_FIELD,
141
            'ean' => self::getTextFieldConfig(),
142
            'height' => self::FLOAT_FIELD,
143
            'length' => self::FLOAT_FIELD,
144
            'markAsTopseller' => self::BOOLEAN_FIELD,
145
            'productNumber' => self::getTextFieldConfig(),
146
            'ratingAverage' => self::FLOAT_FIELD,
147
            'releaseDate' => [
148
                'type' => 'date',
149
                'format' => 'yyyy-MM-dd HH:mm:ss.000||strict_date_optional_time||epoch_millis',
150
                'ignore_malformed' => true,
151
            ],
152
            'createdAt' => [
153
                'type' => 'date',
154
                'format' => 'yyyy-MM-dd HH:mm:ss.000||strict_date_optional_time||epoch_millis',
155
                'ignore_malformed' => true,
156
            ],
157
            'sales' => self::INT_FIELD,
158
            'stock' => self::INT_FIELD,
159
            'availableStock' => self::INT_FIELD,
160
            'shippingFree' => self::BOOLEAN_FIELD,
161
            'taxId' => self::KEYWORD_FIELD,
162
            'tags' => [
163
                'type' => 'nested',
164
                'properties' => [
165
                    'id' => self::KEYWORD_FIELD,
166
                    'name' => self::getTextFieldConfig(),
167
                    '_count' => self::INT_FIELD,
168
                ],
169
            ],
170
            'visibilities' => [
171
                'type' => 'nested',
172
                'properties' => [
173
                    'salesChannelId' => self::KEYWORD_FIELD,
174
                    'visibility' => self::INT_FIELD,
175
                    '_count' => self::INT_FIELD,
176
                ],
177
            ],
178
            'coverId' => self::KEYWORD_FIELD,
179
            'weight' => self::FLOAT_FIELD,
180
            'width' => self::FLOAT_FIELD,
181
            'states' => self::KEYWORD_FIELD,
182
            'customFields' => [
183
                'properties' => $customFieldsProperties,
184
            ],
185
        ];
186
187
        return [
188
            '_source' => ['includes' => ['id', 'autoIncrement']],
189
            'dynamic_templates' => [
190
                [
191
                    'cheapest_price' => [
192
                        'match' => 'cheapest_price_rule*',
193
                        'mapping' => ['type' => 'double'],
194
                    ],
195
                ],
196
                [
197
                    'price_percentage' => [
198
                        'path_match' => 'price.*.percentage.*',
199
                        'mapping' => ['type' => 'double'],
200
                    ],
201
                ],
202
                [
203
                    'long_to_double' => [
204
                        'match_mapping_type' => 'long',
205
                        'mapping' => ['type' => 'double'],
206
                    ],
207
                ],
208
            ],
209
            'properties' => $properties,
210
        ];
211
    }
212
213
    public function buildTermQuery(Context $context, Criteria $criteria): BoolQuery
214
    {
215
        return $this->searchQueryBuilder->build($criteria, $context);
216
    }
217
218
    /**
219
     * {@inheritDoc}
220
     */
221
    public function fetch(array $ids, Context $context): array
222
    {
223
        $data = $this->fetchProducts($ids, $context);
224
        $documents = [];
225
226
        $groupIds = [];
227
228
        foreach ($data as $row) {
229
            foreach (json_decode($row['propertyIds'] ?? '[]', true, 512, \JSON_THROW_ON_ERROR) as $id) {
230
                $groupIds[(string) $id] = true;
231
            }
232
            foreach (json_decode($row['optionIds'] ?? '[]', true, 512, \JSON_THROW_ON_ERROR) as $id) {
233
                $groupIds[(string) $id] = true;
234
            }
235
        }
236
237
        $groups = $this->fetchProperties(\array_keys($groupIds));
238
239
        foreach ($data as $id => $item) {
240
            $visibilities = array_values(array_unique(array_filter(explode('|', $item['visibilities'] ?? ''))));
241
242
            $visibilities = array_map(static function (string $text) {
243
                [$visibility, $salesChannelId] = explode(',', $text);
244
245
                return [
246
                    'visibility' => $visibility,
247
                    'salesChannelId' => $salesChannelId,
248
                    '_count' => 1,
249
                ];
250
            }, $visibilities);
251
252
            $optionIds = json_decode($item['optionIds'] ?? '[]', true, 512, \JSON_THROW_ON_ERROR);
253
            $propertyIds = json_decode($item['propertyIds'] ?? '[]', true, 512, \JSON_THROW_ON_ERROR);
254
            $tagIds = json_decode($item['tagIds'] ?? '[]', true, 512, \JSON_THROW_ON_ERROR);
255
            $categoriesRo = json_decode($item['categoryIds'] ?? '[]', true, 512, \JSON_THROW_ON_ERROR);
256
            $states = json_decode($item['states'] ?? '[]', true, 512, \JSON_THROW_ON_ERROR);
257
            $tags = json_decode($item['tags'] ?? '[]', true, 512, \JSON_THROW_ON_ERROR);
258
            $categories = json_decode($item['categories'] ?? '[]', true, 512, \JSON_THROW_ON_ERROR);
259
            $manufacturers = json_decode($item['manufacturer_translation'] ?? '[]', true, 512, \JSON_THROW_ON_ERROR);
260
            $translations = json_decode($item['translation'] ?? '[]', true, 512, \JSON_THROW_ON_ERROR);
261
            $parentTranslations = json_decode($item['translation_parent'] ?? '[]', true, 512, \JSON_THROW_ON_ERROR);
262
263
            $filteredTags = [];
264
265
            foreach ($tags as $tag) {
266
                if (empty($tag['id'])) {
267
                    continue;
268
                }
269
270
                $filteredTags[] = [
271
                    'id' => $tag['id'],
272
                    'name' => $this->stripText($tag['name'] ?? ''),
273
                    '_count' => 1,
274
                ];
275
            }
276
277
            $document = [
278
                'id' => $id,
279
                'ratingAverage' => (float) $item['ratingAverage'],
280
                'active' => (bool) $item['active'],
281
                'available' => (bool) $item['available'],
282
                'isCloseout' => (bool) $item['isCloseout'],
283
                'shippingFree' => (bool) $item['shippingFree'],
284
                'markAsTopseller' => (bool) $item['markAsTopseller'],
285
                'visibilities' => $visibilities,
286
                'availableStock' => (int) $item['availableStock'],
287
                'productNumber' => $item['productNumber'],
288
                'ean' => $item['ean'],
289
                'displayGroup' => $item['displayGroup'],
290
                'sales' => (int) $item['sales'],
291
                'stock' => (int) $item['stock'],
292
                'weight' => (float) $item['weight'],
293
                'width' => (float) $item['width'],
294
                'length' => (float) $item['length'],
295
                'height' => (float) $item['height'],
296
                'manufacturerId' => $item['productManufacturerId'],
297
                'manufacturerNumber' => $item['manufacturerNumber'],
298
                'releaseDate' => isset($item['releaseDate']) ? (new \DateTime($item['releaseDate']))->format('c') : null,
299
                'createdAt' => isset($item['createdAt']) ? (new \DateTime($item['createdAt']))->format('c') : null,
300
                'categoriesRo' => array_values(array_map(fn (string $categoryId) => ['id' => $categoryId, '_count' => 1], $categoriesRo)),
301
                'optionIds' => $optionIds,
302
                'propertyIds' => $propertyIds,
303
                'taxId' => $item['taxId'],
304
                'tags' => $filteredTags,
305
                'tagIds' => $tagIds,
306
                'parentId' => $item['parentId'],
307
                'coverId' => $item['coverId'],
308
                'childCount' => (int) $item['childCount'],
309
                'categories' => $this->mapToManyAssociations($categories, ['name']),
310
                'manufacturer' => [
311
                    'id' => $item['productManufacturerId'],
312
                    ...$this->mapToOneAssociations($manufacturers, ['name']),
313
                    '_count' => 1,
314
                ],
315
                'states' => $states,
316
            ];
317
318
            if ($item['cheapest_price_accessor']) {
319
                $cheapestPriceAccessor = json_decode($item['cheapest_price_accessor'] ?? '[]', true, 512, \JSON_THROW_ON_ERROR);
320
321
                foreach ($cheapestPriceAccessor as $rule => $cheapestPriceCurrencies) {
322
                    foreach ($cheapestPriceCurrencies as $currency => $taxes) {
323
                        $key = 'cheapest_price_' . $rule . '_' . $currency . '_gross';
324
                        $document[$key] = $taxes['gross'];
325
326
                        $key = 'cheapest_price_' . $rule . '_' . $currency . '_net';
327
                        $document[$key] = $taxes['net'];
328
329
                        if (empty($taxes['percentage'])) {
330
                            continue;
331
                        }
332
333
                        $key = 'cheapest_price_' . $rule . '_' . $currency . '_gross_percentage';
334
                        $document[$key] = $taxes['percentage']['gross'];
335
336
                        $key = 'cheapest_price_' . $rule . '_' . $currency . '_net_percentage';
337
                        $document[$key] = $taxes['percentage']['net'];
338
                    }
339
                }
340
            }
341
342
            $document['name'] = $this->mapTranslatedField('name', true, ...$parentTranslations, ...$translations);
343
            $document['description'] = $this->mapTranslatedField('description', true, ...$parentTranslations, ...$translations);
344
            $document['metaTitle'] = $this->mapTranslatedField('metaTitle', true, ...$parentTranslations, ...$translations);
345
            $document['metaDescription'] = $this->mapTranslatedField('metaDescription', true, ...$parentTranslations, ...$translations);
346
            $document['customSearchKeywords'] = $this->mapTranslatedField('customSearchKeywords', false, ...$parentTranslations, ...$translations);
347
            $document['customFields'] = [];
348
            $customFields = $this->mapTranslatedField('customFields', false, ...$parentTranslations, ...$translations);
349
350
            foreach ($customFields as $languageId => $customField) {
351
                if (empty($customField)) {
352
                    continue;
353
                }
354
355
                // MariaDB servers gives the result as string and not directly decoded
356
                // @codeCoverageIgnoreStart
357
                if (\is_string($customField)) {
358
                    $customField = json_decode($customField, true, 512, \JSON_THROW_ON_ERROR);
359
                }
360
                // @codeCoverageIgnoreEnd
361
362
                $document['customFields'][$languageId] = $this->formatCustomFields($customField ?: [], $context);
363
            }
364
365
            $document['properties'] = array_values(array_map(function (string $propertyId) use ($groups) {
366
                return array_merge([
367
                    'id' => $propertyId,
368
                    '_count' => 1,
369
                ], $groups[$propertyId]);
370
            }, $propertyIds));
371
372
            $document['options'] = array_values(array_map(function (string $optionId) use ($groups) {
373
                return array_merge([
374
                    'id' => $optionId,
375
                    '_count' => 1,
376
                ], $groups[$optionId]);
377
            }, $optionIds));
378
379
            $documents[$id] = $document;
380
        }
381
382
        return $documents;
383
    }
384
385
    /**
386
     * @param array<string> $ids
387
     *
388
     * @return array<string, array<string, string>>
389
     */
390
    private function fetchProducts(array $ids, Context $context): array
391
    {
392
        $sql = <<<'SQL'
393
SELECT
394
    LOWER(HEX(p.id)) AS id,
395
    IFNULL(p.active, pp.active) AS active,
396
    p.available AS available,
397
398
    CONCAT(
399
        '[',
400
        GROUP_CONCAT(DISTINCT
401
                JSON_OBJECT(
402
                    'id', LOWER(HEX(tag.id)),
403
                    'name', tag.name
404
                )
405
            ),
406
        ']'
407
    ) as tags,
408
409
    CONCAT(
410
        '[',
411
            GROUP_CONCAT(DISTINCT
412
                JSON_OBJECT(
413
                    'languageId', LOWER(HEX(product_main.language_id)),
414
                    'name', product_main.name,
415
                    'description', product_main.description,
416
                    'metaTitle', product_main.meta_title,
417
                    'metaDescription', product_main.meta_description,
418
                    'customSearchKeywords', product_main.custom_search_keywords,
419
                    'customFields', product_main.custom_fields
420
                )
421
            ),
422
        ']'
423
    ) as translation,
424
    CONCAT(
425
        '[',
426
            GROUP_CONCAT(DISTINCT
427
                JSON_OBJECT(
428
                    'languageId', LOWER(HEX(product_parent.language_id)),
429
                    'name', product_parent.name,
430
                    'description', product_parent.description,
431
                    'metaTitle', product_parent.meta_title,
432
                    'metaDescription', product_parent.meta_description,
433
                    'customSearchKeywords', product_parent.custom_search_keywords,
434
                    'customFields', product_parent.custom_fields
435
                )
436
            ),
437
        ']'
438
    ) as translation_parent,
439
    CONCAT(
440
        '[',
441
            GROUP_CONCAT(DISTINCT
442
                JSON_OBJECT(
443
                    'id', LOWER(HEX(category_translation.category_id)),
444
                    'languageId', LOWER(HEX(category_translation.language_id)),
445
                    'name', category_translation.name
446
                )
447
            ),
448
        ']'
449
    ) as categories,
450
    CONCAT(
451
        '[',
452
            GROUP_CONCAT(DISTINCT
453
                JSON_OBJECT(
454
                    'name', product_manufacturer_translation.name,
455
                    'id', LOWER(HEX(product_manufacturer_translation.product_manufacturer_id)),
456
                    'languageId', LOWER(HEX(product_manufacturer_translation.language_id))
457
                )
458
            ),
459
        ']'
460
    ) as manufacturer_translation,
461
    IFNULL(p.manufacturer_number, pp.manufacturer_number) AS manufacturerNumber,
462
    IFNULL(p.available_stock, pp.available_stock) AS availableStock,
463
    IFNULL(p.rating_average, pp.rating_average) AS ratingAverage,
464
    p.product_number as productNumber,
465
    p.sales,
466
    LOWER(HEX(IFNULL(p.product_manufacturer_id, pp.product_manufacturer_id))) AS productManufacturerId,
467
    IFNULL(p.shipping_free, pp.shipping_free) AS shippingFree,
468
    IFNULL(p.is_closeout, pp.is_closeout) AS isCloseout,
469
    LOWER(HEX(IFNULL(p.product_media_id, pp.product_media_id))) AS coverId,
470
    IFNULL(p.weight, pp.weight) AS weight,
471
    IFNULL(p.length, pp.length) AS length,
472
    IFNULL(p.height, pp.height) AS height,
473
    IFNULL(p.width, pp.width) AS width,
474
    IFNULL(p.release_date, pp.release_date) AS releaseDate,
475
    IFNULL(p.created_at, pp.created_at) AS createdAt,
476
    IFNULL(p.category_tree, pp.category_tree) AS categoryIds,
477
    IFNULL(p.option_ids, pp.option_ids) AS optionIds,
478
    IFNULL(p.property_ids, pp.property_ids) AS propertyIds,
479
    IFNULL(p.tag_ids, pp.tag_ids) AS tagIds,
480
    LOWER(HEX(IFNULL(p.tax_id, pp.tax_id))) AS taxId,
481
    IFNULL(p.stock, pp.stock) AS stock,
482
    IFNULL(p.ean, pp.ean) AS ean,
483
    IFNULL(p.mark_as_topseller, pp.mark_as_topseller) AS markAsTopseller,
484
    p.auto_increment as autoIncrement,
485
    GROUP_CONCAT(CONCAT(product_visibility.visibility, ',', LOWER(HEX(product_visibility.sales_channel_id))) SEPARATOR '|') AS visibilities,
486
    p.display_group as displayGroup,
487
    IFNULL(p.cheapest_price_accessor, pp.cheapest_price_accessor) as cheapest_price_accessor,
488
    LOWER(HEX(p.parent_id)) as parentId,
489
    p.child_count as childCount,
490
    p.states
491
492
FROM product p
493
    LEFT JOIN product pp ON(p.parent_id = pp.id AND pp.version_id = :liveVersionId)
494
    LEFT JOIN product_visibility ON(product_visibility.product_id = p.visibilities AND product_visibility.product_version_id = p.version_id)
495
    LEFT JOIN product_translation product_main ON product_main.product_id = p.id AND product_main.product_version_id = p.version_id
496
    LEFT JOIN product_translation product_parent ON product_parent.product_id = p.parent_id AND product_parent.product_version_id = p.version_id
497
498
    LEFT JOIN product_manufacturer_translation ON product_manufacturer_translation.product_manufacturer_id = IFNULL(p.product_manufacturer_id, pp.product_manufacturer_id) AND product_manufacturer_translation.product_manufacturer_version_id = p.version_id
499
500
    LEFT JOIN product_tag ON (product_tag.product_id = p.tags AND product_tag.product_version_id = p.version_id)
501
    LEFT JOIN tag ON (tag.id = product_tag.tag_id)
502
503
    LEFT JOIN product_category ON (product_category.product_id = p.categories AND product_category.product_version_id = p.version_id)
504
    LEFT JOIN category_translation ON category_translation.category_id = product_category.category_id AND category_translation.category_version_id = product_category.category_version_id AND category_translation.name IS NOT NULL
505
506
WHERE p.id IN (:ids) AND p.version_id = :liveVersionId AND (p.child_count = 0 OR p.parent_id IS NOT NULL OR JSON_EXTRACT(`p`.`variant_listing_config`, "$.displayParent") = 1)
507
508
GROUP BY p.id
509
SQL;
510
511
        /** @var array<string, array<string, string>> $result */
512
        $result = $this->connection->fetchAllAssociativeIndexed(
513
            $sql,
514
            [
515
                'ids' => Uuid::fromHexToBytesList($ids),
516
                'liveVersionId' => Uuid::fromHexToBytes($context->getVersionId()),
517
            ],
518
            [
519
                'ids' => ArrayParameterType::STRING,
520
            ]
521
        );
522
523
        return $result;
524
    }
525
526
    /**
527
     * @return array<string, mixed>
528
     */
529
    private function getCustomFieldsMapping(Context $context): array
530
    {
531
        $fieldMapping = $this->getCustomFieldTypes($context);
532
        $mapping = [
533
            'type' => 'object',
534
            'dynamic' => true,
535
            'properties' => [],
536
        ];
537
538
        foreach ($fieldMapping as $name => $type) {
539
            /** @var array<mixed> $esType */
540
            $esType = CustomFieldUpdater::getTypeFromCustomFieldType($type);
541
542
            $mapping['properties'][$name] = $esType;
543
        }
544
545
        return $mapping;
546
    }
547
548
    /**
549
     * @param array<string, mixed> $customFields
550
     *
551
     * @return array<string, mixed>
552
     */
553
    private function formatCustomFields(array $customFields, Context $context): array
554
    {
555
        $types = $this->getCustomFieldTypes($context);
556
557
        foreach ($customFields as $name => $customField) {
558
            $type = $types[$name] ?? null;
559
560
            if ($type === null) {
561
                unset($customFields[$name]);
562
563
                continue;
564
            }
565
566
            if ($type === CustomFieldTypes::BOOL) {
567
                $customFields[$name] = (bool) $customField;
568
            } elseif (\is_int($customField)) {
569
                $customFields[$name] = (float) $customField;
570
            }
571
        }
572
573
        return $customFields;
574
    }
575
576
    /**
577
     * @param list<string> $propertyIds
0 ignored issues
show
Bug introduced by
The type Shopware\Elasticsearch\Product\list was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
578
     *
579
     * @return array<string, array{id: string, groupId: string, translations?: string, name: array<int|string, string>}>
580
     */
581
    private function fetchProperties(array $propertyIds): array
582
    {
583
        if (empty($propertyIds)) {
584
            return [];
585
        }
586
587
        $sql = <<<'SQL'
588
SELECT
589
       LOWER(HEX(id)) as id,
590
       LOWER(HEX(property_group_id)) as groupId,
591
       CONCAT(
592
               '[',
593
               GROUP_CONCAT(
594
                       JSON_OBJECT(
595
                               'languageId', lower(hex(property_group_option_translation.language_id)),
596
                               'name', property_group_option_translation.name
597
                           )
598
                   ),
599
               ']'
600
           ) as translations
601
FROM property_group_option
602
         LEFT JOIN property_group_option_translation
603
            ON property_group_option_translation.property_group_option_id = property_group_option.id
604
605
WHERE property_group_option.id in (:ids)
606
GROUP BY property_group_option.id
607
SQL;
608
609
        /** @var array<string, array{id: string, groupId: string, translations: string}> $options */
610
        $options = $this->connection->fetchAllAssociativeIndexed(
611
            $sql,
612
            [
613
                'ids' => Uuid::fromHexToBytesList($propertyIds),
614
            ],
615
            [
616
                'ids' => ArrayParameterType::STRING,
617
            ]
618
        );
619
620
        foreach ($options as $optionId => $option) {
621
            $translation = json_decode($option['translations'] ?? '', true, 512, \JSON_THROW_ON_ERROR);
622
623
            $options[$optionId]['name'] = $option['name'] ?? [];
624
            foreach ($translation as $item) {
625
                $options[$optionId]['name'][$item['languageId']] = $this->stripText($item['name'] ?? '');
626
            }
627
628
            unset($options[$optionId]['translations']);
629
        }
630
631
        return $options;
632
    }
633
634
    /**
635
     * @return array<string, string>
636
     */
637
    private function getCustomFieldTypes(Context $context): array
638
    {
639
        if ($this->customFieldsTypes !== null) {
640
            return $this->customFieldsTypes;
641
        }
642
643
        $event = new ElasticsearchProductCustomFieldsMappingEvent($this->customMapping, $context);
644
        $this->eventDispatcher->dispatch($event);
645
646
        $this->customFieldsTypes = $event->getMappings();
647
648
        return $this->customFieldsTypes;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->customFieldsTypes returns the type null which is incompatible with the type-hinted return array.
Loading history...
649
    }
650
}
651