Passed
Push — master ( 3655d1...89f7f5 )
by Marco
05:59
created

BaseIndexTrait::addFulltextFields()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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