Completed
Push — master ( f17ef6...1d1ec5 )
by Randy
05:13
created

ObjectFacade   B

Complexity

Total Complexity 41

Size/Duplication

Total Lines 256
Duplicated Lines 15.63 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 0
Metric Value
wmc 41
lcom 1
cbo 3
dl 40
loc 256
rs 8.2769
c 0
b 0
f 0

18 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A getObject() 0 4 1
A getReflection() 0 8 2
A getNameVariations() 0 8 1
A setValue() 0 10 4
B getValue() 0 16 6
A setValueByProperty() 11 11 3
A setValueByMethod() 11 11 3
A getValueByMethod() 9 9 3
A getValueByProperty() 9 9 3
A getSetterMethod() 0 4 1
A getGetterMethod() 0 4 1
A getMethod() 0 11 3
A invokeMethod() 0 9 3
A getMethodByName() 0 4 2
A getPropertyByName() 0 4 2
A hasProperty() 0 4 1
A hasMethod() 0 4 1

How to fix   Duplicated Code    Complexity   

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:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like ObjectFacade often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ObjectFacade, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Dgame\Object;
4
5
use ICanBoogie\Inflector;
6
use ReflectionClass;
7
use ReflectionMethod;
8
use ReflectionProperty;
9
use function Dgame\Ensurance\enforce;
10
11
/**
12
 * Class ObjectFacade
13
 * @package Dgame\Object
14
 */
