Passed
Push — main ( 5528ce...f6374d )
by Simon
01:16
created

BaseIndexTrait   A

Complexity

Total Complexity 29

Size/Duplication

Total Lines 302
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 61
c 2
b 0
f 0
dl 0
loc 302
rs 10
wmc 29

20 Methods

Rating   Name   Duplication   Size   Complexity  
A getSortFields() 0 3 1
A addAllDateFields() 0 3 1
A addFulltextField() 0 5 1
A addAllFulltextFields() 0 3 1
A setFulltextFields() 0 5 1
A addFulltextFieldsForClass() 0 11 4
A setFilterFields() 0 8 2
A addFacetField() 0 9 2
A setSortFields() 0 8 2
A setFacetFields() 0 7 2
A getFacetFields() 0 3 1
A addSortField() 0 6 1
A addAllFieldsByType() 0 8 2
A getFulltextFields() 0 5 1
A getFilterFields() 0 3 1
A getClient() 0 3 1
A addFilterField() 0 6 1
A setStoredFields() 0 8 2
A setClient() 0 3 1
A getStoredFields() 0 3 1
1
<?php
2
/**
3
 * Trait BaseIndexTrait|Firesphere\ElasticSearch\Traits\BaseIndexTrait Used to extract methods from the
4
 * {@link \Firesphere\ElasticSearch\Indexes\ElasticIndex} to make the code more readable
5
 *
6
 * @package Firesphere\Elastic\Search
7
 * @author Simon `Firesphere` Erkelens; Marco `Sheepy` Hermo
8
 * @copyright Copyright (c) 2018 - now() Firesphere & Sheepy
9
 */
10
11
namespace Firesphere\ElasticSearch\Traits\IndexTraits;
12
13
use Elastic\Elasticsearch\Client;
14
use Firesphere\SearchBackend\Indexes\CoreIndex;
15
use ReflectionClass;
16
use ReflectionException;
17
use SilverStripe\Core\Config\Config;
18
use SilverStripe\Core\Injector\Injector;
19
use SilverStripe\Dev\Deprecation;
20
use SilverStripe\ORM\DataObject;
21
use SilverStripe\ORM\FieldType\DBDate;
22
use SilverStripe\ORM\FieldType\DBString;
23
24
/**
25
 * Trait ElasticIndexTrait
26
 * Getters and Setters for the ElasticIndex
27
 *
28
 * @package Firesphere\Elastic\Search
29
 */
