Passed
Push — hans/Index-all-fluent-options ( 33af16...2afa88 )
by Simon
07:48
created

BaseIndexTrait::addFulltextField()   A

Complexity

Conditions 5
Paths 16

Size

Total Lines 21
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 5.0187

Importance

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