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.

EnumTrait::resolveMembers()   B
last analyzed

Complexity

Conditions 7
Paths 11

Size

Total Lines 29
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

Changes 2
Bugs 1 Features 0
Metric Value
cc 7
eloc 16
c 2
b 1
f 0
nc 11
nop 0
dl 0
loc 29
ccs 0
cts 0
cp 0
crap 56
rs 8.8333
1
<?php
2
declare(strict_types=1);
3
namespace Thunder\Platenum\Enum;
4
5
use Thunder\Platenum\Exception\PlatenumException;
6
7
/**
8
 * @template TMember
9
 * @template TValue
10
 *
11
 * @author Tomasz Kowalczyk <[email protected]>
12
 */
13
trait EnumTrait
14
{
15
    /** @var TMember */
0 ignored issues
show
Bug introduced by
The type Thunder\Platenum\Enum\TMember was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
16
    private $member;
17
    /** @var TValue */
0 ignored issues
show
Bug introduced by
The type Thunder\Platenum\Enum\TValue was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
18
    private $value;
19
20
    /** @var non-empty-array<string,non-empty-array<string,int|string>> */
0 ignored issues
show
Documentation Bug introduced by
The doc comment non-empty-array<string,n...ray<string,int|string>> at position 0 could not be parsed: Unknown type name 'non-empty-array' at position 0 in non-empty-array<string,non-empty-array<string,int|string>>.
Loading history...
21
    protected static $members = [];
22
    /** @var array<string,array<string,static>> */
23 26
    protected static $instances = [];
24
25 26
26 26
    /**
27 26
     * @param TMember $member
28
     * @param TValue $value
29
     */
30
    /* final */ private function __construct(string $member, $value)
31 38
    {
32
        $this->member = $member;
0 ignored issues
show
Documentation Bug introduced by
It seems like $member of type string is incompatible with the declared type Thunder\Platenum\Enum\TMember of property $member.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
33 38
        $this->value = $value;
34 38
    }
35 1
36
    /* --- CREATE --- */
37
38 37
    final public static function __callStatic(string $member, array $arguments)
39
    {
40
        $class = static::class;
41 45
        if($arguments) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $arguments of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
42
            throw PlatenumException::fromConstantArguments($class);
43 45
        }
44 45
45 9
        return static::fromMember($member);
46
    }
47
48 44
    final public static function fromMember(string $member): self
49 36
    {
50 10
        $class = static::class;
51 6
        if(isset(static::$instances[$class][$member])) {
52
            return static::$instances[$class][$member];
53
        }
54
55 26
        static::resolveMembers();
56
        if(false === array_key_exists($member, static::$members[$class])) {
57
            static::throwInvalidMemberException($member);
58
            static::throwDefaultInvalidMemberException($member);
59
        }
60
61
        /** @psalm-suppress UnsafeInstantiation,ArgumentTypeCoercion,PropertyTypeCoercion */
62 14
        return static::$instances[$class][$member] = new static($member, static::$members[$class][$member]);
63
    }
64 14
65 14
    /**
66 1
     * @param mixed $value
67
     * @return static
68
     */
69 13
    final public static function fromValue($value): self
70 11
    {
71 11
        $class = static::class;
72 5
        if(false === is_scalar($value)) {
73 3
            throw PlatenumException::fromIllegalValue($class, $value);
74
        }
75
76
        static::resolveMembers();
77 6
        $member = array_search($value, static::$members[$class], true);
78
        if(false === $member) {
79
            static::throwInvalidValueException($value);
80
            static::throwDefaultInvalidValueException($value);
81
        }
82
83
        /** @var string $member */
84 4
        return static::fromMember($member);
85
    }
86 4
87 2
    /**
88
     * @param static $enum
89
     * @return static
90 2
     */
91
    final public static function fromEnum($enum): self
92
    {
93
        if(false === $enum instanceof static) {
94
            throw PlatenumException::fromMismatchedClass(static::class, \get_class($enum));
95
        }
96
97 2
        return static::fromValue($enum->value);
98
    }
99 2
100 1
    /**
101
     * @psalm-suppress ReferenceConstraintViolation
102
     * @param static $enum
103
     * @param-out AbstractConstantsEnum|AbstractDocblockEnum|AbstractStaticEnum|AbstractCallbackEnum|AbstractAttributeEnum $enum
104 3
     */
105
    final public function fromInstance(&$enum): void
106 3
    {
107
        $enum = static::fromEnum($enum);
108 9
    }
