FlexibleAttribute::getCleanKeySegment()   A
last analyzed

Complexity

Conditions 3
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 3.072

Importance

Changes 0
Metric Value
cc 3
eloc 4
nc 2
nop 1
dl 0
loc 9
ccs 4
cts 5
cp 0.8
crap 3.072
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace NovaFlexibleContent\Http;
4
5
use Illuminate\Support\Arr;
6
7
class FlexibleAttribute
8
{
9
    /**
10
     * The attribute key name of all flexible field in request.
11
     *
12
     * @var string
13
     */
14
    const REGISTER_FLEXIBLE_FIELD_NAME = '___nova_flexible_content_fields';
15
16
    /**
17
     * The string that identifies an "upload" value.
18
     *
19
     * @var string
20
     */
21
    const FILE_INDICATOR = '___upload-';
22
23
    /**
24
     * The string between the group identifier
25
     * and the actual attribute.
26
     *
27
     * @var string
28
     */
29
    const GROUP_SEPARATOR = '__';
30
31
    /**
32
     * The original attribute name
33
     *
34
     * @var string
35
     */
36
    public $original;
37
38
    /**
39
     * The layout group identifier part
40
     *
41
     * @var string
42
     */
43
    public $group;
44
45
    /**
46
     * The layout group identifier part
47
     *
48
     * @var string
49
     */
50
    public string $name;
51
52
    /**
53
     * The aggregate key (true = increment)
54
     *
55
     * @var bool|string
56
     */
57
    public $key;
58
59
    /**
60
     * Whether the attribute begins with the file indicator
61
     *
62
     * @var bool
63
     */
64
    public bool $upload;
65
66
    /**
67
     * Create a new attribute instance
68
     *
69
     * @param  string  $original
70
     * @param  mixed  $group
71
     * @return void
72
     */
73 6
    public function __construct($original, $group = null)
74
    {
75 6
        $this->original = $original;
76 6
        $this->setUpload();
77 6
        $this->setGroup($group);
78 6
        $this->setKey();
79 6
        $this->setName();
80
    }
81
82
    /**
83
     * Build an attribute from its components
84
     *
85
     * @param string $name
86
     * @param string|null $group
87
     * @param mixed $key
88
     * @param bool $upload
89
     * @return FlexibleAttribute
90
     */
91 6
    public static function make(string $name, ?string $group = null, ?string $key = null, bool $upload = false): static
92
    {
93 6
        $original = $upload ? static::FILE_INDICATOR : '';
94 6
        $original .= static::formatGroupPrefix($group) ?? '';
95 6
        $original .= $name;
96 6
        $original .= $key ? '['.($key !== true ? $key : '').']' : '';
0 ignored issues
show
introduced by
The condition $key !== true is always true.
Loading history...
97
98 6
        return new static($original, $group);
99
    }
100
101
    /**
102
     * Check if attribute is a flexible fields register
103
     */
104 5
    public function isFlexibleFieldsRegister(): bool
105
    {
106 5
        return $this->name === static::REGISTER_FLEXIBLE_FIELD_NAME;
107
    }
108
109
    /**
110
     * Check if attribute or given value match a probable file
111
     *
112
     * @param  mixed  $value
113
     * @return bool
114
     */
115 6
    public function isFlexibleFile($value = null): bool
116
    {
117 6
        if (!is_null($value) && !is_string($value)) {
118 2
            return false;
119 6
        } elseif (is_null($value)) {
0 ignored issues
show
introduced by
The condition is_null($value) is always true.
Loading history...
120 6
            return $this->upload;
121
        }
122
123 6
        return strpos($value, static::FILE_INDICATOR) === 0;
124
    }
125
126
    /**
127
     * Return a FlexibleAttribute instance matching the target upload field
128
     *
129
     * @param  mixed  $value
130
     * @return \NovaFlexibleContent\Http\FlexibleAttribute
131
     */
132 2
    public function getFlexibleFileAttribute($value): static
133
    {
134 2
        return new static($value, $this->group);
135
    }
136
137
    /**
138
     * Check if attribute represents an array item
139
     *
140
     * @return bool
141
     */
142 6
    public function isAggregate(): bool
143
    {
144 6
        return !is_null($this->key);
145
    }
146
147
    /**
148
     * Check if the found group key is used in the attribute's name
149
     *
150
     * @return bool
151
     */
152 6
    public function hasGroupInName(): bool
153
    {
154 6
        if (is_null($this->group)) {
0 ignored issues
show
introduced by
The condition is_null($this->group) is always false.
Loading history...
155 6
            return false;
156
        }
157
158 5
        $position = strpos($this->original, $this->groupPrefix());
159 5
        $index    = $this->isFlexibleFile() ? strlen(static::FILE_INDICATOR) : 0;
160
161 5
        return $position === $index;
162
    }
163
164
    /**
165
     * Get the group prefix string.
166
     */
167 5
    public function groupPrefix(?string $group = null): ?string
168
    {
169 5
        return static::formatGroupPrefix($group ?? $this->group);
170
    }
171
172
    /**
173
     * Get a group prefix string.
174
     */
175 6
    public static function formatGroupPrefix(?string $group = null): ?string
176
    {
177 6
        return $group ? $group.static::GROUP_SEPARATOR : null;
178
    }
179
180
    /**
181
     * Set given value in given using the current attribute definition
182
     *
183
     * @param  array  $attributes
184
     * @param  string  $value
185
     * @return array
186
     */
187 5
    public function setDataIn(&$attributes, $value): array
188
    {
189 5
        $value = is_string($value) && $value === '' ? null : $value;
190
191 5
        if (!$this->isAggregate()) {
192 5
            $attributes[$this->name] = $value;
193
194 5
            return $attributes;
195
        }
196
197
        if (!isset($attributes[$this->name])) {
198
            $attributes[$this->name] = [];
199
        } elseif (!is_array($attributes[$this->name])) {
200
            $attributes[$this->name] = [$attributes[$this->name]];
201
        }
202
203
        if ($this->key === true) {
204
            $attributes[$this->name][] = $value;
205
        } else {
206
            data_set($attributes[$this->name], $this->key, $value);
0 ignored issues
show
Bug introduced by
It seems like $this->key can also be of type false; however, parameter $key of data_set() does only seem to accept array|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

206
            data_set($attributes[$this->name], /** @scrutinizer ignore-type */ $this->key, $value);
Loading history...
207
        }
208
209
        return $attributes;
210
    }
211
212
    /**
213
     * Remove current attribute from given array
214
     *
215
     * @param  array  $attributes
216
     * @return array
217
     */
218 2
    public function unsetDataIn(&$attributes)
219
    {
220 2
        if (!$this->isAggregate() || !is_array($attributes[$this->name])) {
221 2
            unset($attributes[$this->name]);
222
223 2
            return $attributes;
224
        }
225
226
        if ($this->key === true) {
227
            array_shift($attributes[$this->name]);
228
        } else {
229
            Arr::forget($attributes[$this->name], $this->key);
230
        }
231
232
        return $attributes;
233
    }
234
235
    /**
236
     * Return a new instance with appended key
237
     *
238
     * @param  string  $key
239
     * @return \NovaFlexibleContent\Http\FlexibleAttribute
240
     */
241 1
    public function nest($key)
242
    {
243 1
        $append = implode('', array_map(function ($segment) {
244 1
            return '['.$segment.']';
245 1
        }, explode('.', $key)));
246
247 1
        return new static($this->original.$append, $this->group);
248
    }
249
250
    /**
251
     * Check attribute is an "upload" attribute and define it on the object
252
     *
253
     * @param  mixed  $group
254
     * @return void
255
     */
256 6
    protected function setUpload()
257
    {
258 6
        $this->upload = $this->isFlexibleFile($this->original);
259
    }
260
261
    /**
262
     * Check if given group identifier is included in original
263
     * attribute. If so, set it as the group property.
264
     *
265
     * @param  mixed  $group
266
     * @return void
267
     */
268 6
    protected function setGroup($group = null): void
269
    {
270 6
        if (!$group) {
271 6
            return;
272
        }
273
274 5
        $group = strval($group);
275
276 5
        if (strpos($this->original, $this->groupPrefix($group)) !== false) {
277 5
            $this->group = $group;
278
        }
279
    }
280
281
    /**
282
     * Check if the original attribute contains an aggregate syntax.
283
     * If so, extract the aggregate key and assign it to the key property.
284
     *
285
     * @return void
286
     */
287 6
    protected function setKey(): void
288
    {
289 6
        preg_match('/^.+?(\[.*\])?$/', $this->original, $arrayMatches);
290
291 6
        if (!isset($arrayMatches[1])) {
292 6
            return;
293
        }
294
295 1
        preg_match_all('/(?:\[([^\[\]]*)\])+?/', $arrayMatches[1], $keyMatches);
296
297 1
        $key = implode('.', array_map(function ($segment) {
298 1
            return $this->getCleanKeySegment($segment);
299 1
        }, $keyMatches[1]));
300
301 1
        $this->key = strlen($key) ? $key : true;
302
    }
303
304
    /**
305
     * Formats a key segment (removes unwanted characters, removes
306
     * group references from).
307
     *
308
     * @param  string  $segment
309
     * @return string
310
     */
311 1
    protected function getCleanKeySegment($segment): string
312
    {
313 1
        $segment = trim($segment, "'\" \t\n\r\0\x0B");
314
315 1
        if ($this->group && strpos($segment, $this->groupPrefix()) === 0) {
316
            return (new static($segment, $this->group))->name;
317
        }
318
319 1
        return $segment;
320
    }
321
322
    /**
323
     * Extract the attribute's final name
324
     *
325
     * @return void
326
     */
327 6
    protected function setName(): void
328
    {
329 6
        $name = trim($this->original);
330
331 6
        if ($this->isFlexibleFile()) {
332 2
            $position = strpos($name, static::FILE_INDICATOR) + strlen(static::FILE_INDICATOR);
333 2
            $name     = substr($name, $position);
334
        }
335
336 6
        if ($this->hasGroupInName()) {
337 5
            $position = strpos($name, $this->group) + strlen($this->groupPrefix());
338 5
            $name     = substr($name, $position);
339
        }
340
341 6
        if ($this->isAggregate()) {
342 1
            $position = strpos($name, '[');
343 1
            $name     = substr($name, 0, $position);
344
        }
345
346 6
        $this->name = $name;
347
    }
348
}
349