Passed
Push — hans/bugfixes ( 9cef69...39db1b )
by Simon
02:35
created

SchemaService::setBaseTemplatePath()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
c 0
b 0
f 0
nc 1
nop 2
dl 0
loc 5
ccs 3
cts 3
cp 1
crap 1
rs 10
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 array Base paths 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
    }
58
59
    /**
60
     * Get all fulltext field definitions that are loaded
61
     *
62
     * @return ArrayList
63
     * @throws Exception
64
     */
65 35
    public function getFulltextFieldDefinitions()
66
    {
67 35
        $return = ArrayList::create();
68 35
        $store = $this->store;
69 35
        $this->setStore(true);
70 35
        foreach ($this->index->getFulltextFields() as $field) {
71 35
            $this->getFieldDefinition($field, $return);
72
        }
73
74 35
        $this->extend('onBeforeFulltextFields', $return);
75
76 35
        $this->setStore($store);
77
78 35
        return $return;
79
    }
80
81
    /**
82
     * Get the field definition for a single field
83
     *
84
     * @param $fieldName
85
     * @param ArrayList $return
86
     * @param null|string $copyField
87
     * @throws Exception
88
     */
89 35
    protected function getFieldDefinition($fieldName, &$return, $copyField = null)
90
    {
91 35
        $field = $this->fieldResolver->resolveField($fieldName);
92 35
        $typeMap = Statics::getTypeMap();
93 35
        $storeFields = $this->getStoreFields();
94 35
        $item = [];
95 35
        foreach ($field as $name => $options) {
96
            // Temporary short-name solution until the Introspection is properly solved
97 35
            $name = getShortFieldName($name);
98
            // Boosted fields are always stored
99 35
            $store = ($this->store || array_key_exists($options['name'], $storeFields)) ? 'true' : 'false';
100
            $item = [
101 35
                'Field'       => $name,
102 35
                'Type'        => $typeMap[$options['type']],
103 35
                'Indexed'     => 'true',
104 35
                'Stored'      => $options['store'] ?? $store,
105 35
                'MultiValued' => $options['multi_valued'] ? 'true' : 'false',
106 35
                'Destination' => $copyField,
107
            ];
108 35
            $return->push($item);
109
        }
110
111 35
        $this->extend('onAfterFieldDefinition', $return, $item);
112 35
    }
113
114
    /**
115
     * Get the stored fields. This includes boosted and faceted fields
116
     *
117
     * @return array
118
     */
119 35
    protected function getStoreFields(): array
120
    {
121 35
        $boostedFields = $this->index->getBoostedFields();
122 35
        $storedFields = $this->index->getStoredFields();
123 35
        $facetFields = $this->index->getFacetFields();
124 35
        $facetArray = [];
125 35
        foreach ($facetFields as $key => $facetField) {
126 35
            $facetArray[] = $key . '.' . $facetField['Field'];
127
        }
128
129
        // Boosts, facets and obviously stored fields need to be stored
130 35
        return array_merge($storedFields, array_keys($boostedFields), $facetArray);
131
    }
132
133
    /**
134
     * Get the fields that should be copied
135
     *
136
     * @return ArrayList
137
     */
138 35
    public function getCopyFields()
139
    {
140 35
        $fields = $this->index->getCopyFields();
141
142 35
        $return = ArrayList::create();
143 35
        foreach ($fields as $field => $copyFields) {
144
            $item = [
145 35
                'Field' => $field,
146
            ];
147
148 35
            $return->push($item);
149
        }
150
151 35
        $this->extend('onBeforeCopyFields', $return);
152
153 35
        return $return;
154
    }
155
156
    /**
157
     * Get the definition of a copy field for determining what to load in to Solr
158
     *
159
     * @return ArrayList
160
     * @throws Exception
161
     */
162 35
    public function getCopyFieldDefinitions()
