Passed
Push — hans/searchhistory ( a34d75 )
by Simon
06:36
created

BaseIndexTrait::setHistory()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

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