LocalFactory::create()   F
last analyzed

Complexity

Conditions 12
Paths 1056

Size

Total Lines 45
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 26
CRAP Score 12.0524

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 12
eloc 28
c 2
b 0
f 0
nc 1056
nop 2
dl 0
loc 45
ccs 26
cts 28
cp 0.9286
crap 12.0524
rs 2.8

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * This file is part of Scout Extended.
7
 *
8
 * (c) Algolia Team <[email protected]>
9
 *
10
 *  For the full copyright and license information, please view the LICENSE
11
 *  file that was distributed with this source code.
12
 */
13
14
namespace Algolia\ScoutExtended\Settings;
15
16
use Algolia\AlgoliaSearch\SearchIndex;
17
use Algolia\ScoutExtended\Exceptions\ModelNotFoundException;
18
use Algolia\ScoutExtended\Repositories\RemoteSettingsRepository;
19
use Algolia\ScoutExtended\Searchable\Aggregator;
20
use Illuminate\Database\Eloquent\ModelNotFoundException as BaseModelNotFoundException;
21
use Illuminate\Database\QueryException;
22
use Illuminate\Support\Str;
23
use function in_array;
24
use function is_string;
25
26
/**
27
 * @internal
28
 */
29
final class LocalFactory
30
{
31
    /**
32
     * @var \Algolia\ScoutExtended\Repositories\RemoteSettingsRepository
33
     */
34
    private $remoteRepository;
35
36
    /**
37
     * @var string[]
38
     */
39
    private static $customRankingKeys = [
40
        '*ed_at',
41
        'count_*',
42
        '*_count',
43
        'number_*',
44
        '*_number',
45
    ];
46
47
    /**
48
     * @var string[]
49
     */
50
    private static $unsearchableAttributesKeys = [
51
        'id',
52
        '*_id',
53
        'id_*',
54
        '*ed_at',
55
        '*_count',
56
        'count_*',
57
        'number_*',
58
        '*_number',
59
        '*image*',
60
        '*url*',
61
        '*link*',
62
        '*password*',
63
        '*token*',
64
        '*hash*',
65
    ];
66
67
    /**
68
     * @var string[]
69
     */
70
    private static $attributesForFacetingKeys = [
71
        '*category*',
72
        '*list*',
73
        '*country*',
74
        '*city*',
75
        '*type*',
76
    ];
77
78
    /**
79
     * @var string[]
80
     */
81
    private static $unretrievableAttributes = [
82
        '*password*',
83
        '*token*',
84
        '*secret*',
85
        '*hash*',
86
    ];
87
88
    /**
89
     * @var string[]
90
     */
91
    private static $unsearchableAttributesValues = [
92
        'http://*',
93
        'https://*',
94
    ];
95
96
    /**
97
     * @var string[]
98
     */
99
    private static $disableTypoToleranceOnAttributesKeys = [
100
        'slug',
101
        '*_slug',
102
        'slug_*',
103
        '*code*',
104
        '*sku*',
105
        '*reference*',
106
    ];
107
108
    /**
109
     * SettingsFactory constructor.
110
     *
111
     * @param \Algolia\ScoutExtended\Repositories\RemoteSettingsRepository $remoteRepository
112
     *
113
     * @return void
114
     */
115 4
    public function __construct(RemoteSettingsRepository $remoteRepository)
116
    {
117 4
        $this->remoteRepository = $remoteRepository;
118 4
    }
119
120
    /**
121
     * Creates settings for the given model.
122
     *
123
     * @param \Algolia\AlgoliaSearch\SearchIndex $index
124
     * @param string $model
125
     *
126
     * @return \Algolia\ScoutExtended\Settings\Settings
127
     */
128 4
    public function create(SearchIndex $index, string $model): Settings
129
    {
130 4
        $attributes = $this->getAttributes($model);
131 3
        $searchableAttributes = [];
132 3
        $attributesForFaceting = [];
133 3
        $customRanking = [];
134 3
        $disableTypoToleranceOnAttributes = [];
135 3
        $unretrievableAttributes = [];
136 3
        foreach ($attributes as $key => $value) {
137 3
            $key = (string) $key;
138
139 3
            if ($this->isSearchableAttributes($key, $value)) {
140 3
                $searchableAttributes[] = $key;
141
            }
142
143 3
            if ($this->isAttributesForFaceting($key, $value)) {
144 3
                $attributesForFaceting[] = $key;
145
            }
146
147 3
            if ($this->isCustomRanking($key, $value)) {
148 3
                $customRanking[] = "desc({$key})";
149
            }
150
151 3
            if ($this->isDisableTypoToleranceOnAttributes($key, $value)) {
152
                $disableTypoToleranceOnAttributes[] = $key;
153
            }
154
155 3
            if ($this->isUnretrievableAttributes($key, $value)) {
156 3
                $unretrievableAttributes[] = $key;
157
            }
158
        }
159
160
        $detectedSettings = [
161 3
            'searchableAttributes' => ! empty($searchableAttributes) ? $searchableAttributes : null,
162 3
            'attributesForFaceting' => ! empty($attributesForFaceting) ? $attributesForFaceting : null,
163 3
            'customRanking' => ! empty($customRanking) ? $customRanking : null,
164 3
            'disableTypoToleranceOnAttributes' => ! empty($disableTypoToleranceOnAttributes) ?
165
                $disableTypoToleranceOnAttributes : null,
166 3
            'unretrievableAttributes' => ! empty($unretrievableAttributes) ? $unretrievableAttributes : null,
167 3
            'queryLanguages' => array_unique([config('app.locale'), config('app.fallback_locale')]),
168
        ];
169
170 3
        $settings = array_merge($this->remoteRepository->find($index)->compiled(), $detectedSettings);
171
172 3
        return new Settings($settings, $this->remoteRepository->defaults());
173
    }
174
175
    /**
176
     * Checks if the given key/value is a 'searchableAttributes'.
177
     *
178
     * @param  string $key
179
     * @param  mixed $value
180
     *
181
     * @return bool
182
     */
183 3
    public function isSearchableAttributes(string $key, $value): bool
184
    {
185 3
        return ! is_object($value) && ! is_array($value) &&
186 3
            ! Str::is(self::$unsearchableAttributesKeys, $key) &&
187 3
            ! Str::is(self::$unsearchableAttributesValues, $value);
188
    }
189
190
    /**
191
     * Checks if the given key/value is a 'attributesForFaceting'.
192
     *
193
     * @param  string $key
194
     * @param  mixed $value
195
     *
196
     * @return bool
197
     */
198 3
    public function isAttributesForFaceting(string $key, $value): bool
199
    {
200 3
        return Str::is(self::$attributesForFacetingKeys, $key);
201
    }
202
203
    /**
204
     * Checks if the given key/value is a 'customRanking'.
205
     *
206
     * @param  string $key
207
     * @param  mixed $value
208
     *
209
     * @return bool
210
     */
211 3
    public function isCustomRanking(string $key, $value): bool
212
    {
213 3
        return Str::is(self::$customRankingKeys, $key);
214
    }
215
216
    /**
217
     * Checks if the given key/value is a 'disableTypoToleranceOnAttributes'.
218
     *
219
     * @param  string $key
220
     * @param  mixed $value
221
     *
222
     * @return bool
223
     */
224 3
    public function isDisableTypoToleranceOnAttributes(string $key, $value): bool
225
    {
226 3
        return is_string($key) && Str::is(self::$disableTypoToleranceOnAttributesKeys, $key);
227
    }
228
229
    /**
230
     * Checks if the given key/value is a 'unretrievableAttributes'.
231
     *
232
     * @param  string $key
233
     * @param  mixed $value
234
     *
235
     * @return bool
236
     */
237 3
    public function isUnretrievableAttributes(string $key, $value): bool
238
    {
239 3
        return is_string($key) && Str::is(self::$unretrievableAttributes, $key);
240
    }
241
242
    /**
243
     * Tries to get attributes from the searchable class.
244
     *
245
     * @param  string $searchable
246
     *
247
     * @return array
248
     */
249 4
    private function getAttributes(string $searchable): array
250
    {
251 4
        $attributes = [];
252
253 4
        if (in_array(Aggregator::class, class_parents($searchable), true)) {
254
            foreach (($instance = new $searchable)->getModels() as $model) {
0 ignored issues
show
Unused Code introduced by
The assignment to $instance is dead and can be removed.
Loading history...
255
                $attributes = array_merge($attributes, $this->getAttributes($model));
256
            }
257
        } else {
258 4
            $instance = null;
259
260
            try {
261 4
                $instance = $searchable::firstOrFail();
262 1
            } catch (QueryException | BaseModelNotFoundException $e) {
263 1
                throw tap(new ModelNotFoundException())->setModel($searchable);
264
            }
265
266 3
            $attributes = method_exists($instance, 'toSearchableArray') ? $instance->toSearchableArray() :
267 3
                $instance->toArray();
268
        }
269
270 3
        return $attributes;
271
    }
272
}
273