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 ( 1f39c8...d40293 )
by SignpostMarv
04:46
created

RetrievePropertyValueFromDataExpectBoolishOrNull()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 1
dl 0
loc 9
ccs 0
cts 0
cp 0
crap 6
rs 10
c 0
b 0
f 0
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 1092
    public function __construct(array $data = [], bool $writeAll = false)
49
    {
50 1092
        if (true === $writeAll) {
51 192
            foreach ($data as $k => $v) {
52 192
                $this->__set($k, $v);
53
            }
54
        } else {
55 900
            foreach ($data as $k => $v) {
56 240
                $this->data[$k] = $v;
57
            }
58
        }
59 1092
    }
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 124
    /**
121
    * @param array<int|string, scalar|(scalar|array|object|null)[]|object|null> $array
122
    */
123
    final public static function DaftObjectFromJsonArray(
124 124
        array $array,
125
        bool $writeAll = self::BOOL_DEFAULT_WRITEALL
126 52
    ) : DaftJson {
127
        $type = JsonTypeUtilities::ThrowIfNotDaftJson(static::class);
128
129
        $array = JsonTypeUtilities::ThrowIfJsonDefNotValid($type, $array);
130
131 52
        /**
132 52
        * @var array<int, string>
133
        */
134
        $props = array_keys($array);
135
        $mapper = static::DaftJsonClosure($array, $writeAll);
136
137 52
        /**
138
        * @var array<int, scalar|object|array|null>
139 52
        */
140
        $vals = array_map($mapper, $props);
141
142 196
        return new $type(array_combine($props, $vals), $writeAll);
143
    }
144
145
    public static function DaftObjectFromJsonString(string $string) : DaftJson
146
    {
147 196
        /**
148
        * @var scalar|array<int|string, scalar|(scalar|array|object|null)[]|object|null>|object|null
149 196
        */
150 52
        $decoded = json_decode($string, true);
151
152
        return JsonTypeUtilities::ThrowIfNotDaftJson(static::class)::DaftObjectFromJsonArray(
153
            is_array($decoded) ? $decoded : [$decoded]
154 532
        );
155
    }
156 532
157
    public function DaftObjectWormPropertyWritten(string $property) : bool
