Passed
Push — main ( 5a4aff...d40937 )
by Simon
01:12
created

BaseIndexTrait::setCopyFields()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 5
rs 10
1
<?php
2
3
namespace Firesphere\ElasticSearch\Traits\IndexTraits;
4
5
use Elastic\Elasticsearch\Client;
6
use ReflectionClass;
7
use ReflectionException;
8
use SilverStripe\Core\Config\Config;
9
use SilverStripe\Core\Injector\Injector;
10
use SilverStripe\Dev\Deprecation;
11
use SilverStripe\ORM\DataObject;
12
use SilverStripe\ORM\FieldType\DBDate;
13
use SilverStripe\ORM\FieldType\DBString;
14
15
trait BaseIndexTrait
16
{
17
    /**
18
     * @var Client Query client
19
     */
20
    protected $client;
21
    /**
22
     * @var array Facet fields
23
     */
24
    protected $facetFields = [];
25
    /**
26
     * @var array Fulltext fields
27
     */
28
    protected $fulltextFields = [];
29
    /**
30
     * @var array Filterable fields
31
     */
32
    protected $filterFields = [];
33
    /**
34
     * @var array Sortable fields
35
     */
36
    protected $sortFields = [];
37
    /**
38
     * @var array Stored fields
39
     */
40
    protected $storedFields = [];
41
42
    /**
43
     * usedAllFields is used to determine if the addAllFields method has been called
44
     * This is to prevent a notice if there is no yml.
45
     *
46
     * @var bool
47
     */
48
    protected $usedAllFields = false;
49
50
    /**
51
     * Add a field to sort on
52
     *
53
     * @param $sortField
54
     * @return $this
55
     */
56
    public function addSortField($sortField): self
57
    {
58
        if (!in_array($sortField, $this->getFulltextFields(), true) &&
59
            !in_array($sortField, $this->getFilterFields(), true)
60
        ) {
61
            $this->addFulltextField($sortField);
62
            $this->sortFields[] = $sortField;
63
        }
64
65
        $this->setSortFields(array_unique($this->getSortFields()));
66
67
        return $this;
68
    }
69
70
    /**
71
     * Get the fulltext fields
72
     *
73
     * @return array
74
     */
75
    public function getFulltextFields(): array
76
    {
77
        return array_values(
78
            array_unique(
79
                $this->fulltextFields
80
            )
81
        );
82
    }
83
84
    /**
85
     * Set the fulltext fields
86
     *
87
     * @param array $fulltextFields
88
     * @return $this
89
     */
90
    public function setFulltextFields($fulltextFields): self
91
    {
92
        $this->fulltextFields = $fulltextFields;
93
94
        return $this;
95
    }
96
97
    /**
98
     * Get the filter fields
99
     *
100
     * @return array
101
     */
102
    public function getFilterFields(): array
103
    {
104
        return $this->filterFields;
105
    }
106
107
    /**
108
     * Set the filter fields
109
     *
110
     * @param array $filterFields
111
     * @return $this
112
     */
113
    public function setFilterFields($filterFields): self
114
    {
115
        $this->filterFields = $filterFields;
116
117
        return $this;
118
    }
119
120
    /**
121
     * Add a single Fulltext field
122
     *
123
     * @param string $fulltextField
124
     * @param null|string $forceType
125
     * @param array $options
126
     * @return $this
127
     */
128
    public function addFulltextField($fulltextField, $forceType = null, $options = []): self
129
    {
130
        if ($forceType) {
131
            Deprecation::notice('5.0', 'ForceType should be handled through casting');
132
        }
133
134
        $key = array_search($fulltextField, $this->getFilterFields(), true);
135
136
        if (!$key) {
137
            $this->fulltextFields[] = $fulltextField;
138
        }
139
140
        if (isset($options['boost'])) {
141
            $this->addBoostedField($fulltextField, [], $options['boost']);
0 ignored issues
show
Bug introduced by
It seems like addBoostedField() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

141
            $this->/** @scrutinizer ignore-call */ 
142
                   addBoostedField($fulltextField, [], $options['boost']);
Loading history...
142
        }
143
144
        if (isset($options['stored'])) {
145
            $this->storedFields[] = $fulltextField;
146
        }
147
148
        return $this;
149
    }
150
151
    /**
152
     * Get the sortable fields
153
     *
154
     * @return array
155
     */
156
    public function getSortFields(): array
157
    {
158
        return $this->sortFields;
159
    }
160
161
    /**
162
     * Set/override the sortable fields
163
     *
164
     * @param array $sortFields
165
     * @return $this
166
     */
167
    public function setSortFields($sortFields): self
168
    {
169
        $this->sortFields = $sortFields;
170
171
        return $this;
172
    }
173
174
    /**
175
     * Add all text-type fields to the given index
176
     *
177
     * @throws ReflectionException
178
     */
179
    public function addAllFulltextFields()
180
    {
181
        $this->addAllFieldsByType(DBString::class);
182
    }
183
184
    /**
185
     * Add all database-backed text fields as fulltext searchable fields.
186
     *
187
     * For every class included in the index, examines those classes and all parent looking for "DBText" database
188
     * fields (Varchar, Text, HTMLText, etc) and adds them all as fulltext searchable fields.
189
     *
190
     * Note, there is no check on boosting etc. That needs to be done manually.
191
     *
192
     * @param string $dbType
193
     * @throws ReflectionException
194
     */
195
    protected function addAllFieldsByType($dbType = DBString::class): void
196
    {
197
        $this->usedAllFields = true;
198
        $classes = $this->getClasses();
199
        foreach ($classes as $key => $class) {
200
            $fields = DataObject::getSchema()->databaseFields($class, true);
201
202
            $this->addFulltextFieldsForClass($fields, $dbType);
203
        }
204
    }
205
206
    /**
207
     * This trait requires classes to be set, so getClasses can be called.
208
     *
209
     * @return array
210
     */
211
    abstract public function getClasses(): array;
212
213
    /**
214
     * Add all fields of a given type to the index
215
     *
216
     * @param array $fields The fields on the DataObject
217
     * @param string $dbType Class type the reflection should extend
218
     * @throws ReflectionException
219
     */
220
    protected function addFulltextFieldsForClass(array $fields, $dbType = DBString::class): void
221
    {
222
        foreach ($fields as $field => $type) {
223
            $pos = strpos($type, '(');
224
            if ($pos !== false) {
225
                $type = substr($type, 0, $pos);
226
            }
227
            $conf = Config::inst()->get(Injector::class, $type);
228
            $ref = new ReflectionClass($conf['class']);
229
            if ($ref->isSubclassOf($dbType)) {
230
                $this->addFulltextField($field);
231
            }
232
        }
233
    }
234
235
    /**
236
     * Add all date-type fields to the given index
237
     *
238
     * @throws ReflectionException
239
     */
240
    public function addAllDateFields()
241
    {
242
        $this->addAllFieldsByType(DBDate::class);
243
    }
244
245
    /**
246
     * Add a facet field
247
     *
248
     * @param $field
249
     * @param array $options
250
     * @return $this
251
     */
252
    public function addFacetField($field, $options): self
253
    {
254
        $this->facetFields[$field] = $options;
255
256
        if (!in_array($options['Field'], $this->getFilterFields(), true)) {
257
            $this->addFilterField($options['Field']);
258
        }
259
260
        return $this;
261
    }
262
263
    /**
264
     * Add a filterable field
265
     *
266
     * @param $filterField
267
     * @return $this
268
     */
269
    public function addFilterField($filterField): self
270
    {
271
        $key = array_search($filterField, $this->getFulltextFields(), true);
272
        if ($key === false) {
273
            $this->filterFields[] = $filterField;
274
        }
275
276
        return $this;
277
    }
278
279
    public function getClient(): Client
280
    {
281
        return $this->client;
282
    }
283
284
    public function setClient(Client $client): void
285
    {
286
        $this->client = $client;
287
    }
288
}
289