Passed
Push — 6.4 ( be76f2...e19c4d )
by Christian
14:08 queued 13s
created

ProductAdminSearchIndexer::getName()   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
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
1
<?php declare(strict_types=1);
2
3
namespace Shopware\Elasticsearch\Admin\Indexer;
4
5
use Doctrine\DBAL\Connection;
6
use ONGR\ElasticsearchDSL\Query\Compound\BoolQuery;
7
use ONGR\ElasticsearchDSL\Query\FullText\SimpleQueryStringQuery;
8
use ONGR\ElasticsearchDSL\Search;
9
use Shopware\Core\Content\Product\ProductDefinition;
10
use Shopware\Core\Defaults;
11
use Shopware\Core\Framework\Context;
12
use Shopware\Core\Framework\DataAbstractionLayer\Dbal\Common\IterableQuery;
13
use Shopware\Core\Framework\DataAbstractionLayer\Dbal\Common\IteratorFactory;
14
use Shopware\Core\Framework\DataAbstractionLayer\Entity;
15
use Shopware\Core\Framework\DataAbstractionLayer\EntityCollection;
16
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
17
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
18
use Shopware\Core\Framework\Log\Package;
19
use Shopware\Core\Framework\Plugin\Exception\DecorationPatternException;
20
use Shopware\Core\Framework\Uuid\Uuid;
21
22
/**
23
 * @internal
24
 */
25
#[Package('system-settings')]
26
final class ProductAdminSearchIndexer extends AbstractAdminIndexer
27
{
28
    private Connection $connection;
29
30
    private IteratorFactory $factory;
31
32
    private EntityRepository $repository;
33
34
    private int $indexingBatchSize;
35
36
    public function __construct(
37
        Connection $connection,
38
        IteratorFactory $factory,
39
        EntityRepository $repository,
40
        int $indexingBatchSize
41
    ) {
42
        $this->connection = $connection;
43
        $this->factory = $factory;
44
        $this->repository = $repository;
45
        $this->indexingBatchSize = $indexingBatchSize;
46
    }
47
48
    public function getDecorated(): AbstractAdminIndexer
49
    {
50
        throw new DecorationPatternException(self::class);
51
    }
52
53
    public function getEntity(): string
54
    {
55
        return ProductDefinition::ENTITY_NAME;
56
    }
57
58
    public function getName(): string
59
    {
60
        return 'product-listing';
61
    }
62
63
    public function getIterator(): IterableQuery
64
    {
65
        return $this->factory->createIterator($this->getEntity(), null, $this->indexingBatchSize);
66
    }
67
68
    /**
69
     * @param array<string, mixed> $result
70
     *
71
     * @return array{total:int, data:EntityCollection<Entity>}
0 ignored issues
show
Documentation Bug introduced by
The doc comment array{total:int, data:EntityCollection<Entity>} at position 8 could not be parsed: Expected '}' at position 8, but found 'EntityCollection'.
Loading history...
72
     */
73
    public function globalData(array $result, Context $context): array
74
    {
75
        $ids = array_column($result['hits'], 'id');
76
        $criteria = new Criteria($ids);
77
        $criteria->addAssociations(['options.group']);
78
79
        return [
80
            'total' => (int) $result['total'],
81
            'data' => $this->repository->search($criteria, $context)->getEntities(),
82
        ];
83
    }
84
85
    public function globalCriteria(string $term, Search $criteria): Search
86
    {
87
        $splitTerms = explode(' ', $term);
88
        $lastPart = end($splitTerms);
89
90
        // If the end of the search term is not a symbol, apply the prefix search query
91
        if (preg_match('/^[a-zA-Z0-9]+$/', $lastPart)) {
92
            $term = $term . '*';
93
        }
94
95
        $query = new SimpleQueryStringQuery($term, [
96
            'fields' => ['textBoosted'],
97
            'boost' => 10,
98
        ]);
99
100
        $criteria->addQuery($query, BoolQuery::SHOULD);
101
102
        return $criteria;
103
    }
104
105
    /**
106
     * @param array<string>|array<int, array<string>> $ids
107
     *
108
     * @throws \Doctrine\DBAL\Exception
109
     *
110
     * @return array<int|string, array<string, mixed>>
111
     */
112
    public function fetch(array $ids): array
113
    {
114
        $data = $this->connection->fetchAllAssociative(
115
            '
116
            SELECT LOWER(HEX(product.id)) as id,
117
                   GROUP_CONCAT(DISTINCT translation.name) as name,
118
                   CONCAT("[", GROUP_CONCAT(translation.custom_search_keywords), "]") as custom_search_keywords,
119
                   GROUP_CONCAT(DISTINCT tag.name) as tags,
120
                   product.product_number,
121
                   product.ean,
122
                   product.manufacturer_number
123
            FROM product
124
                INNER JOIN product_translation AS translation
125
                    ON product.id = translation.product_id AND product.version_id = translation.product_version_id
126
                LEFT JOIN product_tag
127
                    ON product.id = product_tag.product_id AND product.version_id = product_tag.product_version_id
128
                LEFT JOIN tag
129
                    ON product_tag.tag_id = tag.id
130
            WHERE product.id IN (:ids)
131
            AND product.version_id = :versionId
132
            GROUP BY product.id
133
        ',
134
            [
135
                'ids' => Uuid::fromHexToBytesList($ids),
136
                'versionId' => Uuid::fromHexToBytes(Defaults::LIVE_VERSION),
137
            ],
138
            [
139
                'ids' => Connection::PARAM_STR_ARRAY,
140
            ]
141
        );
142
143
        $mapped = [];
144
        foreach ($data as $row) {
145
            $textBoosted = $row['name'] . ' ' . $row['product_number'];
146
147
            if ($row['custom_search_keywords']) {
148
                $row['custom_search_keywords'] = json_decode($row['custom_search_keywords'], true);
149
                $textBoosted = $textBoosted . ' ' . implode(' ', array_unique(array_merge(...$row['custom_search_keywords'])));
150
            }
151
152
            $id = $row['id'];
153
            unset($row['name'],  $row['product_number'], $row['custom_search_keywords']);
154
            $text = \implode(' ', array_filter(array_unique(array_values($row))));
155
            $mapped[$id] = ['id' => $id, 'textBoosted' => \strtolower($textBoosted), 'text' => \strtolower($text)];
156
        }
157
158
        return $mapped;
159
    }
160
}
161