109
110 9
    /**
111
     * @psalm-suppress UnusedForeachValue
112
     * @return list<static>
0 ignored issues
show
Bug introduced by
The type Thunder\Platenum\Enum\list was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
113
     */
114 2
    final public static function getInstances(): array
115
    {
116 2
        static::resolveMembers();
117
        foreach(static::$members[static::class] as $member => $value) {
118
            static::fromMember($member);
119 6
        }
120
121 6
        return array_values(static::$instances[static::class]);
0 ignored issues
show
Bug Best Practice introduced by
The expression return array_values(stat...stances[static::class]) returns the type array which is incompatible with the documented return type Thunder\Platenum\Enum\list.
Loading history...
122
    }
123
124
    /* --- EXCEPTIONS --- */
125
126
    /** @psalm-suppress UnusedParam */
127 3
    private static function throwInvalidMemberException(string $member): void
0 ignored issues
show
Unused Code introduced by
The parameter $member is not used and could be removed. ( Ignorable by Annotation )

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

127
    private static function throwInvalidMemberException(/** @scrutinizer ignore-unused */ string $member): void

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
128
    {
129 3
    }
130
131
    private static function throwDefaultInvalidMemberException(string $member): void
132
    {
133
        throw PlatenumException::fromInvalidMember(static::class, $member, static::$members[static::class]);
134 6
    }
135
136 6
    /**
137
     * @param mixed $value
138
     * @psalm-suppress UnusedParam
139
     */
140 9
    private static function throwInvalidValueException($value): void
0 ignored issues
show
Unused Code introduced by
The parameter $value is not used and could be removed. ( Ignorable by Annotation )

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

140
    private static function throwInvalidValueException(/** @scrutinizer ignore-unused */ $value): void

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
141
    {
142 9
    }
143
144
    /** @param mixed $value */
145 1
    private static function throwDefaultInvalidValueException($value): void
146
    {
147 1
        throw PlatenumException::fromInvalidValue(static::class, $value);
148
    }
149
150 1
    /* --- COMPARE --- */
151
152 1
    /** @param static $other */
153
    final public function equals($other): bool
154
    {
155
        return $other instanceof $this && $this->value === $other->value;
156
    }
157 8
158
    /* --- TRANSFORM --- */
159 8
160
    /** @return TMember */
161 7
    final public function getMember(): string
162
    {
163
        return $this->member;
164
    }
165 8
166
    /** @return TValue */
167 8
    final public function getValue()
168
    {
169 8
        return $this->value;
170
    }
171
172 1
    /** @psalm-suppress MissingReturnType */
173
    #[\ReturnTypeWillChange]
174 1
    final public function jsonSerialize()
175
    {
176
        return $this->getValue();
177
    }
178 1
179
    final public function __toString(): string
180 1
    {
181
        return (string)$this->getValue();
182
    }
183
184
    /* --- CHECK --- */
185
186 6
    final public static function memberExists(string $member): bool
187
    {
188 6
        static::resolveMembers();
189 5
190 3
        return array_key_exists($member, static::$members[static::class]);
191
    }
192
193 1
    /** @param int|string $value */
194
    final public static function valueExists($value): bool
195
    {
196
        static::resolveMembers();
197 7
198
        return \in_array($value, static::$members[static::class], true);
199 7
    }
200 5
201 3
    /** @param list<string> $members */
202
    final public static function membersExist(array $members): bool
203
    {
204 2
        static::resolveMembers();
205
206
        return [] !== array_intersect(array_keys(static::$members[static::class]), $members);
207 1
    }
208
209 1
    /** @param list<int|string> $values */
210
    final public static function valuesExist(array $values): bool
211 1
    {
212
        static::resolveMembers();
213
214 1
        return [] !== array_intersect(static::$members[static::class], $values);
215
    }
216 1
217
    /** @param TMember $member */
218 1
    final public function hasMember(string $member): bool
219
    {
220
        return $member === $this->member;
221 5
    }
222
223 5
    /** @param TValue $value */
224
    final public function hasValue($value): bool
225 5
    {
226
        return $value === $this->value;
227
    }
228
229
    /** @param list<TMember> $members */
230 74
    final public function hasMemberIn(array $members): bool
231
    {
232 74
        return in_array($this->member, $members, true);
233 74
    }
234 15
235
    /** @param list<TValue> $values */
236
    final public function hasValueIn(array $values): bool
237 73
    {
238 1
        return in_array($this->value, $values, true);
239 73
    }
240
241
    /** @param list<static> $enums */
242 73
    final public function isIn(array $enums): bool
