GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Test Failed
Push — master ( da55b1...7ac43b )
by SignpostMarv
04:31
created

MaybeModifyValueBeforeNudge()   A

Complexity

Conditions 5
Paths 8

Size

Total Lines 34
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 5

Importance

Changes 0
Metric Value
eloc 17
dl 0
loc 34
ccs 15
cts 15
cp 1
rs 9.3888
c 0
b 0
f 0
cc 5
nc 8
nop 4
crap 5
1
<?php
2
/**
3
* Base daft objects.
4
*
5
* @author SignpostMarv
6
*/
7
declare(strict_types=1);
8
9
namespace SignpostMarv\DaftObject;
10
11
use Closure;
12
13
/**
14
* Array-backed daft objects.
15
*/
16
abstract class AbstractArrayBackedDaftObject extends AbstractDaftObject implements DaftObjectCreatedByArray
17
{
18
    const BOOL_DEFAULT_WRITEALL = false;
19
20
    const BOOL_DEFAULT_AUTOTRIMSTRINGS = false;
21
22
    const BOOL_DEFAULT_THROWIFNOTUNIQUE = false;
23
24
    /**
25
    * data for this instance.
26
    *
27
    * @var array<string, scalar|array|object|null>
28
    */
29
    private $data = [];
30
31
    /**
32
    * List of changed properties.
33
    *
34
    * @var array<string, bool>
35
    */
36
    private $changedProperties = [];
37
38
    /**
39
    * List of changed properties, for write-once read-many.
40
    *
41
    * @var array<string, bool>
42
    */
43
    private $wormProperties = [];
44
45
    /**
46
    * @param array<string, scalar|array|object|null> $data
47
    */
48 1152
    public function __construct(array $data = [], bool $writeAll = false)
49
    {
50 1152
        if (true === $writeAll) {
51 192
            foreach ($data as $k => $v) {
52 192
                $this->__set($k, $v);
53
            }
54
        } else {
55 960
            foreach ($data as $k => $v) {
56 300
                $this->data[$k] = $v;
57
            }
58
        }
59 1152
    }
60
61 80
    public function __isset(string $property) : bool
62
    {
63
        return
64 80
            in_array(
65 60
                $property,
66 80
                static::DaftObjectProperties(),
67 80
                DefinitionAssistant::IN_ARRAY_STRICT_MODE
68
            ) &&
69 80
            isset($this->data, $this->data[$property]);
70
    }
71
72 88
    public function ChangedProperties() : array
73
    {
74 88
        return array_keys($this->changedProperties);
75
    }
76
77 88
    public function MakePropertiesUnchanged(string ...$properties) : void
78
    {
79 88
        foreach ($properties as $property) {
80 88
            unset($this->changedProperties[$property]);
81
        }
82 88
    }
83
84 352
    public function HasPropertyChanged(string $property) : bool
85
    {
86 352
        return $this->changedProperties[$property] ?? false;
87
    }
88
89 124
    public function jsonSerialize() : array
90
    {
91
        /**
92
        * @var array<int, string>
93
        */
94 124
        $properties = static::DaftObjectJsonPropertyNames();
95
96
        /**
97
        * @var array<string, string>
98
        */
99 52
        $properties = array_combine($properties, $properties);
100
101 52
        return array_filter(
102 39
            array_map(
103
                /**
104
                * @return scalar|array|object|null
105
                */
106
                function (string $property) {
107 52
                    return $this->DoGetSet($property, false);
108 52
                },
109 26
                $properties
110
            ),
111
            /**
112
            * @param scalar|array|object|null $maybe
113
            */
114
            function ($maybe) : bool {
115 52
                return ! is_null($maybe);
116 52
            }
117
        );
118
    }
119
120
    /**
121
    * @param array<int|string, scalar|(scalar|array|object|null)[]|object|null> $array
122
    */
123 124
    final public static function DaftObjectFromJsonArray(
124
        array $array,
125
        bool $writeAll = self::BOOL_DEFAULT_WRITEALL
126
    ) : DaftJson {
127 124
        $type = JsonTypeUtilities::ThrowIfNotDaftJson(static::class);
128
129 52
        $array = JsonTypeUtilities::ThrowIfJsonDefNotValid($type, $array);
130
131
        /**
132
        * @var array<int, string>
133
        */
134 52
        $props = array_keys($array);
135 52
        $mapper = static::DaftJsonClosure($array, $writeAll);
136
137
        /**
138
        * @var array<int, scalar|object|array|null>
139
        */
140 52
        $vals = array_map($mapper, $props);
141
142 52
        return new $type(array_combine($props, $vals), $writeAll);
143
    }
144
145 196
    public static function DaftObjectFromJsonString(string $string) : DaftJson
146
    {
147
        /**
148
        * @var scalar|array<int|string, scalar|(scalar|array|object|null)[]|object|null>|object|null
149
        */
150 196
        $decoded = json_decode($string, true);
151
152 196
        return JsonTypeUtilities::ThrowIfNotDaftJson(static::class)::DaftObjectFromJsonArray(
153 52
            is_array($decoded) ? $decoded : [$decoded]
154
        );
155
    }
156
157 532
    public function DaftObjectWormPropertyWritten(string $property) : bool
158
    {
159 532
        $wormProperties = $this->wormProperties;
160
161
        return
162 532
            ($this instanceof DaftObjectWorm) &&
163
            (
164 264
                $this->HasPropertyChanged($property) ||
165 532
                isset($wormProperties[$property])
166
            );
167
    }
168
169
    /**
170
    * Retrieve a property from data.
171
    *
172
    * @param string $property the property being retrieved
173
    *
174
    * @throws Exceptions\PropertyNotNullableException if value is not set and $property is not listed as nullabe
175
    *
176
    * @return scalar|array|object|null the property value
177
    */
178 216
    protected function RetrievePropertyValueFromData(string $property)
179
    {
180 216
        $isNullable = in_array(
181 162
            $property,
182 216
            static::DaftObjectNullableProperties(),
183 216
            DefinitionAssistant::IN_ARRAY_STRICT_MODE
184
        );
185
186 216
        if ( ! array_key_exists($property, $this->data) && ! $isNullable) {
187 4
            throw Exceptions\Factory::PropertyNotNullableException(static::class, $property);
188 212
        } elseif ($isNullable) {
189 128
            return $this->data[$property] ?? null;
190
        }
191
192 152
        return $this->data[$property];
193
    }
194
195 76
    protected function RetrievePropertyValueFromDataExpectString(string $property) : string
196
    {
197 76
        return TypeUtilities::ExpectRetrievedValueIsString(
198 57
            $property,
199 76
            $this->RetrievePropertyValueFromData($property),
200
            static::class
201
        );
202
    }
203 4
204
    protected function RetrievePropertyValueFromDataExpectStringOrNull(string $property) : ? string
205 4
    {
206
        $value = $this->RetrievePropertyValueFromData($property);
207 4
208 4
        if (is_null($value)) {
209
            return null;
210
        }
211 4
212
        return TypeUtilities::ExpectRetrievedValueIsString($property, $value, static::class);
213
    }
214 4
215
    protected function RetrievePropertyValueFromDataExpectArray(string $property) : array
216 4
    {
217 3
        return TypeUtilities::ExpectRetrievedValueIsArray(
218 4
            $property,
219
            $this->RetrievePropertyValueFromData($property),
220
            static::class
221
        );
222 4
    }
223
224 4
    protected function RetrievePropertyValueFromDataExpectArrayOrNull(string $property) : ? array
225
    {
226 4
        $value = $this->RetrievePropertyValueFromData($property);
227 4
228
        if (is_null($value)) {
229
            return null;
230 4
        }
231
232
        return TypeUtilities::ExpectRetrievedValueIsArray($property, $value, static::class);
233 8
    }
234
235 8
    protected function RetrievePropertyValueFromDataExpectIntish(string $property) : int
236 6
    {
237 8
        return TypeUtilities::ExpectRetrievedValueIsIntish(
238
            $property,
239
            $this->RetrievePropertyValueFromData($property),
240
            static::class
241 12
        );
242
    }
243 12
244
    protected function RetrievePropertyValueFromDataExpectIntishOrNull(string $property) : ? int
245 12
    {
246 12
        $value = $this->RetrievePropertyValueFromData($property);
247
248
        if (is_null($value)) {
249 12
            return null;
250
        }
251
252 4
        return TypeUtilities::ExpectRetrievedValueIsIntish($property, $value, static::class);
253
    }
254 4
255 3
    protected function RetrievePropertyValueFromDataExpectFloatish(string $property) : float
256 4
    {
257
        return TypeUtilities::ExpectRetrievedValueIsFloatish(
258
            $property,
259
            $this->RetrievePropertyValueFromData($property),
260 12
            static::class
261
        );
262 12
    }
263
264 12
    protected function RetrievePropertyValueFromDataExpectFloatishOrNull(string $property) : ? float
265 12
    {
266
        $value = $this->RetrievePropertyValueFromData($property);
267
268 12
        if (is_null($value)) {
269
            return null;
270
        }
271 8
272
        return TypeUtilities::ExpectRetrievedValueIsFloatish($property, $value, static::class);
273 8
    }
274 6
275 8
    protected function RetrievePropertyValueFromDataExpectBoolish(string $property) : bool
276
    {
277
        return TypeUtilities::ExpectRetrievedValueIsBoolish(
278
            $property,
279 28
            $this->RetrievePropertyValueFromData($property),
280
            static::class
281 28
        );
282
    }
283 28
284 28
    protected function RetrievePropertyValueFromDataExpectBoolishOrNull(string $property) : ? bool
285
    {
286
        $value = $this->RetrievePropertyValueFromData($property);
287 28
288
        if (is_null($value)) {
289
            return null;
290
        }
291
292
        return TypeUtilities::ExpectRetrievedValueIsBoolish($property, $value, static::class);
293 540
    }
294
295
    /**
296
    * @param scalar|array|object|null $value
297
    */
298
    protected function NudgePropertyValue(
299
        string $property,
300
        $value,
301
        bool $autoTrimStrings = self::BOOL_DEFAULT_AUTOTRIMSTRINGS,
302 540
        bool $throwIfNotUnique = self::BOOL_DEFAULT_THROWIFNOTUNIQUE
303
    ) : void {
304 540
        /**
305
        * @var array<int, string>
306 324
        */
307 243
        $nullables = static::DaftObjectNullableProperties();
308 162
309 162
        $this->MaybeThrowOnNudge($property, $value, $nullables);
310 162
311
        $value = $this->MaybeModifyValueBeforeNudge(
312
            $property,
313
            $value,
314 308
            $autoTrimStrings,
315 308
            $throwIfNotUnique
316
        );
317
318 308
        $isChanged = (
319
            ! array_key_exists($property, $this->data) ||
320 308
            $this->data[$property] !== $value
321 308
        );
322
323 308
        $this->data[$property] = $value;
324
325
        if ($isChanged && true !== isset($this->changedProperties[$property])) {
326
            $this->changedProperties[$property] = $this->wormProperties[$property] = true;
327
        }
328 80
    }
329
330 80
    /**
331 4
    * @param array<int|string, scalar|array|object|null> $array
332 4
    */
333 2
    private static function DaftJsonClosure(array $array, bool $writeAll) : Closure
334 4
    {
335
        $jsonDef = static::DaftObjectJsonProperties();
336
337
        return
338 76
            /**
339
            * @return scalar|array|object|null
340
            */
341
            function (string $prop) use ($array, $jsonDef, $writeAll) {
342
                /**
343
                * @var string|null
344 8
                */
345
                $jsonType = $jsonDef[$prop] ?? null;
346 8
347 4
                if ( ! is_string($jsonType)) {
348 4
                    return $array[$prop];
349 2
                }
350 4
351
                /**
352
                * @var array<int|string, scalar|(scalar|(scalar|array|object|null)[]|object|null)[]|object|null>
353
                */
354 4
                $propVal = (is_array($array[$prop]) ? $array[$prop] : [$array[$prop]]);
355
356
                if ('[]' === mb_substr($jsonType, -2)) {
357
                    /**
358
                    * @psalm-var class-string<DaftObject>
359
                    */
360 20
                    $jsonType = mb_substr($jsonType, 0, -2);
361
362 20
                    $jsonType = JsonTypeUtilities::ThrowIfNotJsonType($jsonType);
363 4
364
                    return JsonTypeUtilities::DaftObjectFromJsonTypeArray(
365
                        $jsonType,
366 20
                        $prop,
367 4
                        $propVal,
368 4
                        $writeAll
369 2
                    );
370 4
                }
371
372
                /**
373
                * @psalm-var class-string<DaftObject>
374 16
                */
375
                $jsonType = $jsonType;
376
377
                $jsonType = JsonTypeUtilities::ThrowIfNotJsonType($jsonType);
378
379
                return JsonTypeUtilities::DaftJsonFromJsonType($jsonType, $propVal, $writeAll);
380 16
            };
381
    }
382 16
383 4
    /**
384
    * @param scalar|array|object|null $value
385
    *
386 16
    * @return scalar|array|object|null
387 4
    */
388 4
    private function MaybeModifyValueBeforeNudge(
389 2
        string $property,
390 4
        $value,
391
        bool $autoTrimStrings = self::BOOL_DEFAULT_AUTOTRIMSTRINGS,
392
        bool $throwIfNotUnique = self::BOOL_DEFAULT_THROWIFNOTUNIQUE
393
    ) {
394 12
        $spec = null;
395
396
        if (
397
            is_a(
398
                static::class,
399
                DaftObjectHasPropertiesWithMultiTypedArraysOfUniqueValues::class,
400 28
                true
401
            )
402 28
        ) {
403 8
            $spec = (
404 20
                static::DaftObjectPropertiesWithMultiTypedArraysOfUniqueValues()[$property] ?? null
405 8
            );
406
        }
407
408 12
        if (is_array($spec)) {
409 4
            $value = DefinitionAssistant::MaybeThrowIfValueDoesNotMatchMultiTypedArray(
410 4
                $autoTrimStrings,
411 2
                $throwIfNotUnique,
412 4
                $value,
413
                ...$spec
414
            );
415
        }
416 8
417
        if (is_string($value) && $autoTrimStrings) {
418
            $value = trim($value);
419
        }
420
421
        return $value;
422 52
    }
423
424 52
    /**
425
    * @see AbstractArrayBackedDaftObject::NudgePropertyValue()
426
    */
427
    private function MaybeThrowForPropertyOnNudge(string $property) : string
428
    {
429
        $properties = static::DaftObjectProperties();
430
431
        if ( ! in_array($property, $properties, DefinitionAssistant::IN_ARRAY_STRICT_MODE)) {
432
            throw Exceptions\Factory::UndefinedPropertyException(static::class, $property);
433
        } elseif ($this->DaftObjectWormPropertyWritten($property)) {
434 52
            throw Exceptions\Factory::PropertyNotRewriteableException(static::class, $property);
435
        }
436 52
437 36
        return $property;
438
    }
439
440
    /**
441
    * @param scalar|array|object|null $value
442
    *
443 44
    * @see AbstractArrayBackedDaftObject::NudgePropertyValue()
444
    */
445 44
    private function MaybeThrowOnNudge(string $property, $value, array $properties) : void
446
    {
447
        $property = $this->MaybeThrowForPropertyOnNudge($property);
448
449 44
        if (
450
            true === is_null($value) &&
451 44
            ! in_array($property, $properties, DefinitionAssistant::IN_ARRAY_STRICT_MODE)
452
        ) {
453 44
            throw Exceptions\Factory::PropertyNotNullableException(static::class, $property);
454 33
        }
455 22
    }
456
}
457