Enum   A
last analyzed

Complexity

Total Complexity 21

Size/Duplication

Total Lines 118
Duplicated Lines 0 %

Test Coverage

Coverage 95.65%

Importance

Changes 2
Bugs 0 Features 1
Metric Value
eloc 35
c 2
b 0
f 1
dl 0
loc 118
ccs 44
cts 46
cp 0.9565
rs 10
wmc 21

18 Methods

Rating   Name   Duplication   Size   Complexity  
A create() 0 3 1
A attributes() 0 3 1
A equals() 0 3 1
A match() 0 3 1
A value() 0 3 1
A __toString() 0 3 1
A values() 0 3 1
A isValid() 0 3 1
A getEnumAttributes() 0 3 1
A bindEnumAttributes() 0 6 1
A key() 0 3 1
A __callStatic() 0 9 2
A instantiate() 0 9 2
A getConstantsFrom() 0 3 1
A associates() 0 4 1
A __construct() 0 7 2
A throwErrorForInvalidValue() 0 3 1
A attribute() 0 5 1
1
<?php
2
/**
3
 * Created by enea dhack - 08/07/2020 16:59.
4
 */
5
6
namespace Vaened\Enum;
7
8
use BadMethodCallException;
9
use ReflectionClass;
10
use Stringable;
11
use UnexpectedValueException;
12
13
use function array_reduce;
14
15
abstract class Enum implements Enumerable, Stringable
16
{
17
    private string|int|float|bool $value;
18
19
    private static array $attributes = [];
20 20
21
    private static array $cache = [];
22 20
23 2
    protected function __construct(string|int|float|bool $value)
24
    {
25
        if (!self::isValid($value)) {
26 18
            $this->throwErrorForInvalidValue($value);
27 18
        }
28
29 20
        $this->value = $value;
30
    }
31 20
32
    public static function create(string|int|float|bool $value): static
33
    {
34 4
        return new static($value);
35
    }
36 4
37
    public static function instantiate(string $key): static
38 4
    {
39 2
        $values = static::associates();
40
41
        if (!isset($values[$key])) {
42 2
            throw new UnexpectedValueException("Key '$key' is not part of the enum " . static::class);
43
        }
44
45 22
        return static::create($values[$key]);
46
    }
47 22
48
    public static function isValid(string|int|float|bool $value): bool
49
    {
50 2
        return in_array($value, static::associates(), true);
51
    }
52 2
53
    public static function values(): array
54
    {
55 26
        return array_map(static fn(string|int|float|bool $value) => static::create($value), static::associates());
56
    }
57 26
58 26
    private static function associates(): array
59
    {
60
        $classname = static::class;
61 2
        return self::$cache[$classname] ??= static::getConstantsFrom($classname);
62
    }
63 2
64
    private static function getConstantsFrom(string $classname): array
65
    {
66 2
        return (new ReflectionClass($classname))->getConstants();
67
    }
68 2
69
    private static function getEnumAttributes(): array
70
    {
71 2
        return self::$attributes[static::class] ??= static::bindEnumAttributes();
72
    }
73
74 2
    private static function bindEnumAttributes(): array
75 2
    {
76 2
        return array_reduce(static::attributes(), static function (array $acc, Attributor $attribute): array {
77
            $acc[$attribute->getCase()] = $attribute->getAttributes();
78
            return $acc;
79
        }, []);
80
    }
81
82
    protected function throwErrorForInvalidValue(string|int|float|bool $value): void
83
    {
84 12
        throw new UnexpectedValueException("Value '$value' is not part of the enum " . static::class);
85
    }
86 12
87
    protected static function attributes(): array
88
    {
89 10
        return [];
90
    }
91 10
92
    public function value(): string|int|float|bool
93
    {
94 2
        return $this->value;
95
    }
96 2
97
    public function key(): string
98
    {
99 2
        return array_search($this->value, static::associates(), true);
100
    }
101 2
102 2
    public function equals(string|int|float|bool $value): bool
103 2
    {
104
        return $this->value() === $value;
105
    }
106 14
107
    public function match(Enumerable $value): bool
108 14
    {
109
        return $this->value() === $value->value();
110 14
    }
111 12
112
    protected function attribute(string $name): mixed
113
    {
114 2
        $constants  = static::getEnumAttributes();
115
        $attributes = $constants[$this->key()] ?? [];
116
        return $attributes[$name] ?? null;
117 2
    }
118
119 2
    public static function __callStatic(string $name, array $arguments): self
120
    {
121
        $values = static::associates();
122
123
        if (isset($values[$name])) {
124
            return static::create($values[$name]);
125
        }
126
127
        throw new BadMethodCallException("No static method or enum constant '$name' in enum " . static::class);
128
    }
129
130
    public function __toString(): string
131
    {
132
        return $this->value();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->value() could return the type boolean which is incompatible with the type-hinted return string. Consider adding an additional type-check to rule them out.
Loading history...
133
    }
134
}
135
136