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

Enum::resolveByString()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 12
rs 9.8666
c 0
b 0
f 0
cc 3
nc 3
nop 1
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
        return array_map(
24
            fn (EnumDefinition $definition) => $definition->label,
25
            static::resolveDefinition()
26
        );
27
    }
28
29
    /**
30
     * @param mixed $value
31
     */
32
    public function __construct($value)
33
    {
34
        $definition = $this->findDefinition($value);
35
36
        if ($definition === null) {
37
            $enumClass = static::class;
38
39
            throw new BadMethodCallException("There's no value {$value} defined for enum {$enumClass}, consider adding it in the docblock definition.");
40
        }
41
42
        $this->value = $definition->value;
0 ignored issues
show
Bug introduced by
The property value is declared read-only in Spatie\Enum\Enum.
Loading history...
43
        $this->label = $definition->label;
0 ignored issues
show
Bug introduced by
The property label is declared read-only in Spatie\Enum\Enum.
Loading history...
44
    }
45
46
    public function __get($name)
47
    {
48
        if ($name === 'label') {
49
            return $this->label;
50
        }
51
52
        if ($name === 'value') {
53
            return $this->value;
54
        }
55
    }
56
57
    public static function __callStatic(string $name, array $arguments)
58
    {
59
        return new static($name);
60
    }
61
62
    public function equals(Enum ...$others): bool
63
    {
64
        foreach ($others as $other) {
65
            if (
66
                get_class($this) === get_class($other)
67
                && $this->value === $other->value
68
            ) {
69
                return true;
70
            }
71
        }
72
73
        return false;
74
    }
75
76
    protected static function values(): array
77
    {
78
        return [];
79
    }
80
81
    protected static function labels(): array
82
    {
83
        return [];
84
    }
85
86
    private function findDefinition(string $input): ?EnumDefinition
87
    {
88
        foreach (static::resolveDefinition() as $definition) {
89
            if ($definition->equals($input)) {
90
                return $definition;
91
            }
92
        }
93
94
        return null;
95
    }
96
97
    /**
98
     * @return \Spatie\Enum\EnumDefinition[]|null
99
     */
100
    private static function resolveDefinition(): array
101
    {
102
        $className = static::class;
103
104
        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...
105
            return static::$definitionCache[$className];
106
        }
107
108
        $reflectionClass = new ReflectionClass($className);
109
110
        $docComment = $reflectionClass->getDocComment();
111
112
        preg_match_all('/@method static self ([\w_]+)\(\)/', $docComment, $matches);
113
114
        $definition = [];
115
116
        $valueMap = static::values();
117
118
        $labelMap = static::labels();
119
120
        foreach ($matches[1] as $methodName) {
121
            $definition[$methodName] = new EnumDefinition(
122
                $methodName,
123
                $valueMap[$methodName] ?? $methodName,
124
                $labelMap[$methodName] ?? $methodName,
125
            );
126
        }
127
128
        return static::$definitionCache[$className] ??= $definition;
129
    }
130
}
131