Passed
Push — main ( 294a57...77dc3b )
by Carlos C
51s queued 12s
created

Enum::parentEntries()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 4
c 1
b 0
f 0
dl 0
loc 9
ccs 5
cts 5
cp 1
rs 10
cc 3
nc 2
nop 0
crap 3
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Eclipxe\Enum;
6
7
use Eclipxe\Enum\Exceptions\BadMethodCallException;
8
use Eclipxe\Enum\Exceptions\EnumConstructTypeError;
9
use Eclipxe\Enum\Exceptions\IndexNotFoundException;
10
use Eclipxe\Enum\Exceptions\ValueNotFoundException;
11
use Eclipxe\Enum\Internal\Entries;
12
use Eclipxe\Enum\Internal\EntriesPopulator;
13
use Eclipxe\Enum\Internal\Entry;
14
use Throwable;
15
16
abstract class Enum
0 ignored issues
show
Bug introduced by
A parse error occurred: Syntax error, unexpected T_ENUM, expecting T_STRING on line 16 at column 15
Loading history...
17
{
18
    /** @var Entry */
19
    private $content;
20
21 5
    final public function value(): string
22
    {
23 5
        return $this->content->value();
24
    }
25
26 5
    final public function index(): int
27
    {
28 5
        return $this->content->index();
29
    }
30
31 3
    final public function __toString(): string
32
    {
33 3
        return $this->content->value();
34
    }
35
36
    /**
37
     * Enum constructor.
38
     *
39
     * @param string|int|mixed $valueOrIndex
40
     *
41
     * @throws IndexNotFoundException if received argument is an integer and it was not found in indices
42
     * @throws ValueNotFoundException if received argument is a string and it was not found in values
43
     * @throws EnumConstructTypeError if received argument is not an integer, string, scalar or object
44
     */
45 25
    final public function __construct($valueOrIndex)
46
    {
47
        // convert to string if object
48 25
        if (is_object($valueOrIndex)) {
49
            try {
50 2
                $valueOrIndex = strval($valueOrIndex);
51 1
            } catch (Throwable $exception) {
52 1
                throw EnumConstructTypeError::create(static::class, $exception);
53
            }
54
        }
55
56 24
        if (is_int($valueOrIndex)) { // is index
57 19
            $entry = static::currentEntries()->findEntryByIndex($valueOrIndex);
58 18
            if (null === $entry) {
59 18
                throw IndexNotFoundException::create(static::class, strval($valueOrIndex));
60
            }
61 7
        } elseif (is_string($valueOrIndex)) { // is value
62 6
            $entry = static::currentEntries()->findEntryByValue($valueOrIndex);
63 5
            if (null === $entry) {
64 5
                throw ValueNotFoundException::create(static::class, $valueOrIndex);
65
            }
66
        } else {
67 1
            throw EnumConstructTypeError::create(static::class);
68
        }
69
70 19
        $this->content = $entry;
71 19
    }
72
73
    /**
74
     * @param string $name
75
     * @param mixed[] $arguments
76
     * @return mixed
77
     */
78 12
    public function __call(string $name, array $arguments)
79
    {
80 12
        if (strlen($name) > 2 && 'is' === substr($name, 0, 2)) {
81 9
            $entry = static::currentEntries()->findEntryByName(substr($name, 2));
82 9
            return (null !== $entry && $this->content->equals($entry));
83
        }
84
85 3
        throw BadMethodCallException::create(static::class, $name);
86
    }
87
88
    /**
89
     * @param string $name
90
     * @param mixed[] $arguments
91
     * @return static
92
     */
93 16
    public static function __callStatic(string $name, array $arguments)
94
    {
95 16
        $entry = static::currentEntries()->findEntryByName($name);
96 16
        if (null !== $entry) {
97 15
            return new static($entry->index());
98
        }
99
100 1
        throw BadMethodCallException::create(static::class, $name);
101
    }
102
103
    /**
104
     * Obtain the list of registered possible values as an array of indices and values
105
     *
106
     * @return array<int, string>
107
     */
108 4
    final public static function toArray(): array
109
    {
110 4
        return static::currentEntries()->toIndexValueArray();
111
    }
112
113
    /**
114
     * Method to override values
115
     *
116
     * It must return an array with key as the name declared in docblock
117
     * and value as the string value to use.
118
     *
119
     * Example:
120
     * method self extraSmall()
121
     * return ['extraSmall' => 'xs', ...];
122
     *
123
     * @return array<string, string>
124
     */
125 4
    protected static function overrideValues(): array
126
    {
127 4
        return [];
128
    }
129
130
    /**
131
     * Method to override indices
132
     *
133
     * It must return an array with key as the name declared in docblock
134
     * and value as the integer index to use.
135
     *
136
     * Example:
137
     * method self second()
138
     * return ['second' => 2, ...];
139
     *
140
     * @return array<string, int>
141
     */
142 4
    protected static function overrideIndices(): array
143
    {
144 4
        return [];
145
    }
146
147 28
    final protected static function currentEntries(): Entries
148
    {
149
        /*
150
         * $cache contains the list of current entries as [<class> => <entries>]
151
         * Store the information in this way because to prevent collision with parent classes
152
         */
153
        /** @var array<string, Entries> $cache */
154 28
        static $cache = [];
155 28
        if (! isset($cache[static::class])) {
156 6
            $cache[static::class] = self::createEntries();
157
        }
158 26
        return $cache[static::class];
159
    }
160
161 6
    final protected static function createEntries(): Entries
162
    {
163 6
        $populator = new EntriesPopulator(
164 6
            static::class,
165 6
            static::overrideValues(),
166 6
            static::overrideIndices(),
167 6
            static::parentEntries()
168
        );
169 6
        $entries = new Entries();
170 6
        $populator->populate($entries);
171 4
        return $entries;
172
    }
173
174 6
    final protected static function parentEntries(): Entries
175
    {
176 6
        $parentClass = strval(get_parent_class(static::class));
177
        // if does not have a parent class or is the base template (Enum class)
178 6
        if ('' === $parentClass || self::class === $parentClass) {
179 5
            return new Entries();
180
        }
181
        /** @var Enum $parentClass */
182 2
        return $parentClass::currentEntries();
183
    }
184
}
185