243
    {
244 73
        return in_array($this, $enums, true);
245 66
    }
246 1
247
    final public static function isMemberWarm(string $member): bool
248 65
    {
249 1
        return self::memberExists($member)
250
            && array_key_exists(static::class, static::$instances)
251
            && array_key_exists($member, static::$instances[static::class]);
252 64
    }
253 1
254
    /* --- INFO --- */
255 63
256 1
    /** @return int|string */
257
    final public static function memberToValue(string $member)
258
    {
259 62
        if(false === static::memberExists($member)) {
260 62
            static::throwInvalidMemberException($member);
261
            static::throwDefaultInvalidMemberException($member);
262
        }
263
264 1
        return static::$members[static::class][$member];
265
    }
266 1
267
    /** @param int|string $value */
268
    final public static function valueToMember($value): string
269 1
    {
270
        if(false === static::valueExists($value)) {
271 1
            static::throwInvalidValueException($value);
272
            static::throwDefaultInvalidValueException($value);
273
        }
274 1
275
        return (string)array_search($value, static::$members[static::class], true);
276 1
    }
277
278
    final public static function getMembers(): array
279
    {
280 1
        static::resolveMembers();
281
282 1
        return array_keys(static::$members[static::class]);
283
    }
284
285
    final public static function getValues(): array
286 1
    {
287
        static::resolveMembers();
288 1
289
        return array_values(static::$members[static::class]);
290
    }
291
292 1
    final public static function getMembersAndValues(): array
293
    {
294 1
        static::resolveMembers();
295
296
        return static::$members[static::class];
297 1
    }
298
299 1
    /* --- SOURCE --- */
300
301
    private static function resolveMembers(): void
302
    {
303
        $class = static::class;
304
        if(isset(static::$members[$class])) {
305
            return;
306
        }
307
308
        $throwMissingResolve = function(string $class): void {
309
            throw PlatenumException::fromMissingResolve($class);
310
        };
311
        // reflection instead of method_exists because of PHP 7.4 bug #78632
312
        // @see https://bugs.php.net/bug.php?id=78632
313
        $hasResolve = (new \ReflectionClass($class))->hasMethod('resolve');
314
        /** @var array<string,int|string> $members */
315
        $members = $hasResolve ? static::resolve() : $throwMissingResolve($class);
0 ignored issues
show
Bug introduced by
The method resolve() does not exist on Thunder\Platenum\Enum\EnumTrait. Since you implemented __callStatic, consider adding a @method annotation. ( Ignorable by Annotation )

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

315
        $members = $hasResolve ? static::/** @scrutinizer ignore-call */ resolve() : $throwMissingResolve($class);
Loading history...
316
        if(empty($members)) {
317
            throw PlatenumException::fromEmptyMembers($class);
318
        }
319
        if(\count($members) !== \count(\array_unique($members))) {
320
            throw PlatenumException::fromNonUniqueMembers($class);
321
        }
322
        if(['string'] !== \array_unique(\array_map('gettype', array_keys($members)))) {
323
            throw PlatenumException::fromNonStringMembers($class);
324
        }
325
        if(1 !== \count(\array_unique(\array_map('gettype', $members)))) {
326
            throw PlatenumException::fromNonUniformMemberValues($class, $members);
327
        }
328
329
        static::$members[$class] = $members;
330
    }
331
332
    /* --- MAGIC --- */
333
334
    final public function __clone()
335
    {
336
        throw PlatenumException::fromMagicMethod(static::class, __FUNCTION__);
337
    }
338
339
    final public function __call(string $name, array $arguments)
340
    {
341
        throw PlatenumException::fromMagicMethod(static::class, __FUNCTION__);
342
    }
343
344
    final public function __invoke()
345
    {
346
        throw PlatenumException::fromMagicMethod(static::class, __FUNCTION__);
347
    }
348
349
    /** @param mixed $name */
350
    final public function __isset($name)
351
    {
352
        throw PlatenumException::fromMagicMethod(static::class, __FUNCTION__);
353
    }
354
355
    /** @param mixed $name */
356
    final public function __unset($name)
357
    {
358
        throw PlatenumException::fromMagicMethod(static::class, __FUNCTION__);
359
    }
360
361
    /** @param mixed $value */
362
    final public function __set(string $name, $value)
363
    {
364
        throw PlatenumException::fromMagicMethod(static::class, __FUNCTION__);
365
    }
366
367
    final public function __get(string $name)
368
    {
369
        throw PlatenumException::fromMagicMethod(static::class, __FUNCTION__);
370
    }
371
}
372