Passed
Pull Request — master (#194)
by Simon
15:12 queued 06:36
created

SchemaService   A

Complexity

Total Complexity 25

Size/Duplication

Total Lines 236
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 6
Bugs 0 Features 0
Metric Value
eloc 82
c 6
b 0
f 0
dl 0
loc 236
ccs 89
cts 89
cp 1
rs 10
wmc 25

11 Methods

Rating   Name   Duplication   Size   Complexity  
A getFulltextFieldDefinitions() 0 14 2
A getTypes() 0 6 1
A getCopyFieldDefinitions() 0 18 4
A getBaseTemplatePath() 0 11 2
A getCopyFields() 0 16 2
A getFilterFieldDefinitions() 0 19 4
A getFieldDefinition() 0 23 5
A getExtrasPath() 0 3 1
A getStoreFields() 0 13 2
A generateSchema() 0 6 1
A __construct() 0 6 1
1
<?php
2
/**
3
 * class SchemaService|Firesphere\SolrSearch\Services\SchemaService Base service for generating a schema
4
 *
5
 * @package Firesphere\SolrSearch\Services
6
 * @author Simon `Firesphere` Erkelens; Marco `Sheepy` Hermo
7
 * @copyright Copyright (c) 2018 - now() Firesphere & Sheepy
8
 */
9
10
namespace Firesphere\SolrSearch\Services;
11
12
use Exception;
13
use Firesphere\SolrSearch\Helpers\FieldResolver;
14
use Firesphere\SolrSearch\Helpers\Statics;
15
use Firesphere\SolrSearch\Traits\GetSetSchemaServiceTrait;
16
use SilverStripe\Control\Director;
17
use SilverStripe\Core\Injector\Injector;
18
use SilverStripe\Core\Manifest\ModuleLoader;
19
use SilverStripe\Dev\Debug;
20
use SilverStripe\ORM\ArrayList;
21
use SilverStripe\ORM\FieldType\DBHTMLText;
22
use SilverStripe\View\ViewableData;
23
24
/**
25
 * Class SchemaService
26
 *
27
 * @package Firesphere\SolrSearch\Services
28
 */
29
class SchemaService extends ViewableData
30
{
31
    use GetSetSchemaServiceTrait;
32
33
    /**
34
     * The field resolver to find a field for a class
35
     *
36
     * @var FieldResolver
37
     */
38
    protected $fieldResolver;
39
    /**
40
     * CoreService to use
41
     *
42
     * @var SolrCoreService
43
     */
44
    protected $coreService;
45
    /**
46
     * @var string Base path to the template
47
     */
48
    protected $baseTemplatePath;
49 78
50
    /**
51 78
     * SchemaService constructor.
52 78
     */
53 78
    public function __construct()
54 78
    {
55
        parent::__construct();
56
        $this->fieldResolver = Injector::inst()->get(FieldResolver::class);
57
        $this->coreService = Injector::inst()->get(SolrCoreService::class);
58
        $this->baseTemplatePath = ModuleLoader::getModule('firesphere/solr-search')->getPath();
59
    }
60
61
    /**
62 35
     * Get all fulltext field definitions that are loaded
63
     *
64 35
     * @return ArrayList
65 35
     * @throws Exception
66 35
     */
67 35
    public function getFulltextFieldDefinitions()
68 35
    {
69
        $return = ArrayList::create();
70
        $store = $this->store;
71 35
        $this->setStore(true);
72
        foreach ($this->index->getFulltextFields() as $field) {
73 35
            $this->getFieldDefinition($field, $return);
74
        }
75 35
76
        $this->extend('onBeforeFulltextFields', $return);
77
78
        $this->setStore($store);
79
80
        return $return;
81
    }
82
83
    /**
84
     * Get the field definition for a single field
85
     *
86 35
     * @param $fieldName
87
     * @param ArrayList $return
88 35
     * @param null|string $copyField
89 35
     * @throws Exception
90 35
     */
91 35
    protected function getFieldDefinition($fieldName, &$return, $copyField = null)
92 35
    {
93
        $field = $this->fieldResolver->resolveField($fieldName);
94 35
        $typeMap = Statics::getTypeMap();
95
        $storeFields = $this->getStoreFields();
96 35
        $item = [];
97
        foreach ($field as $name => $options) {
98 35
            // Temporary short-name solution until the Introspection is properly solved
99 35
            $name = getShortFieldName($name);
100 35
            // Boosted fields are always stored
101 35
            $store = ($this->store || array_key_exists($options['name'], $storeFields)) ? 'true' : 'false';
102 35
            $item = [
103 35
                'Field'       => $name,
104
                'Type'        => $typeMap[$options['type']],
105 35
                'Indexed'     => 'true',
106
                'Stored'      => $options['store'] ?? $store,
107
                'MultiValued' => $options['multi_valued'] ? 'true' : 'false',
108 35
                'Destination' => $copyField,
109 35
            ];
110
            $return->push($item);
111
        }
112
113
        $this->extend('onAfterFieldDefinition', $return, $item);
114
    }
115
116 35
    /**
117
     * Get the stored fields. This includes boosted and faceted fields
118 35
     *
119 35
     * @return array
120 35
     */
121 35
    protected function getStoreFields(): array
122 35
    {
123 35
        $boostedFields = $this->index->getBoostedFields();
124
        $storedFields = $this->index->getStoredFields();
125
        $facetFields = $this->index->getFacetFields();
126 35
        $facetArray = [];
127
        foreach ($facetFields as $key => $facetField) {
128 35
            $facetArray[] = $key . '.' . $facetField['Field'];
129
        }
130
        // Boosts, facets and obviously stored fields need to be stored
131
        $storeFields = array_merge($storedFields, array_keys($boostedFields), $facetArray);
132
133
        return $storeFields;
134
    }
135
136 35
    /**
137
     * Get the fields that should be copied
138 35
     *
139
     * @return ArrayList
140 35
     */
141 35
    public function getCopyFields()
142
    {
143 35
        $fields = $this->index->getCopyFields();
144
145
        $return = ArrayList::create();
146 35
        foreach ($fields as $field => $copyFields) {
147
            $item = [
148
                'Field' => $field,
149 35
            ];
150
151 35
            $return->push($item);
152
        }
153
154
        $this->extend('onBeforeCopyFields', $return);
155
156
        return $return;
157
    }
158
159
    /**
160 35
     * Get the definition of a copy field for determining what to load in to Solr
161
     *
162 35
     * @return ArrayList
163
     * @throws Exception
164 35
     */
165
    public function getCopyFieldDefinitions()
166 35
    {
167
        $copyFields = $this->index->getCopyFields();
168 35
169 35
        $return = ArrayList::create();
170
171
        foreach ($copyFields as $field => $fields) {
172 35
            // Allow all fields to be in a copyfield via a shorthand
173 35
            if ($fields[0] === '*') {
174
                $fields = $this->index->getFulltextFields();
175
            }
176
177 35
            foreach ($fields as $copyField) {
178
                $this->getFieldDefinition($copyField, $return, $field);
179
            }
180
        }
181
182
        return $return;
183
    }
184
185
    /**
186 35
     * Get the definitions of a filter field to load in to Solr.
187
     *
188 35
     * @return ArrayList
189 35
     * @throws Exception
190
     */
191 35
    public function getFilterFieldDefinitions()
192 35
    {
193 35
        $return = ArrayList::create();
194 35
        $originalStore = $this->store;
195
        // Always store every field in dev mode
196 35
        $this->setStore(Director::isDev() ? true : $this->store);
197 35
        $fields = $this->index->getFilterFields();
198 35
        foreach ($this->index->getFacetFields() as $facetField) {
199
            $fields[] = $facetField['Field'];
200 35
        }
201
        $fields = array_unique($fields);
202 35
        foreach ($fields as $field) {
203
            $this->getFieldDefinition($field, $return);
204 35
        }
205
        $this->extend('onBeforeFilterFields', $return);
206
207
        $this->setStore($originalStore);
208
209
        return $return;
210
    }
211
212 35
    /**
213
     * Get the types template in a rendered state
214 35
     *
215 35
     * @return DBHTMLText
216 35
     */
217 35
    public function getTypes()
218 35
    {
219
        $template = $this->getBaseTemplatePath();
220
        $this->setTypesTemplate($template . '/types.ss');
221 35
222
        return $this->renderWith($this->getTypesTemplate());
223
    }
224
225
    /**
226
     * Generate the Schema xml
227
     *
228
     * @return DBHTMLText
229 35
     */
230
    public function generateSchema()
231 35
    {
232 35
        $template = $this->getBaseTemplatePath();
233 35
        $this->setTemplate($template . '/schema.ss');
234 35
235 35
        return $this->renderWith($this->getTemplate());
236
    }
237
238 35
    /**
239
     * Get any extras that need loading in to Solr
240
     *
241
     * @return string
242
     */
243
    public function getExtrasPath()
244
    {
245
        return $this->getBaseTemplatePath('extras');
246 35
    }
247
248
    /**
249 35
     * Get the base path of the template given
250
     *
251 35
     * @param string $type What type of templates do we need to get
252 35
     * @return string
253
     */
254 35
    protected function getBaseTemplatePath($type = 'templates'): string
255
    {
256
        $templatePath = SolrCoreService::config()->get('paths');
257
        $customPath = $templatePath['base_path'] ?? false;
258
        if ($customPath) {
259
            $this->baseTemplatePath = sprintf($customPath, Director::baseFolder());
260
        }
261
262
        $solrVersion = $this->coreService->getSolrVersion();
263
264
        return sprintf($templatePath[$solrVersion][$type], $this->baseTemplatePath);
265
    }
266
}
267