Completed
Push — master ( 33620a...af9e1a )
by Ondřej
02:56
created

StrictEnum   A

Complexity

Total Complexity 13

Size/Duplication

Total Lines 69
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 69
rs 10
c 0
b 0
f 0
wmc 13

8 Methods

Rating   Name   Duplication   Size   Complexity  
A compareTo() 0 9 4
A __callStatic() 0 3 1
A equals() 0 3 1
A getValueMap() 0 6 2
A getValue() 0 3 1
A __debugInfo() 0 5 1
A __toString() 0 3 1
A __construct() 0 8 2
1
<?php
2
declare(strict_types=1);
3
namespace Ivory\Value;
4
5
use Ivory\Exception\IncomparableException;
6
use Ivory\Value\Alg\IComparable;
7
8
/**
9
 * Base for enumeration classes, implementing a user-defined PostgreSQL enumeration type.
10
 *
11
 * For the subclasses, it is sufficient to implement just the {@link getValues()} method, which should return the list
12
 * of the enumeration values. E.g.:
13
 * <code>
14
 * <?php
15
 * class Planet extends StrictEnum
16
 * {
17
 *     protected static function getValues(): array
18
 *     {
19
 *         return ['Mercury', 'Venus', 'Earth', 'Mars', 'Jupiter', 'Saturn', 'Uranus', 'Neptune'];
20
 *     }
21
 * }
22
 * </code>
23
 *
24
 * Individual items are retrieved using the static method call syntax. Objects of the subclass are returned, which are
25
 * comparable to others:
26
 * <code>
27
 * <?php
28
 * $mars = Planet::Mars();
29
 * assert($mars == Planet::Mars());
30
 * assert($mars->compareTo(Planet::Jupiter()) < 0);
31
 * </code>
32
 *
33
 * Due to PHP `==` operator taking taking the class into consideration, enumeration objects may safely be compared
34
 * including their type:
35
 * <code>
36
 * <?php
37
 * class ChocolateBar extends StrictEnum
38
 * {
39
 *     protected static function getValues(): array
40
 *     {
41
 *         return ['Mars', 'Snickers', 'Twix'];
42
 *     }
43
 * }
44
 *
45
 * assert(ChocolateBar::Mars() == ChocolateBar::Mars());
46
 * assert(Planet::Mars() != ChocolateBar::Mars());
47
 * </code>
48
 *
49
 * Note, in order to let the IDE recognize the items, declare them in the class PHPDoc block using the &#64;method
50
 * annotation, such as: &#64;method static Planet Mercury()
51
 */
52
abstract class StrictEnum implements IComparable
53
{
54
    private static $valueMap = [];
55
    private $offset;
56
57
    /**
58
     * Returns the list of enumeration values as defined in the corresponding PostgreSQL enumeration type (including
59
     * mutual order).
60
     *
61
     * Note the values are case sensitive.
62
     *
63
     * @return string[]
64
     */
65
    abstract protected static function getValues(): array;
66
67
    private static function getValueMap(): array
68
    {
69
        if (!isset(self::$valueMap[static::class])) {
70
            self::$valueMap[static::class] = array_flip(static::getValues());
71
        }
72
        return self::$valueMap[static::class];
73
    }
74
75
    public static function __callStatic(string $name, array $arguments)
76
    {
77
        return new static($name);
78
    }
79
80
    final public function __construct(string $value)
81
    {
82
        $valueMap = self::getValueMap();
83
        if (!isset($valueMap[$value])) {
84
            throw new \InvalidArgumentException("`$value` is not among the defined enumeration values");
85
        }
86
87
        $this->offset = $valueMap[$value];
88
    }
89
90
    final public function getValue(): string
91
    {
92
        return static::getValues()[$this->offset];
93
    }
94
95
    final public function equals($other): bool
96
    {
97
        return ($this == $other);
98
    }
99
100
    final public function compareTo($other): int
101
    {
102
        if ($other === null) {
103
            throw new \InvalidArgumentException();
104
        }
105
        if (!$other instanceof StrictEnum || get_class($other) != static::class) {
106
            throw new IncomparableException();
107
        }
108
        return $this->offset - $other->offset;
109
    }
110
111
    final public function __toString()
112
    {
113
        return $this->getValue();
114
    }
115
116
    public function __debugInfo()
117
    {
118
        return [
119
            'offset' => $this->offset,
120
            'value' => $this->getValue(),
121
        ];
122
    }
123
}
124