Passed
Push — sheepy/introspection ( cfa448...f64a66 )
by Simon
07:45
created

SchemaService::getStoreFields()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
eloc 8
c 0
b 0
f 0
dl 0
loc 13
ccs 0
cts 0
cp 0
rs 10
cc 2
nc 2
nop 0
crap 6
1
<?php
2
3
4
namespace Firesphere\SolrSearch\Services;
5
6
use Exception;
7
use Firesphere\SolrSearch\Helpers\SearchIntrospection;
8
use Firesphere\SolrSearch\Helpers\Statics;
9
use Firesphere\SolrSearch\Indexes\BaseIndex;
10
use SilverStripe\Control\Director;
11
use SilverStripe\Core\Injector\Injector;
12
use SilverStripe\Core\Manifest\ModuleLoader;
13
use SilverStripe\ORM\ArrayList;
14
use SilverStripe\ORM\FieldType\DBHTMLText;
15
use SilverStripe\View\ViewableData;
16
17
class SchemaService extends ViewableData
18
{
19
20
    /**
21
     * @var bool
22
     */
23
    protected $store = false;
24
    /**
25
     * @var string ABSOLUTE Path to template
26
     */
27
    protected $template;
28
29
    /**
30
     * @var string ABSOLUTE Path to types.ss template
31
     */
32
    protected $typesTemplate;
33
    /**
34
     * @var BaseIndex
35
     */
36
    protected $index;
37
38
    /**
39
     * @var SearchIntrospection
40
     */
41
    protected $introspection;
42
43
    /**
44
     * @var SolrCoreService
45
     */
46
    protected $coreService;
47
48
    /**
49
     * SchemaService constructor.
50 14
     */
51
    public function __construct()
52 14
    {
53 14
        parent::__construct();
54 14
        $this->introspection = Injector::inst()->get(SearchIntrospection::class);
55 14
        $this->coreService = Injector::inst()->get(SolrCoreService::class);
56
    }
57
58
    /**
59
     * @return BaseIndex
60 1
     */
61
    public function getIndex()
62 1
    {
63
        return $this->index;
64
    }
65
66
    /**
67
     * @param BaseIndex $index
68
     * @return SchemaService
69 14
     */
70
    public function setIndex($index)
71 14
    {
72
        $this->index = $index;
73
        // Add the index to the introspection as well, there's no need for a separate call here
74 14
        // We're loading this core, why would we want the introspection from a different index?
75
        $this->introspection->setIndex($index);
76 14
77
        return $this;
78
    }
79
80
    /**
81
     * @return string
82 5
     */
83
    public function getIndexName()
84 5
    {
85
        return $this->index->getIndexName();
86
    }
87
88
    /**
89
     * @return string
90 5
     */
91
    public function getDefaultField()
92 5
    {
93
        return $this->index->getDefaultField();
94
    }
95
96
    /**
97
     * Get the Identifier Field for Solr
98
     *
99
     * @return string
100 4
     */
101
    public function getIDField()
102 4
    {
103
        return SolrCoreService::ID_FIELD;
104
    }
105
106
    /**
107
     * Get the Identifier Field for Solr
108
     *
109
     * @return string
110 4
     */
111
    public function getClassID()
112 4
    {
113
        return SolrCoreService::CLASS_ID_FIELD;
114
    }
115
116
    /**
117
     * @return ArrayList
118
     * @throws Exception
119 4
     */
120
    public function getFulltextFieldDefinitions()
121 4
    {
122 4
        $return = ArrayList::create();
123 4
        $store = $this->store;
124
        $this->store = true;
125
        foreach ($this->index->getFulltextFields() as $field) {
126 4
            $this->getFieldDefinition($field, $return);
127
        }
128
129
        $this->store = $store;
130
131
        return $return;
132
    }
133
134
    /**
135 4
     * @param $fieldName
136
     * @param ArrayList $return
137 4
     * @param null|string $copyField
138 4
     * @throws Exception
139 4
     */
140 4
    protected function getFieldDefinition($fieldName, &$return, $copyField = null)
141
    {
142 4
        $field = $this->introspection->getFieldIntrospection($fieldName);
143 4
        $typeMap = Statics::getTypeMap();
144
        $storeFields = $this->getStoreFields();
145 4
        foreach ($field as $name => $options) {
146
            // Temporary short-name solution until the Introspection is properly solved
147 4
            $name = explode('\\', $name);
148 4
            $name = end($name);
149 4
            // Boosted fields are always stored
150 4
            $store = ($this->store || array_key_exists($field['name'], $storeFields)) ? 'true' : 'false';
151 4
            $item = [
152 4
                'Field'       => $name,
153
                'Type'        => $typeMap[$options['type']],
154 4
                'Indexed'     => 'true',
155
                'Stored'      => $options['store'] ?? $store,
156 4
                'MultiValued' => $options['multi_valued'] ? 'true' : 'false',
157
                'Destination' => $copyField
158
            ];
159
            $return->push($item);
160
        }
161 4
    }
162
163 4
    /**
164
     * @return ArrayList
165 4
     */
166 4
    public function getCopyFields()
167
    {
168 4
        $fields = $this->index->getCopyFields();
169
170
        $return = ArrayList::create();
171 4
        foreach ($fields as $field => $copyFields) {
172
            $item = [
173
                'Field' => $field
174 4
            ];
175
176
            $return->push($item);
177
        }
178
179
        return $return;
180
    }
181 4
182
    /**
183 4
     * @return ArrayList
184
     * @throws Exception
185 4
     */
186
    public function getCopyFieldDefinitions()
187 4
    {
188
        $copyFields = $this->index->getCopyFields();
189 4
190 4
        $return = ArrayList::create();
191
192
        foreach ($copyFields as $field => $fields) {
193 4
            // Allow all fields to be in a copyfield via a shorthand
194 4
            if ($fields[0] === '*') {
195
                $fields = $this->index->getFulltextFields();
196
            }
197
198 4
            foreach ($fields as $copyField) {
199
                $this->getFieldDefinition($copyField, $return, $field);
200
            }
201
        }
202
203
        return $return;
204
    }
205 4
206
    /**
207 4
     * @return ArrayList
208 4
     * @throws Exception
209 4
     */
210 4
    public function getFilterFieldDefinitions()
211 4
    {
212
        $return = ArrayList::create();
213
        $originalStore = $this->store;
214 4
        $this->store = Director::isDev() ? true : false;
215
        $fields = $this->index->getFilterFields();
216 4
        foreach ($this->index->getFacetFields() as $facetField) {
217
            $fields[] = $facetField['Field'];
218
        }
219
        $fields = array_unique($fields);
220
        foreach ($fields as $field) {
221
            $this->getFieldDefinition($field, $return);
222 4
        }
223
224 4
        $this->store = $originalStore;
225 4
226 4
        return $return;
227 4
    }
228 4
229
    /**
230
     * @return DBHTMLText
231 4
     */
232
    public function getTypes()
233
    {
234
        if (!$this->typesTemplate) {
235
            $solrVersion = $this->coreService->getSolrVersion();
236
            $dir = ModuleLoader::getModule('firesphere/solr-search')->getPath();
237 4
            $template = sprintf('%s/Solr/%s/templates/types.ss', $dir, $solrVersion);
238
            $this->setTypesTemplate($template);
239 4
        }
240
241
        return $this->renderWith($this->getTypesTemplate());
242
    }
243
244
    /**
245
     * @return string
246 4
     */
247
    public function getTypesTemplate()
248 4
    {
249
        return $this->typesTemplate;
250 4
    }
251
252
    /**
253
     * @param string $typesTemplate
254
     * @return SchemaService
255
     */
256 13
    public function setTypesTemplate($typesTemplate)
257
    {
258 13
        $this->typesTemplate = $typesTemplate;
259 4
260 4
        return $this;
261 4
    }
262 4
263
    /**
264
     * @return DBHTMLText
265 13
     */
266
    public function generateSchema()
267
    {
268
        if (!$this->template) {
269
            $solrVersion = $this->coreService->getSolrVersion();
270
            $dir = ModuleLoader::getModule('firesphere/solr-search')->getPath();
271 13
            $template = sprintf('%s/Solr/%s/templates/schema.ss', $dir, $solrVersion);
272
            $this->setTemplate($template);
273 13
        }
274
275
        return $this->renderWith($this->getTemplate());
276
    }
277
278
    /**
279
     * @return string
280 4
     */
281
    public function getTemplate()
282 4
    {
283
        return $this->template;
284 4
    }
285
286
    /**
287
     * @param string $template
288
     * @return SchemaService
289
     */
290 13
    public function setTemplate($template)
291
    {
292
        $this->template = $template;
293 13
294
        return $this;
295 13
    }
296 13
297
    /**
298 13
     * @return string
299
     */
300
    public function getExtrasPath()
301
    {
302
        // @todo configurable but with default to the current absolute path
303
        $dir = ModuleLoader::getModule('firesphere/solr-search')->getPath();
304 14
305
        $confDirs = SolrCoreService::config()->get('paths');
306 14
        $solrVersion = $this->coreService->getSolrVersion();
307 14
308
        return sprintf($confDirs[$solrVersion]['extras'], $dir);
309
    }
310
311
    /**
312
     * @param bool $store
313
     */
314
    public function setStore(bool $store): void
315
    {
316
        $this->store = $store;
317
    }
318
319
    /**
320
     * @return array
321
     */
322
    protected function getStoreFields(): array
323
    {
324
        $boostedFields = $this->index->getBoostedFields();
325
        $storedFields = $this->index->getStoredFields();
326
        $facetFields = $this->index->getFacetFields();
327
        $facetArray = [];
328
        foreach ($facetFields as $key => $facetField) {
329
            $facetArray[] = $key . '.' . $facetField['Field'];
330
        }
331
        // Boosts, facets and obviously stored fields need to be stored
332
        $storeFields = array_merge($storedFields, array_keys($boostedFields), $facetArray);
333
334
        return $storeFields;
335
    }
336
}
337