30
trait BaseIndexTrait
31
{
32
    /**
33
     * @var Client Query client
34
     */
35
    protected $client;
36
    /**
37
     * @var array Facet fields
38
     */
39
    protected $facetFields = [];
40
    /**
41
     * @var array Fulltext fields
42
     */
43
    protected $fulltextFields = [];
44
    /**
45
     * @var array Filterable fields
46
     */
47
    protected $filterFields = [];
48
    /**
49
     * @var array Sortable fields
50
     */
51
    protected $sortFields = [];
52
    /**
53
     * @var array Stored fields
54
     */
55
    protected $storedFields = [];
56
57
    /**
58
     * usedAllFields is used to determine if the addAllFields method has been called
59
     * This is to prevent a notice if there is no yml.
60
     *
61
     * @var bool
62
     */
63
    protected $usedAllFields = false;
64
65
    /**
66
     * Add a field to sort on
67
     *
68
     * @param $sortField
69
     * @return $this
70
     */
71
    public function addSortField($sortField): self
72
    {
73
        $this->addFulltextField($sortField);
74
        $this->sortFields[] = $sortField;
75
76
        return $this;
77
    }
78
79
    /**
80
     * Get the fulltext fields
81
     *
82
     * @return array
83
     */
84
    public function getFulltextFields(): array
85
    {
86
        return array_values(
87
            array_unique(
88
                $this->fulltextFields
89
            )
90
        );
91
    }
92
93
    /**
94
     * Set the fulltext fields
95
     *
96
     * @param array $fulltextFields
97
     * @return $this
98
     */
99
    public function setFulltextFields($fulltextFields): self
100
    {
101
        $this->fulltextFields = $fulltextFields;
102
103
        return $this;
104
    }
105
106
    /**
107
     * Get the filter fields
108
     *
109
     * @return array
110
     */
111
    public function getFilterFields(): array
112
    {
113
        return $this->filterFields;
114
    }
115
116
    /**
117
     * Set the filter fields
118
     *
119
     * @param array $filterFields
120
     * @return $this
121
     */
122
    public function setFilterFields($filterFields): self
123
    {
124
        $this->filterFields = $filterFields;
125
        foreach ($filterFields as $filterField) {
126
            $this->addFulltextField($filterField);
127
        }
128
129
        return $this;
130
    }
131
132
    /**
133
     * Add a single Fulltext field
134
     *
135
     * @param string $fulltextField
136
     * @param array $options
137
     * @return $this
138
     */
139
    public function addFulltextField($fulltextField, $options = []): self
0 ignored issues
show
Unused Code introduced by
The parameter $options is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

139
    public function addFulltextField($fulltextField, /** @scrutinizer ignore-unused */ $options = []): self

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
140
    {
141
        $this->fulltextFields[] = $fulltextField;
142
143
        return $this;
144
    }
145
146
    /**
147
     * Get the sortable fields
148
     *
149
     * @return array
150
     */
151
    public function getSortFields(): array
152
    {
153
        return $this->sortFields;
154
    }
155
156
    /**
157
     * Set/override the sortable fields
158
     *
159
     * @param array $sortFields
160
     * @return $this
161
     */
162
    public function setSortFields($sortFields): self
163
    {
164
        $this->sortFields = $sortFields;
165
        foreach ($sortFields as $sortField) {
166
            $this->addFulltextField($sortField);
167
        }
168
169
        return $this;
170
    }
171
172
    /**
173
     * Add all text-type fields to the given index
174
     *
175
     * @throws ReflectionException
176
     */
177
    public function addAllFulltextFields()
178
    {
179
        $this->addAllFieldsByType(DBString::class);
180
    }
181
182
    /**
183
     * Add all database-backed text fields as fulltext searchable fields.
184
     *
185
     * For every class included in the index, examines those classes and all parent looking for "DBText" database
186
     * fields (Varchar, Text, HTMLText, etc) and adds them all as fulltext searchable fields.
187
     *
188
     * Note, there is no check on boosting etc. That needs to be done manually.
189
     *
190
     * @param string $dbType
191
     * @throws ReflectionException
192
     */
193
    protected function addAllFieldsByType($dbType = DBString::class): void
194
    {
195
        $this->usedAllFields = true;
196
        $classes = $this->getClasses();
197
        foreach ($classes as $key => $class) {
198
            $fields = DataObject::getSchema()->databaseFields($class, true);
199
200
            $this->addFulltextFieldsForClass($fields, $dbType);
201
        }
202
    }
203
204
    /**
205
     * This trait requires classes to be set, so getClasses can be called.
206
     *
207
     * @return array
208
     */
209
    abstract public function getClasses(): array;
210
211
    /**
212
     * Add all fields of a given type to the index
213
     *
214
     * @param array $fields The fields on the DataObject
215
     * @param string $dbType Class type the reflection should extend
216
     * @throws ReflectionException
217
     */
218
    protected function addFulltextFieldsForClass(array $fields, $dbType = DBString::class): void
219
    {
220
        foreach ($fields as $field => $type) {
221
            $pos = strpos($type, '(');
222
            if ($pos !== false) {
223
                $type = substr($type, 0, $pos);
224
            }
225
            $conf = Config::inst()->get(Injector::class, $type);
226
            $ref = new ReflectionClass($conf['class']);
227
            if ($ref->isSubclassOf($dbType)) {
228
                $this->addFulltextField($field);
229
            }
230
        }
231
    }
232
233
    /**
234
     * Add all date-type fields to the given index
235
     *
236
     * @throws ReflectionException
237
     */
238
    public function addAllDateFields()
239
    {
240
        $this->addAllFieldsByType(DBDate::class);
241
    }
242
243
    /**
244
     * Set the fields to use for faceting
245
     * @param $fields
246
     * @return $this
247
     */
248
    public function setFacetFields($fields)
249
    {
250
        foreach ($fields as $field => $option) {
251
            $this->addFacetField($field, $option);
252
        }
253
254
        return $this;
255
    }
256
257
    /**
258
     * Add a facet field
259
     *
260
     * @param $field
261
     * @param array $options
262
     * @return $this
263
     */
264
    public function addFacetField($field, $options)
265
    {
266
        $this->facetFields[$field] = $options;
267
268
        if (!in_array($options['Field'], $this->getFulltextFields(), true)) {
269
            $this->addFulltextField($options['Field']);
270
        }
271
272
        return $this;
273
    }
274
275
    /**
276
     * @return array
277
     */
278
    public function getFacetFields()
279
    {
280
        return $this->facetFields;
281
    }
282
283
    /**
284
     * Add a filterable field
285
     * Compatibility stub for Solr
286
     *
287
     * @param $filterField
288
     * @return $this
289
     */
290
    public function addFilterField($filterField): self
291
    {
292
        $this->filterFields[] = $filterField;
293
        $this->addFulltextField($filterField);
294
295
        return $this;
296
    }
297
298
    /**
299
     * @return Client
300
     */
301
    public function getClient(): Client
302
    {
303
        return $this->client;
304
    }
305
306
    public function setClient(Client $client): void
307
    {
308
        $this->client = $client;
309
    }
310
311
    /**
312
     * @return array
313
     */
314
    public function getStoredFields(): array
315
    {
316
        return $this->storedFields;
317
    }
318
319
    /**
320
     * Stub to be compatible with Solr. Elastic stores everything anyway
321
     * @param array $storedFields
322
     * @return $this
323
     */
324
    public function setStoredFields(array $storedFields)
325
    {
326
        $this->storedFields = $storedFields;
327
        foreach ($storedFields as $storedField) {
328
            $this->addFulltextField($storedField);
329
        }
330
331
        return $this;
332
    }
333
}
334