Completed
Push — master ( 6e8ce6...e0dcd7 )
by Peter
03:14
created

ReflectionEnum   A

Complexity

Total Complexity 29

Size/Duplication

Total Lines 256
Duplicated Lines 10.16 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 29
lcom 1
cbo 4
dl 26
loc 256
ccs 72
cts 72
cp 1
rs 10
c 0
b 0
f 0

16 Methods

Rating   Name   Duplication   Size   Complexity  
A constants() 0 7 1
A constant() 0 4 1
A __call() 0 11 2
A __construct() 0 4 1
A byValue() 0 18 3
A value() 0 4 1
A values() 13 13 3
A equals() 0 4 3
A isValid() 0 4 1
A choices() 13 13 3
A __toString() 0 4 1
A __clone() 0 4 1
A serialize() 0 4 1
A unserialize() 0 4 1
A detectConstants() 0 18 3
A __callStatic() 0 15 3

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

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
     * @var mixed[][]
45
     */
46
    private static $choices = [];
47
48
    /**
49
     * @var EnumEnum[]
50
     */
51
    private static $values = [];
52
53
    /**
54
     * @param mixed $value
55
     */
56 6
    final private function __construct($value)
57
    {
58 6
        $this->value = $value;
59 6
    }
60
61
    /**
62
     * @param mixed $value
63
     *
64
     * @return Enum
65
     */
66 39
    final public static function byValue($value)
67
    {
68 39
        $class = get_called_class();
69 39
        self::detectConstants($class);
70
71 39
        $method = array_search($value, self::$create_methods[$class], true);
72
73 39
        if ($method === false) {
74 3
            throw OutOfEnumException::create($value, $class);
75
        }
76
77
        // limitation of count object instances
78 36
        if (!isset(self::$instances[$class][$method])) {
79 3
            self::$instances[$class][$method] = new static($value);
80
        }
81
82 36
        return self::$instances[$class][$method];
83
    }
84
85
    /**
86
     * @return mixed
87
     */
88 26
    final public function value()
89
    {
90 26
        return $this->value;
91
    }
92
93
    /**
94
     * Available values.
95
     *
96
     * @return Enum[]
97
     */
98 3 View Code Duplication
    final public static function values()
99
    {
100 3
        $class = get_called_class();
101
102 3
        if (!isset(self::$values[$class])) {
103 3
            self::$values[$class] = [];
104 3
            foreach (self::constants() as $constant => $value) {
105 3
                self::$values[$class][$constant] = self::byValue($value);
106
            }
107
        }
108
109 3
        return self::$values[$class];
0 ignored issues
show
Bug Compatibility introduced by
The expression self::$values[$class]; of type GpsLab\Component\Enum\EnumEnum|array adds the type GpsLab\Component\Enum\EnumEnum to the return on line 109 which is incompatible with the return type declared by the interface GpsLab\Component\Enum\Enum::values of type array.
Loading history...
110
    }
111
112
    /**
113
     * @param Enum $enum
114
     *
115
     * @return bool
116
     */
117 10
    final public function equals(Enum $enum)
118
    {
119 10
        return $this === $enum || ($this->value() === $enum->value() && get_called_class() == get_class($enum));
120
    }
121
122
    /**
123
     * Is value supported.
124
     *
125
     * @param mixed $value
126
     *
127
     * @return bool
128
     */
129 10
    final public static function isValid($value)
130
    {
131 10
        return in_array($value, self::constants(), true);
132
    }
133
134
    /**
135
     * Get choices for radio group.
136
     *
137
     * <code>
138
     * {
139
     *   value1: 'Readable value 1',
140
     *   value2: 'Readable value 2',
141
     * }
142
     * </code>
143
     *
144
     * @return array
145
     */
146 3 View Code Duplication
    final public static function choices()
147
    {
148 3
        $class = get_called_class();
149
150 3
        if (!isset(self::$choices[$class])) {
151 3
            self::$choices[$class] = [];
152 3
            foreach (self::constants() as $value) {
153 3
                self::$choices[$class][$value] = (string) self::byValue($value);
154
            }
155
        }
156
157 3
        return self::$choices[$class];
158
    }
159
160
    /**
161
     * Return readable value.
162
     *
163
     * @return string
164
     */
165 13
    public function __toString()
166
    {
167 13
        return $this->constant();
168
    }
169
170 3
    final public function __clone()
171
    {
172 3
        throw new \LogicException('Enumerations are not cloneable');
173
    }
174
175
    /**
176
     * @return mixed
177
     */
178 10
    public function serialize()
179
    {
180 10
        return serialize($this->value);
181
    }
182
183
    /**
184
     * @param mixed $data
185
     */
186 10
    public function unserialize($data)
187
    {
188 10
        self::byValue($this->value = unserialize($data));
189 10
    }
190
191
    /**
192
     * @param string $class
193
     */
194 58
    private static function detectConstants($class)
195
    {
196 58
        if (!isset(self::$create_methods[$class])) {
197 3
            self::$create_methods[$class] = [];
198 3
            self::$is_methods[$class] = [];
199 3
            self::$constants[$class] = [];
200
201 3
            foreach (ConstantDetector::detect($class) as $constant => $constant_value) {
202 3
                self::$constants[$class][$constant] = $constant_value;
203
204
                // second parameter of ucwords() is not supported on HHVM
205 3
                $constant = str_replace(' ', '', ucwords(str_replace('_', ' ', strtolower($constant))));
206
207 3
                self::$is_methods[$class]['is'.$constant] = $constant_value;
208 3
                self::$create_methods[$class][lcfirst($constant)] = $constant_value;
209
            }
210
        }
211 58
    }
212
213
    /**
214
     * @return array
215
     */
216 16
    private static function constants()
217
    {
218 16
        $class = get_called_class();
219 16
        self::detectConstants($class);
220
221 16
        return self::$constants[$class];
222
    }
223
224
    /**
225
     * @return string
226
     */
227 13
    private function constant()
228
    {
229 13
        return array_search($this->value(), self::constants());
230
    }
231
232
    /**
233
     * @param string $method
234
     * @param array  $arguments
235
     *
236
     * @return bool
237
     */
238 13
    public function __call($method, array $arguments = [])
239
    {
240 13
        $class = get_called_class();
241 13
        self::detectConstants($class);
242
243 13
        if (!isset(self::$is_methods[$class][$method])) {
244 3
            throw BadMethodCallException::noMethod($method, $class);
245
        }
246
247 10
        return $this->value === self::$is_methods[$class][$method];
248
    }
249
250
    /**
251
     * @param string $method
252
     * @param array  $arguments
253
     *
254
     * @return Enum
255
     */
256 22
    public static function __callStatic($method, array $arguments = [])
257
    {
258 22
        $class = get_called_class();
259 22
        if (isset(self::$instances[$class][$method])) {
260 16
            return self::$instances[$class][$method];
261
        }
262
263 6
        self::detectConstants($class);
264
265 6
        if (!isset(self::$create_methods[$class][$method])) {
266 3
            throw BadMethodCallException::noStaticMethod($method, $class);
267
        }
268
269 3
        return self::$instances[$class][$method] = new static(self::$create_methods[$class][$method]);
270
    }
271
}
272