Completed
Push — master ( 5e22b5...480565 )
by Randy
03:47
created

ObjectFacade::setValueByProperty()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 11
Ratio 100 %

Importance

Changes 0
Metric Value
dl 11
loc 11
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 6
nc 2
nop 2
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
        if ($this->hasMethod('__set')) {
87
            $this->invokeMethod('__set', $name, $value);
88
89
            return true;
90
        }
91
92
        return false;
93
    }
94
95
    /**
96
     * @param string $name
97
     *
98
     * @return mixed|null
99
     */
100
    final public function getValue(string $name)
101
    {
102
        foreach ($this->getNameVariations($name) as $attribute) {
103
            $property = $this->getPropertyByName($attribute);
104
            if ($property !== null && Validator::new($this)->isValidProperty($property)) {
105
                return $property->getValue($this->object);
106
            }
107
108
            $method = $this->getGetterMethod($name);
109
            if ($method !== null && Validator::new($this)->isValidGetterMethod($method)) {
110
                return $method->invoke($this->object);
111
            }
112
        }
113
114
        return $this->invokeMethod('__get', $name);
115
    }
116
117
    /**
118
     * @param string $name
119
     * @param        $value
120
     *
121
     * @return bool
122
     */
123 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...
124
    {
125
        $property = $this->getPropertyByName($name);
126
        if ($property !== null && Validator::new($this)->isValidProperty($property)) {
127
            $property->setValue($this->object, $value);
128
129
            return true;
130
        }
131
132
        return false;
133
    }
134
135
    /**
136
     * @param string $name
137
     * @param        $value
138
     *
139
     * @return bool
140
     */
141 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...
142
    {
143
        $method = $this->getSetterMethod($name);
144
        if ($method !== null && Validator::new($this)->isValidSetterMethod($method, $value)) {
145
            $method->invoke($this->object, $value);
146
147
            return true;
148
        }
149
150
        return false;
151
    }
152
153
    /**
154
     * @param string $name
155
     *
156
     * @return mixed|null
157
     */
158 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...
159
    {
160
        $method = $this->getGetterMethod($name);
161
        if ($method !== null && Validator::new($this)->isValidGetterMethod($method)) {
162
            return $method->invoke($this->object);
163
        }
164
165
        return null;
166
    }
167
168
    /**
169
     * @param string $name
170
     *
171
     * @return mixed|null
172
     */
173 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...
174
    {
175
        $property = $this->getPropertyByName($name);
176
        if ($property !== null && Validator::new($this)->isValidProperty($property)) {
177
            return $property->getValue($this->object);
178
        }
179
180
        return null;
181
    }
182
183
    /**
184
     * @param string $postfix
185
     *
186
     * @return null|ReflectionMethod
187
     */
188
    final public function getSetterMethod(string $postfix)
189
    {
190
        return $this->getMethod($postfix, ['set', 'append']);
191
    }
192
193
    /**
194
     * @param string $postfix
195
     *
196
     * @return null|ReflectionMethod
197
     */
198
    final public function getGetterMethod(string $postfix)
199
    {
200
        return $this->getMethod($postfix, ['get']);
201
    }
202
203
    /**
204
     * @param string $postfix
205
     * @param array  $prefixe
206
     *
207
     * @return null|ReflectionMethod
208
     */
209
    final public function getMethod(string $postfix, array $prefixe)
210
    {
211
        foreach ($prefixe as $prefix) {
212
            $method = $this->getMethodByName($prefix . ucfirst($postfix));
213
            if ($method !== null) {
214
                return $method;
215
            }
216
        }
217
218
        return null;
219
    }
220
221
    /**
222
     * @param string $name
223
     * @param array  ...$args
224
     *
225
     * @return mixed|null
226
     */
227
    final public function invokeMethod(string $name, ...$args)
228
    {
229
        $method = $this->getMethodByName($name);
230
        if ($method !== null && Validator::new($this)->areValidMethodArguments($method, ...$args)) {
231
            return $method->invokeArgs($this->object, $args);
232
        }
233
234
        return null;
235
    }
236
237
    /**
238
     * @param string $name
239
     *
240
     * @return null|ReflectionMethod
241
     */
242
    final public function getMethodByName(string $name)
243
    {
244
        return $this->hasMethod($name) ? $this->getReflection()->getMethod($name) : null;
245
    }
246
247
    /**
248
     * @param string $name
249
     *
250
     * @return null|ReflectionProperty
251
     */
252
    final public function getPropertyByName(string $name)
253
    {
254
        return $this->hasProperty($name) ? $this->getReflection()->getProperty($name) : null;
255
    }
256
257
    /**
258
     * @param string $name
259
     *
260
     * @return bool
261
     */
262
    final public function hasProperty(string $name): bool
263
    {
264
        return $this->getReflection()->hasProperty($name);
265
    }
266
267
    /**
268
     * @param string $name
269
     *
270
     * @return bool
271
     */
272
    final public function hasMethod(string $name): bool
273
    {
274
        return $this->getReflection()->hasMethod($name);
275
    }
276
}
277