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

AdminSearcher::buildSearch()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 19
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 10
c 1
b 0
f 0
nc 2
nop 2
dl 0
loc 19
rs 9.9332
1
<?php declare(strict_types=1);
2
3
namespace Shopware\Elasticsearch\Admin;
4
5
use Elasticsearch\Client;
6
use ONGR\ElasticsearchDSL\Query\Compound\BoolQuery;
7
use ONGR\ElasticsearchDSL\Query\FullText\SimpleQueryStringQuery;
8
use ONGR\ElasticsearchDSL\Search;
9
use Shopware\Core\Framework\Api\Acl\Role\AclRoleDefinition;
10
use Shopware\Core\Framework\Context;
11
use Shopware\Core\Framework\DataAbstractionLayer\Entity;
12
use Shopware\Core\Framework\DataAbstractionLayer\EntityCollection;
13
use Shopware\Core\Framework\Log\Package;
14
15
/**
16
 * @internal
17
 *
18
 * @final
19
 */
20
#[Package('system-settings')]
21
class AdminSearcher
22
{
23
    private Client $client;
24
25
    private AdminSearchRegistry $registry;
26
27
    private AdminElasticsearchHelper $adminEsHelper;
28
29
    public function __construct(Client $client, AdminSearchRegistry $registry, AdminElasticsearchHelper $adminEsHelper)
30
    {
31
        $this->client = $client;
32
        $this->registry = $registry;
33
        $this->adminEsHelper = $adminEsHelper;
34
    }
35
36
    /**
37
     * @param array<string> $entities
38
     *
39
     * @return array<string, array{total: int, data:EntityCollection<Entity>, indexer: string, index: string}>
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<string, array{tota...string, index: string}> at position 12 could not be parsed: Expected '}' at position 12, but found 'EntityCollection'.
Loading history...
40
     */
41
    public function search(string $term, array $entities, Context $context, int $limit = 5): array
42
    {
43
        $index = [];
44
        $term = (string) mb_eregi_replace('\s(or)\s', '|', $term);
45
        $term = (string) mb_eregi_replace('\s(and)\s', ' + ', $term);
46
        $term = (string) mb_eregi_replace('\s(not)\s', ' -', $term);
47
48
        foreach ($entities as $entityName) {
49
            if (!$context->isAllowed($entityName . ':' . AclRoleDefinition::PRIVILEGE_READ)) {
50
                continue;
51
            }
52
53
            $indexer = $this->registry->getIndexer($entityName);
54
            $alias = $this->adminEsHelper->getIndex($indexer->getName());
55
            $index[] = ['index' => $alias];
56
57
            $index[] = $indexer->globalCriteria($term, $this->buildSearch($term, $limit))->toArray();
58
        }
59
60
        $responses = $this->client->msearch(['body' => $index]);
61
62
        $result = [];
63
        foreach ($responses['responses'] as $response) {
64
            if (empty($response['hits']['hits'])) {
65
                continue;
66
            }
67
68
            $index = $response['hits']['hits'][0]['_index'];
69
70
            $result[$index] = [
71
                'total' => $response['hits']['total']['value'],
72
                'hits' => [],
73
            ];
74
75
            foreach ($response['hits']['hits'] as $hit) {
76
                $result[$index]['hits'][] = [
77
                    'id' => $hit['_id'],
78
                    'score' => $hit['_score'],
79
                    'parameters' => $hit['_source']['parameters'],
80
                    'entityName' => $hit['_source']['entityName'],
81
                ];
82
            }
83
        }
84
85
        $mapped = [];
86
        foreach ($result as $index => $values) {
87
            $entityName = $values['hits'][0]['entityName'];
88
            $indexer = $this->registry->getIndexer($entityName);
89
90
            $data = $indexer->globalData($values, $context);
91
            $data['indexer'] = $indexer->getName();
92
            $data['index'] = (string) $index;
93
94
            $mapped[$indexer->getEntity()] = $data;
95
        }
96
97
        return $mapped;
98
    }
99
100
    private function buildSearch(string $term, int $limit): Search
101
    {
102
        $search = new Search();
103
        $splitTerms = explode(' ', $term);
104
        $lastPart = end($splitTerms);
105
106
        // If the end of the search term is not a symbol, apply the prefix search query
107
        if (preg_match('/^[a-zA-Z0-9]+$/', $lastPart)) {
108
            $term = $term . '*';
109
        }
110
111
        $query = new SimpleQueryStringQuery($term, [
112
            'fields' => ['text'],
113
        ]);
114
115
        $search->addQuery($query, BoolQuery::SHOULD);
116
        $search->setSize($limit);
117
118
        return $search;
119
    }
120
}
121