158
    {
159 532
        $wormProperties = $this->wormProperties;
160
161 264
        return
162 532
            ($this instanceof DaftObjectWorm) &&
163
            (
164
                $this->HasPropertyChanged($property) ||
165
                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 156
    *
176
    * @return scalar|array|object|null the property value
177 156
    */
178 117
    protected function RetrievePropertyValueFromData(string $property)
179 156
    {
180 156
        $isNullable = in_array(
181
            $property,
182
            static::DaftObjectNullableProperties(),
183 156
            DefinitionAssistant::IN_ARRAY_STRICT_MODE
184 4
        );
185 152
186 68
        if ( ! array_key_exists($property, $this->data) && ! $isNullable) {
187
            throw Exceptions\Factory::PropertyNotNullableException(static::class, $property);
188
        } elseif ($isNullable) {
189 152
            return $this->data[$property] ?? null;
190
        }
191
192
        return $this->data[$property];
193
    }
194
195 540
    protected function RetrievePropertyValueFromDataExpectString(string $property) : string
196
    {
197
        return $this->ExpectRetrievedValueIsString(
198
            $property,
199
            $this->RetrievePropertyValueFromData($property)
200
        );
201
    }
202
203
    protected function RetrievePropertyValueFromDataExpectStringOrNull(string $property) : ? string
204 540
    {
205
        $value = $this->RetrievePropertyValueFromData($property);
206 540
207
        if (is_null($value)) {
208 324
            return null;
209 243
        }
210 162
211 162
        return $this->ExpectRetrievedValueIsString($property, $value);
212 162
    }
213
214
    /**
215
    * @param scalar|array|object|null $value
216 308
    */
217 308
    private function ExpectRetrievedValueIsString(string $property, $value) : string
218
    {
219
        if ( ! is_string($value)) {
220 308
            throw Exceptions\Factory::PropertyValueNotOfExpectedTypeException(
221
                static::class,
222 308
                $property,
223 308
                'string'
224
            );
225 308
        }
226
227 52
        return $value;
228
    }
229 52
230
    protected function RetrievePropertyValueFromDataExpectArray(string $property) : array
231
    {
232
        return $this->ExpectRetrievedValueIsArray(
233
            $property,
234
            $this->RetrievePropertyValueFromData($property)
235
        );
236
    }
237
238
    protected function RetrievePropertyValueFromDataExpectArrayOrNull(string $property) : ? array
239 52
    {
240
        $value = $this->RetrievePropertyValueFromData($property);
241 52
242 36
        if (is_null($value)) {
243
            return null;
244
        }
245 44
246
        return $this->ExpectRetrievedValueIsArray($property, $value);
247 44
    }
248
249
    /**
250
    * @param scalar|array|object|null $value
251 44
    */
252
    private function ExpectRetrievedValueIsArray(string $property, $value) : array
253 44
    {
254
        if ( ! is_array($value)) {
255 44
            throw Exceptions\Factory::PropertyValueNotOfExpectedTypeException(
256 33
                static::class,
257 22
                $property,
258 22
                'array'
259 22
            );
260
        }
261
262
        return $value;
263
    }
264
265
    protected function RetrievePropertyValueFromDataExpectIntish(string $property) : int
266 28
    {
267
        return $this->ExpectRetrievedValueIsIntish(
268 28
            $property,
269
            $this->RetrievePropertyValueFromData($property)
270 28
        );
271 52
    }
272
273
    protected function RetrievePropertyValueFromDataExpectIntishOrNull(string $property) : ? int
274
    {
275
        $value = $this->RetrievePropertyValueFromData($property);
276
277
        if (is_null($value)) {
278
            return null;
279 324
        }
280
281
        return $this->ExpectRetrievedValueIsIntish($property, $value);
282
    }
283
284
    /**
285 324
    * @param scalar|array|object|null $value
286
    */
287
    private function ExpectRetrievedValueIsIntish(string $property, $value) : int
288 324
    {
289 324
        if (is_string($value) && ctype_digit($value)) {
290 324
            $value = (int) $value;
291 324
        }
292
293
        if ( ! is_int($value)) {
294
            throw Exceptions\Factory::PropertyValueNotOfExpectedTypeException(
295 24
                static::class,
296
                $property,
297
                'int'
298
            );
299 324
        }
300 20
301 15
        return $value;
302 10
    }
303 10
304 8
    protected function RetrievePropertyValueFromDataExpectFloatish(string $property) : float
305
    {
306
        return $this->ExpectRetrievedValueIsFloatish(
307
            $property,
308 308
            $this->RetrievePropertyValueFromData($property)
309 4
        );
310
    }
311
312 308
    protected function RetrievePropertyValueFromDataExpectFloatishOrNull(string $property) : ? float
313
    {
314
        $value = $this->RetrievePropertyValueFromData($property);
315
316
        if (is_null($value)) {
317
            return null;
318 540
        }
319
320 540
        return $this->ExpectRetrievedValueIsFloatish($property, $value);
321
    }
322 540
323 8
    /**
324 532
    * @param scalar|array|object|null $value
325 192
    */
326
    private function ExpectRetrievedValueIsFloatish(string $property, $value) : float
327
    {
328 532
        if (is_string($value) && is_numeric($value)) {
329
            $value = (float) $value;
330
        }
331
332
        if ( ! is_float($value)) {
333
            throw Exceptions\Factory::PropertyValueNotOfExpectedTypeException(
334
                static::class,
335
                $property,
336 540
                'float'
337
            );
338 540
        }
339
340
        return $value;
341 532
    }
342 474
343
    protected function RetrievePropertyValueFromDataExpectBoolish(string $property) : bool
344 208
    {
345
        return $this->ExpectRetrievedValueIsBoolish(
346 324
            $property,
347
            $this->RetrievePropertyValueFromData($property)
348
        );
349
    }
350
351
    protected function RetrievePropertyValueFromDataExpectBoolishOrNull(string $property) : ? bool
352
    {
353
        $value = $this->RetrievePropertyValueFromData($property);
354
355
        if (is_null($value)) {
356
            return null;
357
        }
358
359
        return $this->ExpectRetrievedValueIsBoolish($property, $value);
360
    }
361
362
    /**
363
    * @param scalar|array|object|null $value
364
    */
365
    private function ExpectRetrievedValueIsBoolish(string $property, $value) : bool
366
    {
367
        if ('1' === $value || 1 === $value) {
368
            return true;
369
        } elseif ('0' === $value || 0 === $value) {
370
            return false;
371
        }
372
373
        if ( ! is_bool($value)) {
374
            throw Exceptions\Factory::PropertyValueNotOfExpectedTypeException(
375
                static::class,
376
                $property,
377
                'bool'
378
            );
379
        }
380
381
        return $value;
382
    }
383
384
    /**
385
    * @param scalar|array|object|null $value
386
    */
387
    protected function NudgePropertyValue(
388
        string $property,
389
        $value,
390
        bool $autoTrimStrings = self::BOOL_DEFAULT_AUTOTRIMSTRINGS,
391
        bool $throwIfNotUnique = self::BOOL_DEFAULT_THROWIFNOTUNIQUE
392
    ) : void {
393
        /**
394
        * @var array<int, string>
395
        */
396
        $nullables = static::DaftObjectNullableProperties();
397
398
        $this->MaybeThrowOnNudge($property, $value, $nullables);
399
400
        $value = $this->MaybeModifyValueBeforeNudge(
401
            $property,
402
            $value,
403
            $autoTrimStrings,
404
            $throwIfNotUnique
405
        );
406
407
        $isChanged = (
408
            ! array_key_exists($property, $this->data) ||
409
            $this->data[$property] !== $value
410
        );
411
412
        $this->data[$property] = $value;
413
414
        if ($isChanged && true !== isset($this->changedProperties[$property])) {
415
            $this->changedProperties[$property] = $this->wormProperties[$property] = true;
416
        }
417
    }
418
419
    /**
420
    * @param array<int|string, scalar|array|object|null> $array
421
    */
422
    private static function DaftJsonClosure(array $array, bool $writeAll) : Closure
423
    {
424
        $jsonDef = static::DaftObjectJsonProperties();
425
426
        return
427
            /**
428
            * @return scalar|array|object|null
429
            */
430
            function (string $prop) use ($array, $jsonDef, $writeAll) {
431
                /**
432
                * @var string|null
433
                */
434
                $jsonType = $jsonDef[$prop] ?? null;
435
436
                if ( ! is_string($jsonType)) {
437
                    return $array[$prop];
438
                }
439
440
                /**
441
                * @var array<int|string, scalar|(scalar|(scalar|array|object|null)[]|object|null)[]|object|null>
442
                */
443
                $propVal = (is_array($array[$prop]) ? $array[$prop] : [$array[$prop]]);
444
445
                if ('[]' === mb_substr($jsonType, -2)) {
446
                    /**
447
                    * @psalm-var class-string<DaftObject>
448
                    */
449
                    $jsonType = mb_substr($jsonType, 0, -2);
450
451
                    $jsonType = JsonTypeUtilities::ThrowIfNotJsonType($jsonType);
452
453
                    return JsonTypeUtilities::DaftObjectFromJsonTypeArray(
454
                        $jsonType,
455
                        $prop,
456
                        $propVal,
457
                        $writeAll
458
                    );
459
                }
460
461
                /**
462
                * @psalm-var class-string<DaftObject>
463
                */
464
                $jsonType = $jsonType;
465
466
                $jsonType = JsonTypeUtilities::ThrowIfNotJsonType($jsonType);
467
468
                return JsonTypeUtilities::DaftJsonFromJsonType($jsonType, $propVal, $writeAll);
469
            };
470
    }
471
472
    /**
473
    * @param scalar|array|object|null $value
474
    *
475
    * @return scalar|array|object|null
476
    */
477
    private function MaybeModifyValueBeforeNudge(
478
        string $property,
479
        $value,
480
        bool $autoTrimStrings = self::BOOL_DEFAULT_AUTOTRIMSTRINGS,
481
        bool $throwIfNotUnique = self::BOOL_DEFAULT_THROWIFNOTUNIQUE
482
    ) {
483
        $spec = null;
484
485
        if (
486
            is_a(
487
                static::class,
488
                DaftObjectHasPropertiesWithMultiTypedArraysOfUniqueValues::class,
489
                true
490
            )
491
        ) {
492
            $spec = (
493
                static::DaftObjectPropertiesWithMultiTypedArraysOfUniqueValues()[$property] ?? null
494
            );
495
        }
496
497
        if (is_array($spec)) {
498
            $value = DefinitionAssistant::MaybeThrowIfValueDoesNotMatchMultiTypedArray(
499
                $autoTrimStrings,
500
                $throwIfNotUnique,
501
                $value,
502
                ...$spec
503
            );
504
        }
505
506
        if (is_string($value) && $autoTrimStrings) {
507
            $value = trim($value);
508
        }
509
510
        return $value;
511
    }
512
513
    /**
514
    * @see AbstractArrayBackedDaftObject::NudgePropertyValue()
515
    */
516
    private function MaybeThrowForPropertyOnNudge(string $property) : string
517
    {
518
        $properties = static::DaftObjectProperties();
519
520
        if ( ! in_array($property, $properties, DefinitionAssistant::IN_ARRAY_STRICT_MODE)) {
521
            throw Exceptions\Factory::UndefinedPropertyException(static::class, $property);
522
        } elseif ($this->DaftObjectWormPropertyWritten($property)) {
523
            throw Exceptions\Factory::PropertyNotRewriteableException(static::class, $property);
524
        }
525
526
        return $property;
527
    }
528
529
    /**
530
    * @param scalar|array|object|null $value
531
    *
532
    * @see AbstractArrayBackedDaftObject::NudgePropertyValue()
533
    */
534
    private function MaybeThrowOnNudge(string $property, $value, array $properties) : void
535
    {
536
        $property = $this->MaybeThrowForPropertyOnNudge($property);
537
538
        if (
539
            true === is_null($value) &&
540
            ! in_array($property, $properties, DefinitionAssistant::IN_ARRAY_STRICT_MODE)
541
        ) {
542
            throw Exceptions\Factory::PropertyNotNullableException(static::class, $property);
543
        }
544
    }
545
}
546