15
class ObjectFacade
16
{
17
    /**
18
     * @var object
19
     */
20
    private $object;
21
    /**
22
     * @var ReflectionClass
23
     */
24
    private $reflection;
25
26
    /**
27
     * ObjectFacade constructor.
28
     *
29
     * @param object $object
30
     */
31
    public function __construct($object)
32
    {
33
        enforce(is_object($object))->orThrow('That is not a valid object');
34
35
        $this->object = $object;
36
    }
37
38
    /**
39
     * @return object
40
     */
41
    final public function getObject()
42
    {
43
        return $this->object;
44
    }
45
46
    /**
47
     * @return ReflectionClass
48
     */
49
    final public function getReflection(): ReflectionClass
50
    {
51
        if ($this->reflection === null) {
52
            $this->reflection = new ReflectionClass($this->object);
53
        }
54
55
        return $this->reflection;
56
    }
57
58
    /**
59
     * @param string $name
60
     *
61
     * @return array
62
     */
63
    private function getNameVariations(string $name): array
64
    {
65
        return [
66
            Inflector::get()->camelize($name, Inflector::DOWNCASE_FIRST_LETTER),
67
            Inflector::get()->camelize($name, Inflector::UPCASE_FIRST_LETTER),
68
            Inflector::get()->underscore($name)
69
        ];
70
    }
71
72
    /**
73
     * @param string $name
74
     * @param        $value
75
     *
76
     * @return bool
77
     */
78
    final public function setValue(string $name, $value): bool
79
    {
80
        foreach ($this->getNameVariations($name) as $attribute) {
81
            if ($this->setValueByProperty($attribute, $value) || $this->setValueByMethod($attribute, $value)) {
82
                return true;
83
            }
84
        }
85
86
        return $this->invokeMethod('__set', $name, $value);
87
    }
88
89
    /**
90
     * @param string $name
91
     *
92
     * @return mixed|null
93
     */
94
    final public function getValue(string $name)
95
    {
96
        foreach ($this->getNameVariations($name) as $attribute) {
97
            $property = $this->getPropertyByName($attribute);
98
            if ($property !== null && Validator::new($this)->isValidProperty($property)) {
99
                return $property->getValue($this->object);
100
            }
101
102
            $method = $this->getGetterMethod($name);
103
            if ($method !== null && Validator::new($this)->isValidGetterMethod($method)) {
104
                return $method->invoke($this->object);
105
            }
106
        }
107
108
        return $this->invokeMethod('__get', $name);
109
    }
110
111
    /**
112
     * @param string $name
113
     * @param        $value
114
     *
115
     * @return bool
116
     */
117 View Code Duplication
    final public function setValueByProperty(string $name, $value): bool
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
118
    {
119
        $property = $this->getPropertyByName($name);
120
        if ($property !== null && Validator::new($this)->isValidProperty($property)) {
121
            $property->setValue($this->object, $value);
122
123
            return true;
124
        }
125
126
        return false;
127
    }
128
129
    /**
130
     * @param string $name
131
     * @param        $value
132
     *
133
     * @return bool
134
     */
135 View Code Duplication
    final public function setValueByMethod(string $name, $value): bool
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
136
    {
137
        $method = $this->getSetterMethod($name);
138
        if ($method !== null && Validator::new($this)->isValidSetterMethod($method, $value)) {
139
            $method->invoke($this->object, $value);
140
141
            return true;
142
        }
143
144
        return false;
145
    }
146
147
    /**
148
     * @param string $name
149
     *
150
     * @return mixed|null
151
     */
152 View Code Duplication
    final public function getValueByMethod(string $name)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
153
    {
154
        $method = $this->getGetterMethod($name);
155
        if ($method !== null && Validator::new($this)->isValidGetterMethod($method)) {
156
            return $method->invoke($this->object);
157
        }
158
159
        return null;
160
    }
161
162
    /**
163
     * @param string $name
164
     *
165
     * @return mixed|null
166
     */
167 View Code Duplication
    final public function getValueByProperty(string $name)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
168
    {
169
        $property = $this->getPropertyByName($name);
170
        if ($property !== null && Validator::new($this)->isValidProperty($property)) {
171
            return $property->getValue($this->object);
172
        }
173
174
        return null;
175
    }
176
177
    /**
178
     * @param string $postfix
179
     *
180
     * @return null|ReflectionMethod
181
     */
182
    final public function getSetterMethod(string $postfix)
183
    {
184
        return $this->getMethod($postfix, ['set', 'append']);
185
    }
186
187
    /**
188
     * @param string $postfix
189
     *
190
     * @return null|ReflectionMethod
191
     */
192
    final public function getGetterMethod(string $postfix)
193
    {
194
        return $this->getMethod($postfix, ['get']);
195
    }
196
197
    /**
198
     * @param string $postfix
199
     * @param array  $prefixe
200
     *
201
     * @return null|ReflectionMethod
202
     */
203
    final public function getMethod(string $postfix, array $prefixe)
204
    {
205
        foreach ($prefixe as $prefix) {
206
            $method = $this->getMethodByName($prefix . ucfirst($postfix));
207
            if ($method !== null) {
208
                return $method;
209
            }
210
        }
211
212
        return null;
213
    }
214
215
    /**
216
     * @param string $name
217
     * @param array  ...$args
218
     *
219
     * @return mixed|null
220
     */
221
    final public function invokeMethod(string $name, ...$args)
222
    {
223
        $method = $this->getMethodByName($name);
224
        if ($method !== null && Validator::new($this)->areValidMethodArguments($method, ...$args)) {
225
            return $method->invokeArgs($this->object, $args);
226
        }
227
228
        return null;
229
    }
230
231
    /**
232
     * @param string $name
233
     *
234
     * @return null|ReflectionMethod
235
     */
236
    final public function getMethodByName(string $name)
237
    {
238
        return $this->hasMethod($name) ? $this->getReflection()->getMethod($name) : null;
239
    }
240
241
    /**
242
     * @param string $name
243
     *
244
     * @return null|ReflectionProperty
245
     */
246
    final public function getPropertyByName(string $name)
247
    {
248
        return $this->hasProperty($name) ? $this->getReflection()->getProperty($name) : null;
249
    }
250
251
    /**
252
     * @param string $name
253
     *
254
     * @return bool
255
     */
256
    final public function hasProperty(string $name): bool
257
    {
258
        return $this->getReflection()->hasProperty($name);
259
    }
260
261
    /**
262
     * @param string $name
263
     *
264
     * @return bool
265
     */
266
    final public function hasMethod(string $name): bool
267
    {
268
        return $this->getReflection()->hasMethod($name);
269
    }
270
}
271