Passed
Push — hans/7even ( 430523...f65aef )
by Simon
08:01 queued 06:03
created

BaseIndexTrait::getFilterFields()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
cc 1
nc 1
nop 0
crap 1
1
<?php
2
3
4
namespace Firesphere\SolrSearch\Traits;
5
6
use Firesphere\SolrSearch\Indexes\BaseIndex;
7
use ReflectionClass;
8
use ReflectionException;
9
use SilverStripe\Core\Config\Config;
10
use SilverStripe\Core\Injector\Injector;
11
use SilverStripe\Dev\Deprecation;
12
use SilverStripe\ORM\DataObject;
13
use SilverStripe\ORM\FieldType\DBDate;
14
use SilverStripe\ORM\FieldType\DBString;
15
use Solarium\Core\Client\Client;
16
17
/**
18
 * This is slightly cheating, but it works and also makes things more readable.
19
 *
20
 * This is slightly cheating, but it works and also makes things more readable.
21
 *
22
 * @package Firesphere\SolrSearch\Traits
23
 */
24
trait BaseIndexTrait
25
{
26
    /**
27
     * @var Client Query client
28
     */
29
    protected $client;
30
    /**
31
     * @var array Facet fields
32
     */
33
    protected $facetFields = [];
34
    /**
35
     * @var array Fulltext fields
36
     */
37
    protected $fulltextFields = [];
38
    /**
39
     * @var array Filterable fields
40
     */
41
    protected $filterFields = [];
42
    /**
43
     * @var array Sortable fields
44
     */
45
    protected $sortFields = [];
46
    /**
47
     * @var string Default search field
48
     */
49
    protected $defaultField = '_text';
50
    /**
51
     * @var array Stored fields
52
     */
53
    protected $storedFields = [];
54
    /**
55
     * @var array Fields to copy to the default fields
56
     */
57
    protected $copyFields = [
58
        '_text' => [
59
            '*',
60
        ],
61
    ];
62
    /**
63
     * usedAllFields is used to determine if the addAllFields method has been called
64
     * This is to prevent a notice if there is no yml.
65
     *
66
     * @var bool
67
     */
68
    protected $usedAllFields = false;
69
    /**
70
     * Return the copy fields
71
     *
72
     * @return array
73
     */
74 34
    public function getCopyFields(): array
75
    {
76 34
        return $this->copyFields;
77
    }
78
79
    /**
80
     * Set the copy fields
81
     *
82
     * @param array $copyField
83
     * @return $this
84
     */
85 74
    public function setCopyFields($copyField): self
86
    {
87 74
        $this->copyFields = $copyField;
88
89 74
        return $this;
90
    }
91
92
    /**
93
     * Return the default field for this index
94
     *
95
     * @return string
96
     */
97 35
    public function getDefaultField(): string
98
    {
99 35
        return $this->defaultField;
100
    }
101
102
    /**
103
     * Set the default field for this index
104
     *
105
     * @param string $defaultField
106
     * @return $this
107
     */
108 74
    public function setDefaultField($defaultField): self
109
    {
110 74
        $this->defaultField = $defaultField;
111
112 74
        return $this;
113
    }
114
115
    /**
116
     * Add a field to sort on
117
     *
118
     * @param $sortField
119
     * @return $this
120
     */
121 75
    public function addSortField($sortField): self
122
    {
123 75
        if (!in_array($sortField, $this->getFulltextFields(), true) &&
124 75
            !in_array($sortField, $this->getFilterFields(), true)
125
        ) {
126 1
            $this->addFulltextField($sortField);
127 1
            $this->sortFields[] = $sortField;
128
        }
129
130 75
        $this->setSortFields(array_unique($this->getSortFields()));
131
132 75
        return $this;
133
    }
134
135
    /**
136
     * Get the fulltext fields
137
     *
138
     * @return array
139
     */
140 75
    public function getFulltextFields(): array
141
    {
142 75
        return array_values(
143 75
            array_unique(
144 75
                $this->fulltextFields
145
            )
146
        );
147
    }
148
149
    /**
150
     * Set the fulltext fields
151
     *
152
     * @param array $fulltextFields
153
     * @return $this
154
     */
155 74
    public function setFulltextFields($fulltextFields): self
156
    {
157 74
        $this->fulltextFields = $fulltextFields;
158
159 74
        return $this;
160
    }
161
162
    /**
163
     * Get the filter fields
164
     *
165
     * @return array
166
     */
167 75
    public function getFilterFields(): array
168
    {
169 75
        return $this->filterFields;
170
    }
171
172
    /**
173
     * Set the filter fields
174
     *
175
     * @param array $filterFields
176
     * @return $this
177
     */
178 74
    public function setFilterFields($filterFields): self
179
    {
180 74
        $this->filterFields = $filterFields;
181
182 74
        return $this;
183
    }
184
185
    /**
186
     * Add a single Fulltext field
187
     *
188
     * @param string $fulltextField
189
     * @param null|string $forceType
190
     * @param array $options
191
     * @return $this
192
     */
193 75
    public function addFulltextField($fulltextField, $forceType = null, $options = []): self
194
    {
195 75
        if ($forceType) {
196
            Deprecation::notice('5.0', 'ForceType should be handled through casting');
197
        }
198
199 75
        $key = array_search($fulltextField, $this->getFilterFields(), true);
200
201 75
        if (!$key) {
202 75
            $this->fulltextFields[] = $fulltextField;
203
        }
204
205 75
        if (isset($options['boost'])) {
206 1
            $this->addBoostedField($fulltextField, [], $options['boost']);
207
        }
208
209 75
        if (isset($options['stored'])) {
210 1
            $this->storedFields[] = $fulltextField;
211
        }
212
213 75
        return $this;
214
    }
215
216
    /**
217
     * Add an abstract for the add Boosted Field to keep things consistent
218
     *
219
     * @param string $field
220
     * @param array|int $options
221
     * @param null|int $boost
222
     * @return mixed
223
     */
224
    abstract public function addBoostedField($field, $options = [], $boost = null);
225
226
    /**
227
     * Get the sortable fields
228
     *
229
     * @return array
230
     */
231 75
    public function getSortFields(): array
232
    {
233 75
        return $this->sortFields;
234
    }
235
236
    /**
237
     * Set/override the sortable fields
238
     *
239
     * @param array $sortFields
240
     * @return $this
241
     */
242 75
    public function setSortFields($sortFields): self
243
    {
244 75
        $this->sortFields = $sortFields;
245
246 75
        return $this;
247
    }
248
249
    /**
250
     * Add a Fulltext Field
251
     *
252
     * @param bool $includeSubclasses Compatibility mode, not actually used
253
     * @throws ReflectionException
254
     * @deprecated Please use addAllFulltextFields(). IncludeSubClasses is not used anymore
255
     */
256 1
    public function addFulltextFields($includeSubclasses = true)
257
    {
258 1
        $this->addAllFulltextFields();
259 1
    }
260
261
    /**
262
     * Add all text-type fields to the given index
263
     *
264
     * @throws ReflectionException
265
     */
266 1
    public function addAllFulltextFields()
267
    {
268 1
        $this->addAllFieldsByType(DBString::class);
269 1
    }
270
271
    /**
272
     * Add all database-backed text fields as fulltext searchable fields.
273
     *
274
     * For every class included in the index, examines those classes and all parent looking for "DBText" database
275
     * fields (Varchar, Text, HTMLText, etc) and adds them all as fulltext searchable fields.
276
     *
277
     * Note, there is no check on boosting etc. That needs to be done manually.
278
     *
279
     * @param string $dbType
280
     * @throws ReflectionException
281
     */
282 1
    protected function addAllFieldsByType($dbType = DBString::class): void
283
    {
284 1
        $this->usedAllFields = true;
285 1
        $classes = $this->getClasses();
286 1
        foreach ($classes as $key => $class) {
287 1
            $fields = DataObject::getSchema()->databaseFields($class, true);
288
289 1
            $this->addFulltextFieldsForClass($fields, $dbType);
290
        }
291 1
    }
292
293
    /**
294
     * This trait requires classes to be set, so getClasses can be called.
295
     *
296
     * @return array
297
     */
298
    abstract public function getClasses(): array;
299
300
    /**
301
     * Add all fields of a given type to the index
302
     *
303
     * @param array $fields The fields on the DataObject
304
     * @param string $dbType Class type the reflection should extend
305
     * @throws ReflectionException
306
     */
307 1
    protected function addFulltextFieldsForClass(array $fields, $dbType = DBString::class): void
308
    {
309 1
        foreach ($fields as $field => $type) {
310 1
            $pos = strpos($type, '(');
311 1
            if ($pos !== false) {
312 1
                $type = substr($type, 0, $pos);
313
            }
314 1
            $conf = Config::inst()->get(Injector::class, $type);
315 1
            $ref = new ReflectionClass($conf['class']);
316 1
            if ($ref->isSubclassOf($dbType)) {
317 1
                $this->addFulltextField($field);
318
            }
319
        }
320 1
    }
321
322
    /**
323
     * Add all date-type fields to the given index
324
     *
325
     * @throws ReflectionException
326
     */
327 1
    public function addAllDateFields()
328
    {
329 1
        $this->addAllFieldsByType(DBDate::class);
330 1
    }
331
332
    /**
333
     * Add a facet field
334
     *
335
     * @param $field
336
     * @param array $options
337
     * @return $this
338
     */
339 75
    public function addFacetField($field, $options): self
340
    {
341 75
        $this->facetFields[$field] = $options;
342
343 75
        if (!in_array($options['Field'], $this->getFilterFields(), true)) {
344 75
            $this->addFilterField($options['Field']);
345
        }
346
347 75
        return $this;
348
    }
349
350
    /**
351
     * Add a filterable field
352
     *
353
     * @param $filterField
354
     * @return $this
355
     */
356 75
    public function addFilterField($filterField): self
357
    {
358 75
        $key = array_search($filterField, $this->getFulltextFields(), true);
359 75
        if ($key === false) {
360 75
            $this->filterFields[] = $filterField;
361
        }
362
363 75
        return $this;
364
    }
365
366
    /**
367
     * Add a copy field
368
     *
369
     * @param string $field Name of the copyfield
370
     * @param array $options Array of all fields that should be copied to this copyfield
371
     * @return $this
372
     */
373 1
    public function addCopyField($field, $options): self
374
    {
375 1
        $this->copyFields[$field] = $options;
376
377 1
        return $this;
378
    }
379
380
    /**
381
     * Add a stored/fulltext field
382
     *
383
     * @param string $field
384
     * @param null|string $forceType
385
     * @param array $extraOptions
386
     * @return BaseIndex
387
     */
388 1
    public function addStoredField($field, $forceType = null, $extraOptions = []): self
389
    {
390 1
        $options = array_merge($extraOptions, ['stored' => 'true']);
391 1
        $this->addFulltextField($field, $forceType, $options);
392
393 1
        return $this;
394
    }
395
396
    /**
397
     * Get the client
398
     *
399
     * @return Client
400
     */
401 13
    public function getClient()
402
    {
403 13
        return $this->client;
404
    }
405
406
    /**
407
     * Set/override the client
408
     *
409
     * @param Client $client
410
     * @return $this
411
     */
412 1
    public function setClient($client): self
413
    {
414 1
        $this->client = $client;
415
416 1
        return $this;
417
    }
418
419
    /**
420
     * Get the stored field list
421
     *
422
     * @return array
423
     */
424 34
    public function getStoredFields(): array
425
    {
426 34
        return $this->storedFields;
427
    }
428
429
    /**
430
     * Set/override the stored field list
431
     *
432
     * @param array $storedFields
433
     * @return BaseIndex
434
     */
435 1
    public function setStoredFields(array $storedFields): self
436
    {
437 1
        $this->storedFields = $storedFields;
438
439 1
        return $this;
440
    }
441
}
442