Passed
Push — master ( 57afe5...ecb4e1 )
by Gordon
04:50 queued 02:24
created

Searcher::refactorKeyName()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 5
c 1
b 0
f 0
nc 3
nop 1
dl 0
loc 10
rs 10
1
<?php declare(strict_types = 1);
2
3
/**
4
 * Created by PhpStorm.
5
 * User: gordon
6
 * Date: 25/3/2561
7
 * Time: 1:35 น.
8
 */
9
10
namespace Suilven\ManticoreSearch\Service;
11
12
use Manticoresearch\Search;
13
use SilverStripe\ORM\ArrayList;
14
use SilverStripe\ORM\DataObject;
15
use Suilven\FreeTextSearch\Container\SearchResults;
16
use Suilven\FreeTextSearch\Indexes;
17
18
class Searcher extends \Suilven\FreeTextSearch\Base\Searcher implements \Suilven\FreeTextSearch\Interfaces\Searcher
19
{
20
    /** @var \Suilven\ManticoreSearch\Service\Client */
21
    private $client;
22
23
    public function __construct()
24
    {
25
        $this->client = new Client();
26
    }
27
28
29
    public function search(?string $q): SearchResults
30
    {
31
        $startTime = \microtime(true);
32
        $client = new Client();
33
        $manticoreClient = $client->getConnection();
34
35
        $searcher = new Search($manticoreClient);
36
        $searcher->setIndex($this->indexName);
37
38
        $searcher->limit($this->pageSize);
39
        $offset=$this->pageSize * ($this->page-1);
40
        $searcher->offset($offset);
41
42
        $indexes = new Indexes();
43
        $index = $indexes->getIndex($this->indexName);
44
45
        $searcher->highlight(
46
            [],
47
            ['pre_tags' => '<b>', 'post_tags'=>'</b>']
48
        );
49
50
        $q = \is_null($q)
51
            ? ''
52
            : $q;
53
54
        $manticoreResult = $searcher->search($q)->get();
55
        $allFields = $this->getAllFields($index);
56
57
58
        $ssResult = new ArrayList();
59
        while ($manticoreResult->valid()) {
60
            $hit = $manticoreResult->current();
61
            $source = $hit->getData();
62
            $ssDataObject = new DataObject();
63
64
            $this->populateSearchResult($ssDataObject, $allFields, $source);
65
66
            // manticore lowercases fields, so as above normalize them back to the SS fieldnames
67
            $highlights = $hit->getHighlight();
68
            $fieldsToHighlight = $index->getHighlightedFields();
69
            $this->addHighlights($ssDataObject, $allFields, $highlights, $fieldsToHighlight);
70
71
            $ssDataObject->ID = $hit->getId();
72
            $ssResult->push($ssDataObject);
73
            $manticoreResult->next();
74
        }
75
76
        // we now need to standardize the output returned
77
78
        $searchResults = new SearchResults();
79
        $searchResults->setRecords($ssResult);
80
        $searchResults->setPage($this->page);
81
        $searchResults->setPageSize($this->pageSize);
82
        $searchResults->setQuery($q);
83
        $searchResults->setTotalNumberOfResults($manticoreResult->getTotal());
84
85
        $endTime = \microtime(true);
86
        $delta = $endTime - $startTime;
87
        $delta = \round(1000*$delta)/1000;
88
        $searchResults->setTime($delta);
89
90
        return $searchResults;
91
    }
92
93
94
    /** @return array<string> */
95
    public function getAllFields(\Suilven\FreeTextSearch\Index $index): array
96
    {
97
        $allFields = \array_merge(
98
            $index->getFields(),
99
            $index->getTokens(),
100
            //$index->getHasManyFields(),
101
            $index->getHasOneFields(),
102
            $index->getStoredFields()
103
        );
104
105
        $hasManyFields = $index->getHasManyFields();
106
        foreach (\array_keys($hasManyFields) as $key) {
107
            $allFields[] = $key;
108
        }
109
110
        return $allFields;
111
    }
112
113
114
    public function refactorKeyName(string $keyname): string
115
    {
116
        // @todo This is a hack as $Title is rendering the ID in the template
117
        if ($keyname === 'Title') {
118
            $keyname = 'ResultTitle';
119
        } elseif ($keyname === 'link') {
120
            $keyname = 'Link';
121
        };
122
123
        return $keyname;
124
    }
125
126
127
    /** @param array<string> $allFields */
128
    public function matchKey(string $key, array $allFields): string
129
    {
130
        $keyname = $key;
131
        foreach ($allFields as $field) {
132
            if (\strtolower($field) === $key) {
133
                $keyname = $field;
134
135
                break;
136
            }
137
        }
138
139
        return $keyname;
140
    }
141
142
143
    /**
144
     * @param array<string> $allFields
145
     * @param array<string, string|int|float|bool> $source
146
     */
147
    private function populateSearchResult(DataObject &$ssDataObject, array $allFields, array $source): void
148
    {
149
        $keys = \array_keys($source);
150
        foreach ($keys as $key) {
151
            /** @var string $keyname */
152
            $keyname = $this->matchKey($key, $allFields);
153
            $keyname = $this->refactorKeyName($keyname);
154
155
            /** @phpstan-ignore-next-line */
156
            $ssDataObject->$keyname = $source[$key];
157
        }
158
    }
159
160
161
    /**
162
     * @param array<string> $allFields
163
     * @param array<array<string>> $highlights
164
     * @param array<string> $fieldsToHighlight
165
     */
166
    private function addHighlights(
167
        DataObject &$ssDataObject,
168
        array $allFields,
169
        array $highlights,
170
        array $fieldsToHighlight
171
    ): void {
172
        $highlightsSS = [];
173
174
        $keys = \array_keys($highlights);
175
        foreach ($keys as $key) {
176
            if (!isset($highlights[$key]) || !\in_array($key, $fieldsToHighlight, true)) {
177
                continue;
178
            }
179
            $keyname = $key;
180
            foreach ($allFields as $field) {
181
                if (\strtolower($field) === $key) {
182
                    $keyname = $field;
183
184
                    continue;
185
                }
186
            }
187
188
            if ($key === 'link') {
189
                $keyname = 'Link';
190
            }
191
192
            $highlightsSS[$keyname] = $highlights[$key];
193
        }
194
195
        /** @phpstan-ignore-next-line */
196
        $ssDataObject->Highlights = $highlightsSS;
197
    }
198
}
199