Passed
Pull Request — master (#56)
by Brent
01:34
created

Enum   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 120
Duplicated Lines 0 %

Importance

Changes 33
Bugs 5 Features 3
Metric Value
wmc 20
eloc 46
c 33
b 5
f 3
dl 0
loc 120
rs 10

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __get() 0 8 3
A resolveDefinition() 0 29 3
A labels() 0 3 1
A __callStatic() 0 3 1
A findDefinition() 0 9 3
A equals() 0 12 4
A values() 0 3 1
A __construct() 0 12 2
A toArray() 0 9 2
1
<?php
2
3
namespace Spatie\Enum;
4
5
use BadMethodCallException;
6
use ReflectionClass;
7
8
/**
9
 * @property-read string value
10
 * @property-read string label
11
 */
12
abstract class Enum
13
{
14
    /** @var mixed */
15
    protected $value;
16
17
    protected string $label;
18
19
    private static array $definitionCache = [];
20
21
    public static function toArray(): array
22
    {
23
        $array = [];
24
25
        foreach (static::resolveDefinition() as $definition) {
26
            $array[$definition->value] = $definition->label;
27
        }
28
29
        return $array;
30
    }
31
32
    /**
33
     * @param mixed $value
34
     */
35
    public function __construct($value)
36
    {
37
        $definition = $this->findDefinition($value);
38
39
        if ($definition === null) {
40
            $enumClass = static::class;
41
42
            throw new BadMethodCallException("There's no value {$value} defined for enum {$enumClass}, consider adding it in the docblock definition.");
43
        }
44
45
        $this->value = $definition->value;
0 ignored issues
show
Bug introduced by
The property value is declared read-only in Spatie\Enum\Enum.
Loading history...
46
        $this->label = $definition->label;
0 ignored issues
show
Bug introduced by
The property label is declared read-only in Spatie\Enum\Enum.
Loading history...
47
    }
48
49
    public function __get($name)
50
    {
51
        if ($name === 'label') {
52
            return $this->label;
53
        }
54
55
        if ($name === 'value') {
56
            return $this->value;
57
        }
58
    }
59
60
    public static function __callStatic(string $name, array $arguments)
61
    {
62
        return new static($name);
63
    }
64
65
    public function equals(Enum ...$others): bool
66
    {
67
        foreach ($others as $other) {
68
            if (
69
                get_class($this) === get_class($other)
70
                && $this->value === $other->value
71
            ) {
72
                return true;
73
            }
74
        }
75
76
        return false;
77
    }
78
79
    protected static function values(): array
80
    {
81
        return [];
82
    }
83
84
    protected static function labels(): array
85
    {
86
        return [];
87
    }
88
89
    private function findDefinition(string $input): ?EnumDefinition
90
    {
91
        foreach (static::resolveDefinition() as $definition) {
92
            if ($definition->equals($input)) {
93
                return $definition;
94
            }
95
        }
96
97
        return null;
98
    }
99
100
    /**
101
     * @return \Spatie\Enum\EnumDefinition[]|null
102
     */
103
    private static function resolveDefinition(): array
104
    {
105
        $className = static::class;
106
107
        if (static::$definitionCache[$className] ?? null) {
0 ignored issues
show
Bug introduced by
Since $definitionCache is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $definitionCache to at least protected.
Loading history...
108
            return static::$definitionCache[$className];
109
        }
110
111
        $reflectionClass = new ReflectionClass($className);
112
113
        $docComment = $reflectionClass->getDocComment();
114
115
        preg_match_all('/@method static self ([\w_]+)\(\)/', $docComment, $matches);
116
117
        $definition = [];
118
119
        $valueMap = static::values();
120
121
        $labelMap = static::labels();
122
123
        foreach ($matches[1] as $methodName) {
124
            $definition[$methodName] = new EnumDefinition(
125
                $methodName,
126
                $valueMap[$methodName] ?? $methodName,
127
                $labelMap[$methodName] ?? $methodName,
128
            );
129
        }
130
131
        return static::$definitionCache[$className] ??= $definition;
132
    }
133
}
134