Completed
Push — master ( 334344...573b25 )
by Peter
05:17
created

ReflectionEnum   A

Complexity

Total Complexity 27

Size/Duplication

Total Lines 238
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 100%

Importance

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

16 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A byValue() 0 18 3
A value() 0 4 1
A values() 0 9 2
A equals() 0 4 3
A isValid() 0 4 1
A choices() 0 9 2
A __toString() 0 4 1
A __clone() 0 4 1
A serialize() 0 4 1
A unserialize() 0 4 1
A constants() 0 7 1
A constant() 0 4 1
A __call() 0 11 2
A detectConstants() 0 18 3
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 4
    final private function __construct($value)
47
    {
48 4
        $this->value = $value;
49 4
    }
50
51
    /**
52
     * @param mixed $value
53
     *
54
     * @return Enum
55
     */
56 30
    final public static function byValue($value)
57
    {
58 30
        $class = get_called_class();
59 30
        self::detectConstants($class);
60
61 30
        $method = array_search($value, self::$create_methods[$class], true);
62
63 30
        if ($method === false) {
64 2
            throw OutOfEnumException::create($value, $class);
65
        }
66
67
        // limitation of count object instances
68 28
        if (!isset(self::$instances[$class][$method])) {
69 2
            self::$instances[$class][$method] = new static($value);
70 2
        }
71
72 28
        return self::$instances[$class][$method];
73
    }
74
75
    /**
76
     * @return mixed
77
     */
78 20
    final public function value()
79
    {
80 20
        return $this->value;
81
    }
82
83
    /**
84
     * Available values.
85
     *
86
     * @return Enum[]
87
     */
88 2
    final public static function values()
89
    {
90 2
        $values = [];
91 2
        foreach (self::constants() as $constant => $value) {
92 2
            $values[$constant] = self::byValue($value);
93 2
        }
94
95 2
        return $values;
96
    }
97
98
    /**
99
     * @param Enum $enum
100
     *
101
     * @return bool
102
     */
103 8
    final public function equals(Enum $enum)
104
    {
105 8
        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 8
    final public static function isValid($value)
116
    {
117 8
        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 2
    final public static function choices()
133
    {
134 2
        $choices = [];
135 2
        foreach (self::constants() as $value) {
136 2
            $choices[$value] = (string) self::byValue($value);
137 2
        }
138
139 2
        return $choices;
140
    }
141
142
    /**
143
     * Return readable value.
144
     *
145
     * @return string
146
     */
147 10
    public function __toString()
148
    {
149 10
        return $this->constant();
150
    }
151
152 2
    final public function __clone()
153
    {
154 2
        throw new \LogicException('Enumerations are not cloneable');
155
    }
156
157
    /**
158
     * @return mixed
159
     */
160 8
    public function serialize()
161
    {
162 8
        return serialize($this->value);
163
    }
164
165
    /**
166
     * @param mixed $data
167
     */
168 8
    public function unserialize($data)
169
    {
170 8
        self::byValue($this->value = unserialize($data));
171 8
    }
172
173
    /**
174
     * @param string $class
175
     */
176 44
    private static function detectConstants($class)
177
    {
178 44
        if (!isset(self::$create_methods[$class])) {
179 2
            self::$create_methods[$class] = [];
180 2
            self::$is_methods[$class] = [];
181 2
            self::$constants[$class] = [];
182
183 2
            foreach (ConstantDetector::detect($class) as $constant => $constant_value) {
184 2
                self::$constants[$class][$constant] = $constant_value;
185
186
                // second parameter of ucwords() is not supported on HHVM
187 2
                $constant = str_replace(' ', '', ucwords(str_replace('_', ' ', strtolower($constant))));
188
189 2
                self::$is_methods[$class]['is'.$constant] = $constant_value;
190 2
                self::$create_methods[$class][lcfirst($constant)] = $constant_value;
191 2
            }
192 2
        }
193 44
    }
194
195
    /**
196
     * @return array
197
     */
198 12
    private static function constants()
199
    {
200 12
        $class = get_called_class();
201 12
        self::detectConstants($class);
202
203 12
        return self::$constants[$class];
204
    }
205
206
    /**
207
     * @return string
208
     */
209 10
    private function constant()
210
    {
211 10
        return array_search($this->value(), self::constants());
212
    }
213
214
    /**
215
     * @param string $method
216
     * @param array  $arguments
217
     *
218
     * @return bool
219
     */
220 10
    public function __call($method, array $arguments = [])
221
    {
222 10
        $class = get_called_class();
223 10
        self::detectConstants($class);
224
225 10
        if (!isset(self::$is_methods[$class][$method])) {
226 2
            throw BadMethodCallException::noMethod($method, $class);
227
        }
228
229 8
        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 16
    public static function __callStatic($method, array $arguments = [])
239
    {
240 16
        $class = get_called_class();
241 16
        if (isset(self::$instances[$class][$method])) {
242 12
            return self::$instances[$class][$method];
243
        }
244
245 4
        self::detectConstants($class);
246
247 4
        if (!isset(self::$create_methods[$class][$method])) {
248 2
            throw BadMethodCallException::noStaticMethod($method, $class);
249
        }
250
251 2
        return self::$instances[$class][$method] = new static(self::$create_methods[$class][$method]);
252
    }
253
}
254