Passed
Pull Request — hans/guzzle-to-psr (#261)
by
unknown
21:06
created

BaseIndexTrait::setFilterFields()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

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