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
Pull Request — master (#24)
by Tomasz
07:22
created

EnumTrait::fromMemberAndValue()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 2
dl 0
loc 4
ccs 2
cts 2
cp 1
crap 1
rs 10
1
<?php
2
declare(strict_types=1);
3
namespace Thunder\Platenum\Enum;
4
5
use Thunder\Platenum\Exception\PlatenumException;
6
7
/**
8
 * @author Tomasz Kowalczyk <[email protected]>
9
 * @psalm-template T
10
 * @psalm-immutable
11
 */
12
trait EnumTrait
13
{
14
    /** @var string */
15
    private $member;
16
    /** @psalm-var T */
17
    private $value;
18
19
    /** @psalm-var non-empty-array<string,non-empty-array<string,int|string>> */
20
    protected static $members = [];
21
    /** @var array<string,array<string,static>> */
22
    protected static $instances = [];
23
24
    /** @psalm-param T $value */
25 26
    final private function __construct(string $member, $value)
26
    {
27 26
        $this->member = $member;
28 26
        $this->value = $value;
29 26
    }
30
31
    /* --- CREATE --- */
32
33 38
    final public static function __callStatic(string $member, array $arguments)
34
    {
35 38
        $class = static::class;
36 38
        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...
37 1
            throw PlatenumException::fromConstantArguments($class);
38
        }
39
40 37
        return static::fromMember($member);
41
    }
42
43 45
    final public static function fromMember(string $member): self
44
    {
45 45
        $class = static::class;
46 45
        if(isset(static::$instances[$class][$member])) {
47 9
            return static::$instances[$class][$member];
48
        }
49
50 44
        static::resolveMembers();
51 36
        if(false === array_key_exists($member, static::$members[$class])) {
52 10
            static::throwInvalidMemberException($member);
53 6
            static::throwDefaultInvalidMemberException($member);
54
        }
55
56 26
        return static::$instances[$class][$member] = static::fromMemberAndValue($member, static::$members[$class][$member]);
57
    }
58
59
    /**
60
     * @psalm-param int|string $value
61
     * @psalm-return static
62
     */
63 26
    final private static function fromMemberAndValue(string $member, $value): self
64
    {
65
        /** @psalm-suppress UnsafeInstantiation */
66 26
        return new static($member, $value);
67
    }
68
69
    /**
70
     * @param mixed $value
71
     * @return static
72
     */
73 14
    final public static function fromValue($value): self
74
    {
75 14
        $class = static::class;
76 14
        if(false === is_scalar($value)) {
77 1
            throw PlatenumException::fromIllegalValue($class, $value);
78
        }
79
80 13
        static::resolveMembers();
81 11
        $member = array_search($value, static::$members[$class], true);
82 11
        if(false === $member) {
83 5
            static::throwInvalidValueException($value);
84 3
            static::throwDefaultInvalidValueException($value);
85
        }
86
87
        /** @var string $member */
88 6
        return static::fromMember($member);
89
    }
90
91
    /**
92
     * @param static $enum
93
     * @return static
94
     */
95 4
    final public static function fromEnum($enum): self
96
    {
97 4
        if(false === $enum instanceof static) {
98 2
            throw PlatenumException::fromMismatchedClass(static::class, \get_class($enum));
99
        }
100
101 2
        return static::fromValue($enum->value);
102
    }
103
104
    /**
105
     * @param static &$enum
106
     * @param-out static $enum
107
     */
108 2
    final public function fromInstance(&$enum): void
109
    {
110 2
        $enum = static::fromEnum($enum);
111 1
    }
112
113
    /* --- EXCEPTIONS --- */
114
115 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

115
    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...
116
    {
117 3
    }
118
119 9
    private static function throwDefaultInvalidMemberException(string $member): void
120
    {
121 9
        throw PlatenumException::fromInvalidMember(static::class, $member, static::$members[static::class]);
122
    }
123
124
    /** @param mixed $value */
125 2
    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

125
    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...
126
    {
127 2
    }
128
129
    /** @param mixed $value */
130 6
    private static function throwDefaultInvalidValueException($value): void
131
    {
132 6
        throw PlatenumException::fromInvalidValue(static::class, $value);
133
    }
134
135
    /* --- COMPARE --- */
136
137
    /** @param static $other */
138 3
    final public function equals($other): bool
139
    {
140 3
        return $other instanceof $this && $this->value === $other->value;
141
    }
142
143
    /* --- TRANSFORM --- */
144
145 6
    final public function getMember(): string
146
    {
147 6
        return $this->member;
148
    }
149
150
    /** @psalm-return T */
151 9
    final public function getValue()
152
    {
153 9
        return $this->value;
154
    }
155
156
    /** @psalm-return T */
157 1
    final public function jsonSerialize()
158
    {
159 1
        return $this->getValue();
160
    }
161
162 1
    final public function __toString(): string
163
    {
164 1
        return (string)$this->getValue();
165
    }
166
167
    /* --- CHECK --- */
168
169 8
    final public static function memberExists(string $member): bool
170
    {
171 8
        static::resolveMembers();
172
173 7
        return array_key_exists($member, static::$members[static::class]);
174
    }
175
176
    /** @param int|string $value */
177 8
    final public static function valueExists($value): bool
178
    {
179 8
        static::resolveMembers();
180
181 8
        return \in_array($value, static::$members[static::class], true);
182
    }
183
184 1
    final public function hasMember(string $members): bool
185
    {
186 1
        return $members === $this->member;
187
    }
188
189
    /** @psalm-param T $value */
190 1
    final public function hasValue($value): bool
191
    {
192 1
        return $value === $this->value;
193
    }
194
195
    /* --- INFO --- */
196
197
    /** @return int|string */
198 6
    final public static function memberToValue(string $member)
199
    {
200 6
        if(false === static::memberExists($member)) {
201 5
            static::throwInvalidMemberException($member);
202 3
            static::throwDefaultInvalidMemberException($member);
203
        }
204
205 1
        return static::$members[static::class][$member];
206
    }
207
208
    /** @param int|string $value */
209 7
    final public static function valueToMember($value): string
210
    {
211 7
        if(false === static::valueExists($value)) {
212 5
            static::throwInvalidValueException($value);
213 3
            static::throwDefaultInvalidValueException($value);
214
        }
215
216 2
        return (string)array_search($value, static::$members[static::class], true);
217
    }
218
219 1
    final public static function getMembers(): array
220
    {
221 1
        static::resolveMembers();
222
223 1
        return array_keys(static::$members[static::class]);
224
    }
225
226 1
    final public static function getValues(): array
227
    {
228 1
        static::resolveMembers();
229
230 1
        return array_values(static::$members[static::class]);
231
    }
232
233 5
    final public static function getMembersAndValues(): array
234
    {
235 5
        static::resolveMembers();
236
237 5
        return static::$members[static::class];
238
    }
239
240
    /* --- SOURCE --- */
241
242 74
    final private static function resolveMembers(): void
243
    {
244 74
        $class = static::class;
245 74
        if(isset(static::$members[$class])) {
246 15
            return;
247
        }
248
249 73
        $throwMissingResolve = function(string $class): void {
250 1
            throw PlatenumException::fromMissingResolve($class);
251 73
        };
252
        // reflection instead of method_exists because of PHP 7.4 bug #78632
253
        // @see https://bugs.php.net/bug.php?id=78632
254 73
        $hasResolve = (new \ReflectionClass($class))->hasMethod('resolve');
255
        /** @psalm-var array<string,T> $members */
256 73
        $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

256
        $members = $hasResolve ? static::/** @scrutinizer ignore-call */ resolve() : $throwMissingResolve($class);
Loading history...
257 66
        if(empty($members)) {
258 1
            throw PlatenumException::fromEmptyMembers($class);
259
        }
260 65
        if(\count($members) !== \count(\array_unique($members))) {
0 ignored issues
show
Bug introduced by
It seems like $members can also be of type Thunder\Platenum\Enum\EnumTrait; however, parameter $array of array_unique() does only seem to accept array, 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

260
        if(\count($members) !== \count(\array_unique(/** @scrutinizer ignore-type */ $members))) {
Loading history...
Bug introduced by
It seems like $members can also be of type Thunder\Platenum\Enum\EnumTrait; however, parameter $var of count() does only seem to accept Countable|array, 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

260
        if(\count(/** @scrutinizer ignore-type */ $members) !== \count(\array_unique($members))) {
Loading history...
261 1
            throw PlatenumException::fromNonUniqueMembers($class);
262
        }
263
        /** @psalm-suppress RedundantCondition */
264 64
        if(['string'] !== \array_unique(\array_map('gettype', array_keys($members)))) {
0 ignored issues
show
Bug introduced by
It seems like $members can also be of type Thunder\Platenum\Enum\EnumTrait; however, parameter $input of array_keys() does only seem to accept array, 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

264
        if(['string'] !== \array_unique(\array_map('gettype', array_keys(/** @scrutinizer ignore-type */ $members)))) {
Loading history...
265 1
            throw PlatenumException::fromNonStringMembers($class);
266
        }
267 63
        if(1 !== \count(\array_unique(\array_map('gettype', $members)))) {
0 ignored issues
show
Bug introduced by
It seems like $members can also be of type Thunder\Platenum\Enum\EnumTrait; however, parameter $arr1 of array_map() does only seem to accept array, 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

267
        if(1 !== \count(\array_unique(\array_map('gettype', /** @scrutinizer ignore-type */ $members)))) {
Loading history...
268 1
            throw PlatenumException::fromNonUniformMemberValues($class, $members);
0 ignored issues
show
Bug introduced by
It seems like $members can also be of type Thunder\Platenum\Enum\EnumTrait; however, parameter $members of Thunder\Platenum\Excepti...onUniformMemberValues() does only seem to accept array, 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

268
            throw PlatenumException::fromNonUniformMemberValues($class, /** @scrutinizer ignore-type */ $members);
Loading history...
269
        }
270
271 62
        static::$members[$class] = $members;
272 62
    }
273
274
    /* --- MAGIC --- */
275
276 1
    final public function __clone()
277
    {
278 1
        throw PlatenumException::fromMagicMethod(static::class, __FUNCTION__);
279
    }
280
281 1
    final public function __call(string $name, array $arguments)
282
    {
283 1
        throw PlatenumException::fromMagicMethod(static::class, __FUNCTION__);
284
    }
285
286 1
    final public function __invoke()
287
    {
288 1
        throw PlatenumException::fromMagicMethod(static::class, __FUNCTION__);
289
    }
290
291
    /** @param mixed $name */
292 1
    final public function __isset($name)
293
    {
294 1
        throw PlatenumException::fromMagicMethod(static::class, __FUNCTION__);
295
    }
296
297
    /** @param mixed $name */
298 1
    final public function __unset($name)
299
    {
300 1
        throw PlatenumException::fromMagicMethod(static::class, __FUNCTION__);
301
    }
302
303
    /** @param mixed $value */
304 1
    final public function __set(string $name, $value)
305
    {
306 1
        throw PlatenumException::fromMagicMethod(static::class, __FUNCTION__);
307
    }
308
309 1
    final public function __get(string $name)
310
    {
311 1
        throw PlatenumException::fromMagicMethod(static::class, __FUNCTION__);
312
    }
313
}
314