Completed
Push — master ( 6774bc...4de820 )
by Randy
02:59
created

ObjectFacade::tryMagicSet()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 10
ccs 0
cts 5
cp 0
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 5
nc 2
nop 2
crap 6
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 10
    public function __construct($object)
32
    {
33 10
        enforce(is_object($object))->orThrow('That is not a valid object');
34
35 10
        $this->object = $object;
36 10
    }
37
38
    /**
39
     * @return object
40
     */
41 3
    final public function getObject()
42
    {
43 3
        return $this->object;
44
    }
45
46
    /**
47
     * @return ReflectionClass
48
     */
49 10
    final public function getReflection(): ReflectionClass
50
    {
51 10
        if ($this->reflection === null) {
52 10
            $this->reflection = new ReflectionClass($this->object);
53
        }
54
55 10
        return $this->reflection;
56
    }
57
58
    /**
59
     * @param string $name
60
     *
61
     * @return array
62
     */
63 2
    private function getNameVariations(string $name): array
64
    {
65
        return [
66 2
            Inflector::get()->camelize($name, Inflector::DOWNCASE_FIRST_LETTER),
67 2
            Inflector::get()->camelize($name, Inflector::UPCASE_FIRST_LETTER),
68 2
            Inflector::get()->underscore($name)
69
        ];
70
    }
71
72
    /**
73
     * @param string $name
74
     * @param        $value
75
     *
76
     * @return bool
77
     */
78 2
    final public function setValue(string $name, $value): bool
79
    {
80 2
        foreach ($this->getNameVariations($name) as $attribute) {
81 2
            if ($this->setValueByProperty($attribute, $value) || $this->setValueByMethod($attribute, $value)) {
82 2
                return true;
83
            }
84
        }
85
86
        return $this->tryMagicSet($name, $value);
87
    }
88
89
    /**
90
     * @param string $name
91
     * @param        $value
92
     *
93
     * @return bool
94
     */
95
    private function tryMagicSet(string $name, $value): bool
96
    {
97
        if ($this->hasMethod('__set')) {
98
            $this->invokeMethod('__set', $name, $value);
99
100
            return true;
101
        }
102
103
        return false;
104
    }
105
106
    /**
107
     * @param string $name
108
     *
109
     * @return mixed|null
110
     */
111 2
    final public function getValue(string $name)
112
    {
113 2
        foreach ($this->getNameVariations($name) as $attribute) {
114 2
            $property = $this->getPropertyByName($attribute);
115 2
            if ($property !== null && Validator::new($this)->isValidProperty($property)) {
116 1
                return $property->getValue($this->object);
117
            }
118
119 1
            $method = $this->getGetterMethod($name);
120 1
            if ($method !== null && Validator::new($this)->isValidGetterMethod($method)) {
121 1
                return $method->invoke($this->object);
122
            }
123
        }
124
125
        return $this->invokeMethod('__get', $name);
126
    }
127
128
    /**
129
     * @param string $name
130
     * @param        $value
131
     *
132
     * @return bool
133
     */
134 2
    final public function setValueByProperty(string $name, $value): bool
135
    {
136 2
        $property = $this->getPropertyByName($name);
137 2
        if ($property !== null && Validator::new($this)->isValidProperty($property)) {
138 1
            $property->setValue($this->object, $value);
139
140 1
            return true;
141
        }
142
143 1
        return false;
144
    }
145
146
    /**
147
     * @param string $name
148
     * @param        $value
149
     *
150
     * @return bool
151
     */
152 1
    final public function setValueByMethod(string $name, $value): bool
153
    {
154 1
        $method = $this->getSetterMethod($name);
155 1
        if ($method !== null && Validator::new($this)->isValidSetterMethod($method, $value)) {
156 1
            $method->invoke($this->object, $value);
157
158 1
            return true;
159
        }
160
161 1
        return false;
162
    }
163
164
    /**
165
     * @param string $name
166
     *
167
     * @return mixed|null
168
     */
169 2
    final public function getValueByMethod(string $name)
170
    {
171 2
        $method = $this->getGetterMethod($name);
172 2
        if ($method !== null && Validator::new($this)->isValidGetterMethod($method)) {
173 2
            return $method->invoke($this->object);
174
        }
175
176 1
        return null;
177
    }
178
179
    /**
180
     * @param string $name
181
     *
182
     * @return mixed|null
183
     */
184 2
    final public function getValueByProperty(string $name)
185
    {
186 2
        $property = $this->getPropertyByName($name);
187 2
        if ($property !== null && Validator::new($this)->isValidProperty($property)) {
188 2
            return $property->getValue($this->object);
189
        }
190
191 1
        return null;
192
    }
193
194
    /**
195
     * @param string $postfix
196
     *
197
     * @return null|ReflectionMethod
198
     */
199 2
    final public function getSetterMethod(string $postfix)
200
    {
201 2
        return $this->getMethod($postfix, ['set', 'append']);
202
    }
203
204
    /**
205
     * @param string $postfix
206
     *
207
     * @return null|ReflectionMethod
208
     */
209 3
    final public function getGetterMethod(string $postfix)
210
    {
211 3
        return $this->getMethod($postfix, ['get']);
212
    }
213
214
    /**
215
     * @param string $postfix
216
     * @param array  $prefixe
217
     *
218
     * @return null|ReflectionMethod
219
     */
220 4
    final public function getMethod(string $postfix, array $prefixe)
221
    {
222 4
        foreach ($prefixe as $prefix) {
223 4
            $method = $this->getMethodByName($prefix . ucfirst($postfix));
224 4
            if ($method !== null) {
225 4
                return $method;
226
            }
227
        }
228
229 1
        return null;
230
    }
231
232
    /**
233
     * @param string $name
234
     * @param array  ...$args
235
     *
236
     * @return mixed|null
237
     */
0 ignored issues
show
Documentation introduced by
Consider making the type for parameter $args a bit more specific; maybe use array[].
Loading history...
238
    final public function invokeMethod(string $name, ...$args)
239
    {
240
        $method = $this->getMethodByName($name);
241
        if ($method !== null && Validator::new($this)->areValidMethodArguments($method, ...$args)) {
242
            return $method->invokeArgs($this->object, $args);
243
        }
244
245
        return null;
246
    }
247
248
    /**
249
     * @param string $name
250
     *
251
     * @return null|ReflectionMethod
252
     */
253 5
    final public function getMethodByName(string $name)
254
    {
255 5
        return $this->hasMethod($name) ? $this->getReflection()->getMethod($name) : null;
256
    }
257
258
    /**
259
     * @param string $name
260
     *
261
     * @return null|ReflectionProperty
262
     */
263 4
    final public function getPropertyByName(string $name)
264
    {
265 4
        return $this->hasProperty($name) ? $this->getReflection()->getProperty($name) : null;
266
    }
267
268
    /**
269
     * @param string $name
270
     *
271
     * @return bool
272
     */
273 5
    final public function hasProperty(string $name): bool
274
    {
275 5
        return $this->getReflection()->hasProperty($name);
276
    }
277
278
    /**
279
     * @param string $name
280
     *
281
     * @return bool
282
     */
283 6
    final public function hasMethod(string $name): bool
284
    {
285 6
        return $this->getReflection()->hasMethod($name);
286
    }
287
}
288