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.
Passed
Push — master ( a5c6de...fae6e1 )
by SignpostMarv
06:10
created

DefinitionAssistant   A

Complexity

Total Complexity 32

Size/Duplication

Total Lines 344
Duplicated Lines 0 %

Test Coverage

Coverage 97.22%

Importance

Changes 0
Metric Value
wmc 32
eloc 117
dl 0
loc 344
ccs 105
cts 108
cp 0.9722
rs 9.84
c 0
b 0
f 0

13 Methods

Rating   Name   Duplication   Size   Complexity  
A AutoRegisterType() 0 3 1
A RegisterAbstractDaftObjectType() 0 8 1
A MaybeThrowIfNotArrayIntKeys() 0 18 2
A MaybeRemapStringsToTrimmedStrings() 0 23 4
A MaybeRegisterAdditionalTypes() 0 30 2
A ObtainExpectedProperties() 0 16 4
A IsTypeUnregistered() 0 15 2
A SetterOrGetterClosure() 0 18 3
A RegisterDaftObjectTypeFromTypeAndProps() 0 19 1
A MaybeThrowIfValueDoesNotMatchMultiTypedArray() 0 21 3
A TypeAndGetterAndSetterClosureWithProps() 0 17 1
A MaybeThrowIfValueArrayDoesNotMatchTypes() 0 39 5
A MaybeThrowIfValueDoesNotMatchMultiTypedArrayValueArray() 0 23 3
1
<?php
2
/**
3
* @author SignpostMarv
4
*/
5
declare(strict_types=1);
6
7
namespace SignpostMarv\DaftObject;
8
9
use Closure;
10
use InvalidArgumentException;
11
use SignpostMarv\DaftMagicPropertyAnalysis\DefinitionAssistant as Base;
12
13
/**
14
* @template-extends Base<DaftObject>
15
*/
16
class DefinitionAssistant extends Base
17
{
18
    const BOOL_EXPECTING_GETTER = false;
19
20
    const BOOL_EXPECTING_SETTER = true;
21
22
    const INT_ARRAY_INDEX_TYPE = 0;
23
24
    const INT_ARRAY_INDEX_GETTER = 1;
25
26
    const INT_ARRAY_INDEX_SETTER = 2;
27
28
    const IS_A_STRINGS = true;
29
30
    /**
31
    * @psalm-param class-string<DaftObject> $type
32
    */
33 42
    public static function IsTypeUnregistered(string $type) : bool
34
    {
35 42
        if ( ! is_a($type, DaftObject::class, true)) {
36
            throw new InvalidArgumentException(
37
                'Argument 1 passed to ' .
38
                __METHOD__ .
39
                '() must be an implementation of ' .
40
                DaftObject::class .
41
                ', ' .
42
                $type .
43
                ' given!'
44
            );
45
        }
46
47 42
        return parent::IsTypeUnregistered($type);
48
    }
49
50
    /**
51
    * @psalm-param class-string<AbstractDaftObject> $maybe
52
    */
53 36
    public static function RegisterAbstractDaftObjectType(string $maybe) : void
54
    {
55
        /**
56
        * @var array<int, string>
57
        */
58 36
        $props = $maybe::PROPERTIES;
59
60 36
        static::RegisterDaftObjectTypeFromTypeAndProps($maybe, ...$props);
61 36
    }
62
63
    /**
64
    * {@inheritdoc}
65
    *
66
    * @psalm-param class-string<DaftObject>|DaftObject $maybe
67
    */
68 36
    public static function ObtainExpectedProperties($maybe) : array
69
    {
70
        /**
71
        * @psalm-var class-string<DaftObject>
72
        */
73 36
        $maybe = is_object($maybe) ? get_class($maybe) : $maybe;
74
75 36
        if (static::IsTypeUnregistered($maybe)) {
76 34
            if (is_a($maybe, AbstractDaftObject::class, true)) {
77 34
                static::RegisterAbstractDaftObjectType($maybe);
78
            }
79
        }
80
81 36
        $maybe = self::MaybeRegisterAdditionalTypes($maybe);
82
83 36
        return parent::ObtainExpectedProperties($maybe);
84
    }
85
86
    /**
87
    * @psalm-param class-string<DaftObject> $type
88
    */
89 4
    public static function AutoRegisterType(string $type, string ...$properties) : void
90
    {
91 4
        static::RegisterDaftObjectTypeFromTypeAndProps($type, ...$properties);
92 4
    }
93
94
    /**
95
    * @psalm-return Closure(string):?string
96
    */
97 38
    public static function SetterOrGetterClosure(
98
        string $type,
99
        bool $SetNotGet,
100
        string ...$props
101
    ) : Closure {
102
        return function (string $property) use ($type, $props, $SetNotGet) : ? string {
103 4
            if (in_array($property, $props, self::IN_ARRAY_STRICT_MODE)) {
104
                /**
105
                * @var string
106
                */
107 4
                $method = TypeUtilities::MethodNameFromProperty($property, $SetNotGet);
108
109 4
                if (method_exists($type, $method)) {
110 4
                    return $method;
111
                }
112
            }
113
114 2
            return null;
115 38
        };
116
    }
117
118
    /**
119
    * @param mixed $value
120
    *
121
    * @return array<int, mixed> filtered $value
122
    */
123 14
    public static function MaybeThrowIfValueDoesNotMatchMultiTypedArray(
124
        bool $autoTrimStrings,
125
        bool $throwIfNotUnique,
126
        $value,
127
        string ...$types
128
    ) : array {
129 14
        if ( ! is_array($value)) {
130 2
            throw new InvalidArgumentException(
131
                'Argument 3 passed to ' .
132
                __METHOD__ .
133
                ' must be an array, ' .
134 2
                (is_object($value) ? get_class($value) : gettype($value)) .
135 2
                ' given!'
136
            );
137
        }
138
139 12
        return static::MaybeThrowIfValueDoesNotMatchMultiTypedArrayValueArray(
140 12
            $autoTrimStrings,
141 12
            $throwIfNotUnique,
142 12
            $value,
143 9
            ...$types
144
        );
145
    }
146
147
    /**
148
    * @psalm-param class-string<DaftObject> $type
149
    *
150
    * @psalm-return array{0:class-string<DaftObject>, 1:null|Closure(string):?string, 2:null|Closure(string):?string, 4:string}
151
    */
152 38
    private static function TypeAndGetterAndSetterClosureWithProps(
153
        string $type,
154
        string ...$props
155
    ) : array {
156
        /**
157
        * @psalm-var array{0:class-string<DaftObject>, 1:null|Closure(string):?string, 2:null|Closure(string):?string, 4:string}
158
        */
159 38
        $out = array_merge(
160
            [
161 38
                $type,
162 38
                static::SetterOrGetterClosure($type, self::BOOL_EXPECTING_GETTER, ...$props),
163 38
                static::SetterOrGetterClosure($type, self::BOOL_EXPECTING_SETTER, ...$props),
164
            ],
165 38
            $props
166
        );
167
168 38
        return $out;
169
    }
170
171
    /**
172
    * @psalm-param class-string<DaftObject> $maybe
173
    *
174
    * @psalm-return class-string<DaftObject>
175
    */
176 38
    private static function RegisterDaftObjectTypeFromTypeAndProps(
177
        string $maybe,
178
        string ...$props
179
    ) : string {
180 38
        $args = static::TypeAndGetterAndSetterClosureWithProps($maybe, ...$props);
181
182
        /**
183
        * @var array<int, string>
184
        */
185 38
        $props = array_slice($args, 3);
186
187 38
        static::RegisterType(
188 38
            $args[self::INT_ARRAY_INDEX_TYPE],
189 38
            $args[self::INT_ARRAY_INDEX_GETTER],
190 38
            $args[self::INT_ARRAY_INDEX_SETTER],
191 19
            ...$props
192
        );
193
194 38
        return self::MaybeRegisterAdditionalTypes($args[self::INT_ARRAY_INDEX_TYPE]);
195
    }
196
197
    /**
198
    * @psalm-param class-string<DaftObject> $maybe
199
    *
200
    * @psalm-return class-string<DaftObject>
201
    */
202 38
    private static function MaybeRegisterAdditionalTypes(string $maybe) : string
203
    {
204 38
        return array_reduce(
205 38
            array_filter(
206
                [
207 38
                    DefinesOwnArrayIdInterface::class,
208
                    DefinesOwnIntegerIdInterface::class,
209
                    DefinesOwnStringIdInterface::class,
210
                ],
211
                function (string $otherType) use ($maybe) : bool {
212 38
                    return $otherType !== $maybe;
213 38
                }
214
            ),
215
            /**
216
            * @psalm-param class-string<DaftObject> $maybe
217
            * @psolm-param class-string<DaftObject> $otherType
218
            */
219
            function (string $maybe, string $otherType) : string {
220
                /**
221
                * @psalm-var class-string<DaftObject>
222
                */
223 38
                $otherType = $otherType;
224
225 38
                if (self::IsTypeUnregistered($otherType)) {
226 4
                    self::RegisterDaftObjectTypeFromTypeAndProps($otherType, 'id');
227
                }
228
229 38
                return $maybe;
230 38
            },
231 38
            $maybe
232
        );
233
    }
234
235
    /**
236
    * @return array<int, mixed> filtered $value
237
    */
238 12
    private static function MaybeThrowIfValueDoesNotMatchMultiTypedArrayValueArray(
239
        bool $autoTrimStrings,
240
        bool $throwIfNotUnique,
241
        array $value,
242
        string ...$types
243
    ) : array {
244 12
        $value = static::MaybeThrowIfNotArrayIntKeys($value);
245 10
        $value = static::MaybeThrowIfValueArrayDoesNotMatchTypes($value, ...$types);
246 8
        $value = static::MaybeRemapStringsToTrimmedStrings($value, $autoTrimStrings, ...$types);
247
248 8
        $initialCount = count($value);
249
250 8
        $value = array_unique($value, SORT_REGULAR);
251
252 8
        if ($throwIfNotUnique && count($value) !== $initialCount) {
253 2
            throw new InvalidArgumentException(
254
                'Argument 3 passed to ' .
255
                __METHOD__ .
256 2
                ' contained non-unique values!'
257
            );
258
        }
259
260 6
        return array_values($value);
261
    }
262
263
    /**
264
    * @return array<int, mixed> filtered $value
265
    */
266 12
    private static function MaybeThrowIfNotArrayIntKeys(array $value) : array
267
    {
268 12
        $initialCount = count($value);
269
270
        /**
271
        * @var array<int, mixed>
272
        */
273 12
        $value = array_filter($value, 'is_int', ARRAY_FILTER_USE_KEY);
274
275 12
        if (count($value) !== $initialCount) {
276 2
            throw new InvalidArgumentException(
277
                'Argument 3 passed to ' .
278
                __METHOD__ .
279 2
                ' must be array<int, mixed>'
280
            );
281
        }
282
283 10
        return $value;
284
    }
285
286
    /**
287
    * @param array<int, mixed> $value
288
    *
289
    * @return array<int, mixed> filtered $value
290
    */
291 10
    private static function MaybeThrowIfValueArrayDoesNotMatchTypes(
292
        array $value,
293
        string ...$types
294
    ) : array {
295 10
        $initialCount = count($value);
296
297 10
        $value = array_filter(
298 10
            $value,
299
            /**
300
            * @param mixed $maybe
301
            */
302
            function ($maybe) use ($types) : bool {
303 10
                if (is_object($maybe)) {
304 8
                    foreach ($types as $maybeType) {
305 8
                        if (is_a($maybe, $maybeType)) {
306 8
                            return true;
307
                        }
308
                    }
309
310 2
                    return false;
311
                }
312
313 4
                return in_array(
314 4
                    gettype($maybe),
315 4
                    $types,
316 4
                    DefinitionAssistant::IN_ARRAY_STRICT_MODE
317
                );
318 10
            }
319
        );
320
321 10
        if (count($value) !== $initialCount) {
322 2
            throw new InvalidArgumentException(
323
                'Argument 3 passed to ' .
324
                __METHOD__ .
325 2
                ' contained values that did not match the provided types!'
326
            );
327
        }
328
329 8
        return $value;
330
    }
331
332
    /**
333
    * @param array<int, mixed> $value
334
    *
335
    * @return array<int, mixed>
336
    */
337 8
    private static function MaybeRemapStringsToTrimmedStrings(
338
        array $value,
339
        bool $autoTrimStrings,
340
        string ...$types
341
    ) : array {
342
        if (
343 8
            $autoTrimStrings &&
344 8
            in_array('string', $types, DefinitionAssistant::IN_ARRAY_STRICT_MODE)
345
        ) {
346 2
            $value = array_map(
347
                /**
348
                * @param mixed $maybe
349
                *
350
                * @return mixed
351
                */
352
                function ($maybe) {
353 2
                    return is_string($maybe) ? trim($maybe) : $maybe;
354 2
                },
355 2
                $value
356
            );
357
        }
358
359 8
        return $value;
360
    }
361
}
362