Passed
Push — hans/bugfixes ( 402e83...d21958 )
by Simon
04:46
created

SchemaService::getStoreFields()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 2

Importance

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