Completed
Push — master ( e61af3...334344 )
by Peter
05:18
created

ReflectionEnum   A

Complexity

Total Complexity 27

Size/Duplication

Total Lines 238
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 98.53%

Importance

Changes 0
Metric Value
wmc 27
lcom 1
cbo 4
dl 0
loc 238
ccs 67
cts 68
cp 0.9853
rs 10
c 0
b 0
f 0

16 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A value() 0 4 1
A equals() 0 4 3
A isValid() 0 4 1
A __toString() 0 4 1
A __clone() 0 4 1
A serialize() 0 4 1
A unserialize() 0 4 1
A byValue() 0 18 3
A values() 0 9 2
A choices() 0 9 2
A detectConstants() 0 18 3
A constants() 0 7 1
A constant() 0 4 1
A __call() 0 11 2
A __callStatic() 0 15 3
1
<?php
2
3
/**
4
 * GpsLab component.
5
 *
6
 * @author    Peter Gribanov <[email protected]>
7
 * @copyright Copyright (c) 2011, Peter Gribanov
8
 * @license   http://opensource.org/licenses/MIT
9
 */
10
11
namespace GpsLab\Component\Enum;
12
13
use GpsLab\Component\Enum\Exception\BadMethodCallException;
14
use GpsLab\Component\Enum\Exception\OutOfEnumException;
15
16
abstract class ReflectionEnum implements Enum, \Serializable
17
{
18
    /**
19
     * @var mixed
20
     */
21
    private $value = '';
22
23
    /**
24
     * @var Enum[]
25
     */
26
    private static $instances = [];
27
28
    /**
29
     * @var mixed[][]
30
     */
31
    private static $create_methods = [];
32
33
    /**
34
     * @var mixed[][]
35
     */
36
    private static $is_methods = [];
37
38
    /**
39
     * @var mixed[][]
40
     */
41
    private static $constants = [];
42
43
    /**
44
     * @param mixed $value
45
     */
46 3
    final private function __construct($value)
47
    {
48 3
        $this->value = $value;
49 3
    }
50
51
    /**
52
     * @param mixed $value
53
     *
54
     * @return Enum
55
     */
56 39
    final public static function byValue($value)
57
    {
58 39
        $class = get_called_class();
59 39
        self::detectConstants($class);
60
61 39
        $method = array_search($value, self::$create_methods[$class], true);
62
63 39
        if ($method === false) {
64 3
            throw OutOfEnumException::create($value, $class);
65
        }
66
67
        // limitation of count object instances
68 36
        if (!isset(self::$instances[$class][$method])) {
69 3
            self::$instances[$class][$method] = new static($value);
70
        }
71
72 36
        return self::$instances[$class][$method];
73
    }
74
75
    /**
76
     * @return mixed
77
     */
78 25
    final public function value()
79
    {
80 25
        return $this->value;
81
    }
82
83
    /**
84
     * Available values.
85
     *
86
     * @return Enum[]
87
     */
88 3
    final public static function values()
89
    {
90 3
        $values = [];
91 3
        foreach (self::constants() as $constant => $value) {
92 3
            $values[$constant] = self::byValue($value);
93
        }
94
95 3
        return $values;
96
    }
97
98
    /**
99
     * @param Enum $enum
100
     *
101
     * @return bool
102
     */
103 10
    final public function equals(Enum $enum)
104
    {
105 10
        return $this === $enum || ($this->value() === $enum->value() && get_called_class() == get_class($enum));
106
    }
107
108
    /**
109
     * Is value supported.
110
     *
111
     * @param mixed $value
112
     *
113
     * @return bool
114
     */
115 10
    final public static function isValid($value)
116
    {
117 10
        return in_array($value, self::constants(), true);
118
    }
119
120
    /**
121
     * Get choices for radio group.
122
     *
123
     * <code>
124
     * {
125
     *   value1: 'Readable value 1',
126
     *   value2: 'Readable value 2',
127
     * }
128
     * </code>
129
     *
130
     * @return array
131
     */
132 3
    final public static function choices()
133
    {
134 3
        $choices = [];
135 3
        foreach (self::constants() as $value) {
136 3
            $choices[$value] = (string) self::byValue($value);
137
        }
138
139 3
        return $choices;
140
    }
141
142
    /**
143
     * Return readable value.
144
     *
145
     * @return string
146
     */
147 13
    public function __toString()
148
    {
149 13
        return $this->constant();
150
    }
151
152 3
    final public function __clone()
153
    {
154 3
        throw new \LogicException('Enumerations are not cloneable');
155
    }
156
157
    /**
158
     * @return mixed
159
     */
160 10
    public function serialize()
161
    {
162 10
        return serialize($this->value);
163
    }
164
165
    /**
166
     * @param mixed $data
167
     */
168 10
    public function unserialize($data)
169
    {
170 10
        self::byValue($this->value = unserialize($data));
171 10
    }
172
173
    /**
174
     * @param string $class
175
     */
176 54
    private static function detectConstants($class)
177
    {
178 54
        if (!isset(self::$create_methods[$class])) {
179 3
            self::$create_methods[$class] = [];
180 3
            self::$is_methods[$class] = [];
181 3
            self::$constants[$class] = [];
182
183 3
            foreach (ConstantDetector::detect($class) as $constant => $constant_value) {
184 3
                self::$constants[$class][$constant] = $constant_value;
185
186
                // second parameter of ucwords() is not supported on HHVM
187 3
                $constant = str_replace(' ', '', ucwords(str_replace('_', ' ', strtolower($constant))));
188
189 3
                self::$is_methods[$class]['is'.$constant] = $constant_value;
190 3
                self::$create_methods[$class][lcfirst($constant)] = $constant_value;
191
            }
192
        }
193 54
    }
194
195
    /**
196
     * @return array
197
     */
198 16
    private static function constants()
199
    {
200 16
        $class = get_called_class();
201 16
        self::detectConstants($class);
202
203 16
        return self::$constants[$class];
204
    }
205
206
    /**
207
     * @return string
208
     */
209 13
    private function constant()
210
    {
211 13
        return array_search($this->value(), self::constants());
212
    }
213
214
    /**
215
     * @param string $method
216
     * @param array  $arguments
217
     *
218
     * @return bool
219
     */
220 12
    public function __call($method, array $arguments = [])
221
    {
222 12
        $class = get_called_class();
223 12
        self::detectConstants($class);
224
225 12
        if (!isset(self::$is_methods[$class][$method])) {
226 3
            throw BadMethodCallException::noMethod($method, $class);
227
        }
228
229 9
        return $this->value === self::$is_methods[$class][$method];
230
    }
231
232
    /**
233
     * @param string $method
234
     * @param array  $arguments
235
     *
236
     * @return Enum
237
     */
238 18
    public static function __callStatic($method, array $arguments = [])
239
    {
240 18
        $class = get_called_class();
241 18
        if (isset(self::$instances[$class][$method])) {
242 15
            return self::$instances[$class][$method];
243
        }
244
245 3
        self::detectConstants($class);
246
247 3
        if (!isset(self::$create_methods[$class][$method])) {
248 3
            throw BadMethodCallException::noStaticMethod($method, $class);
249
        }
250
251
        return self::$instances[$class][$method] = new static(self::$create_methods[$class][$method]);
252
    }
253
}
254