163
    {
164 35
        $copyFields = $this->index->getCopyFields();
165
166 35
        $return = ArrayList::create();
167
168 35
        foreach ($copyFields as $field => $fields) {
169
            // Allow all fields to be in a copyfield via a shorthand
170 35
            if ($fields[0] === '*') {
171 35
                $fields = $this->index->getFulltextFields();
172
            }
173
174 35
            foreach ($fields as $copyField) {
175 35
                $this->getFieldDefinition($copyField, $return, $field);
176
            }
177
        }
178
179 35
        return $return;
180
    }
181
182
    /**
183
     * Get the definitions of a filter field to load in to Solr.
184
     *
185
     * @return ArrayList
186
     * @throws Exception
187
     */
188 35
    public function getFilterFieldDefinitions()
189
    {
190 35
        $return = ArrayList::create();
191 35
        $originalStore = $this->store;
192
        // Always store every field in dev mode
193 35
        $this->setStore(Director::isDev() ? true : $this->store);
194 35
        $fields = $this->index->getFilterFields();
195 35
        foreach ($this->index->getFacetFields() as $facetField) {
196 35
            $fields[] = $facetField['Field'];
197
        }
198 35
        $fields = array_unique($fields);
199 35
        foreach ($fields as $field) {
200 35
            $this->getFieldDefinition($field, $return);
201
        }
202 35
        $this->extend('onBeforeFilterFields', $return);
203
204 35
        $this->setStore($originalStore);
205
206 35
        return $return;
207
    }
208
209
    /**
210
     * Get the types template in a rendered state
211
     *
212
     * @return DBHTMLText
213
     */
214 35
    public function getTypes()
215
    {
216 35
        $template = $this->getFullTemplatePath();
217 35
        $this->setTypesTemplate($template . '/types.ss');
218
219 35
        return $this->renderWith($this->getTypesTemplate());
220
    }
221
222
    /**
223
     * Generate the Schema xml
224
     *
225
     * @return DBHTMLText
226
     */
227 35
    public function generateSchema()
228
    {
229 35
        $template = $this->getFullTemplatePath();
230 35
        $this->setTemplate($template . '/schema.ss');
231
232 35
        return $this->renderWith($this->getTemplate());
233
    }
234
235
    /**
236
     * Get any extras that need loading in to Solr
237
     *
238
     * @return string
239
     */
240 35
    public function getExtrasPath()
241
    {
242 35
        return $this->getFullTemplatePath('extras');
243
    }
244
245
    /**
246
     * Get the base path of the template given, e.g. the "schema" templates
247
     * or the "extra" templates.
248
     *
249
     * @param string $type What type of templates do we need to get
250
     * @return string
251
     */
252 35
    public function getFullTemplatePath($type = 'schema'): string
253
    {
254 35
        if (!$this->getBaseTemplatePath($type)) {
255 35
            $templatePath = SolrCoreService::config()->get('paths');
256 35
            $customPath = $templatePath['base_path'] ?? false;
257 35
            $path = ModuleLoader::getModule('firesphere/solr-search')->getPath();
258
259 35
            if ($customPath) {
260
                $path = sprintf($customPath, Director::baseFolder());
261
            }
262
263 35
            $solrVersion = $this->coreService->getSolrVersion();
264 35
            $this->setBaseTemplatePath(sprintf($templatePath[$solrVersion][$type], $path), $type);
265
        }
266
267
268 35
        return $this->getBaseTemplatePath($type);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getBaseTemplatePath($type) could return the type boolean which is incompatible with the type-hinted return string. Consider adding an additional type-check to rule them out.
Loading history...
269
    }
270
271
    /**
272
     * @param string $baseTemplatePath
273
     * @param string $type
274
     * @return SchemaService
275
     */
276 35
    public function setBaseTemplatePath(string $baseTemplatePath, string $type): SchemaService
277
    {
278 35
        $this->baseTemplatePath[$type] = $baseTemplatePath;
279
280 35
        return $this;
281
    }
282
283
    /**
284
     * @param $type
285
     * @return string|bool
286
     */
287 35
    public function getBaseTemplatePath($type)
288
    {
289 35
        return $this->baseTemplatePath[$type] ?? false;
290
    }
291
}
292