Passed
Push — master ( 94d060...0d7b76 )
by Randy
02:16
created

ObjectFacade::exists()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 4
nc 2
nop 2
1
<?php
2
3
namespace Dgame\Object;
4
5
use ReflectionClass;
6
use ReflectionMethod;
7
use ReflectionProperty;
8
use function Dgame\Conditional\debug;
9
use function Dgame\Ensurance\enforce;
10
11
/**
12
 * Class ObjectFacade
13
 * @package Dgame\Object
14
 */
15
class ObjectFacade
16
{
17
    const DEBUG_LABEL = 'Dgame_Object_Facade';
18
19
    /**
20
     * @var object
21
     */
22
    private $object;
23
    /**
24
     * @var ReflectionClass
25
     */
26
    private $reflection;
27
28
    /**
29
     * ObjectFacade constructor.
30
     *
31
     * @param object $object
32
     */
33
    public function __construct($object)
34
    {
35
        enforce(is_object($object))->orThrow('That is not a valid object');
36
37
        $this->object = $object;
38
    }
39
40
    /**
41
     * @return object
42
     */
43
    final public function getObject()
44
    {
45
        return $this->object;
46
    }
47
48
    /**
49
     * @return ReflectionClass
50
     */
51
    final public function getReflection(): ReflectionClass
52
    {
53
        if ($this->reflection === null) {
54
            $this->reflection = new ReflectionClass($this->object);
55
        }
56
57
        return $this->reflection;
58
    }
59
60
    /**
61
     * @param string $name
62
     * @param        $value
63
     *
64
     * @return bool
65
     */
66 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...
67
    {
68
        $property = $this->getPropertyByName($name);
69
        if ($property !== null && $this->validateProperty($property)) {
70
            $property->setValue($this->object, $value);
71
72
            return true;
73
        }
74
75
        return false;
76
    }
77
78
    /**
79
     * @param ReflectionProperty $property
80
     *
81
     * @return bool
82
     */
83 View Code Duplication
    private function validateProperty(ReflectionProperty $property): 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...
84
    {
85
        if (!$property->isPublic()) {
86
            debug(self::DEBUG_LABEL)->output('[Error] Property %s is not public', $property->getName());
87
88
            return false;
89
        }
90
91
        if ($property->isStatic()) {
92
            debug(self::DEBUG_LABEL)->output('[Error] Property %s is static', $property->getName());
93
94
            return false;
95
        }
96
97
        return true;
98
    }
99
100
    /**
101
     * @param string $name
102
     * @param        $value
103
     *
104
     * @return bool
105
     */
106
    final public function setValueByMethod(string $name, $value): bool
107
    {
108
        $method = $this->getSetterMethod($name);
109
        if ($method !== null && $this->validateSetterMethod($method, $value)) {
110
            $method->invoke($this->object, $value);
111
112
            return true;
113
        }
114
115
        return false;
116
    }
117
118
    /**
119
     * @param ReflectionMethod $method
120
     *
121
     * @return bool
122
     */
123 View Code Duplication
    private function validateMethod(ReflectionMethod $method): 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
        if (!$method->isPublic()) {
126
            debug(self::DEBUG_LABEL)->output('[Error] Method %s is not public', $method->getName());
0 ignored issues
show
Bug introduced by
Consider using $method->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
127
128
            return false;
129
        }
130
131
        if ($method->isStatic()) {
132
            debug(self::DEBUG_LABEL)->output('[Error] Method %s is static', $method->getName());
0 ignored issues
show
Bug introduced by
Consider using $method->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
133
134
            return false;
135
        }
136
137
        return true;
138
    }
139
140
    /**
141
     * @param ReflectionMethod $method
142
     * @param                  $value
143
     *
144
     * @return bool
145
     */
146
    private function validateSetterMethod(ReflectionMethod $method, $value): bool
147
    {
148
        if (!$this->validateMethod($method)) {
149
            return false;
150
        }
151
152 View Code Duplication
        if ($value === null && $method->getNumberOfParameters() !== 0 && !$method->getParameters()[0]->allowsNull()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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
            debug(self::DEBUG_LABEL)->output('[Error] First parameter of method %s is not allowed to be null', $method->getName());
0 ignored issues
show
Bug introduced by
Consider using $method->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
154
155
            return false;
156
        }
157
158
        if ($method->getNumberOfParameters() === 0) {
159
            debug(self::DEBUG_LABEL)->output('[Warning] Method %s does not accept any parameters', $method->getName());
0 ignored issues
show
Bug introduced by
Consider using $method->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
160
        }
161
162
        return true;
163
    }
164
165
    /**
166
     * @param string $name
167
     *
168
     * @return mixed|null
169
     */
170
    final public function getValueByMethod(string $name)
171
    {
172
        $method = $this->getGetterMethod($name);
173
        if ($method !== null && $this->validateGetterMethod($method)) {
174
            return $method->invoke($this->object);
175
        }
176
177
        return null;
178
    }
179
180
    /**
181
     * @param ReflectionMethod $method
182
     *
183
     * @return bool
184
     */
185
    private function validateGetterMethod(ReflectionMethod $method): bool
186
    {
187
        if (!$this->validateMethod($method)) {
188
            return false;
189
        }
190
191
        $value = $method->invoke($this->object);
192 View Code Duplication
        if ($value === null && $method->hasReturnType() && !$method->getReturnType()->allowsNull()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
193
            debug(self::DEBUG_LABEL)->output('[Error] Method %s return value is not allowed to be null', $method->getName());
0 ignored issues
show
Bug introduced by
Consider using $method->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
194
195
            return false;
196
        }
197
198
        return true;
199
    }
200
201
    /**
202
     * @param string $name
203
     *
204
     * @return mixed|null
205
     */
206 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...
207
    {
208
        $property = $this->getPropertyByName($name);
209
        if ($property !== null && $this->validateProperty($property)) {
210
            return $property->getValue($this->object);
211
        }
212
213
        return null;
214
    }
215
216
    /**
217
     * @param string $postfix
218
     *
219
     * @return null|ReflectionMethod
220
     */
221
    final public function getSetterMethod(string $postfix)
222
    {
223
        return $this->getMethod($postfix, ['set', 'append']);
224
    }
225
226
    /**
227
     * @param string $postfix
228
     *
229
     * @return null|ReflectionMethod
230
     */
231
    final public function getGetterMethod(string $postfix)
232
    {
233
        return $this->getMethod($postfix, ['get']);
234
    }
235
236
    /**
237
     * @param string $postfix
238
     * @param array  $prefixe
239
     *
240
     * @return null|ReflectionMethod
241
     */
242
    final public function getMethod(string $postfix, array $prefixe)
243
    {
244
        foreach ($prefixe as $prefix) {
245
            $method = $this->getMethodByName($prefix . ucfirst($postfix));
246
            if ($method !== null) {
247
                return $method;
248
            }
249
        }
250
251
        return null;
252
    }
253
254
    /**
255
     * @param string $name
256
     *
257
     * @return null|ReflectionMethod
258
     */
259
    final public function getMethodByName(string $name)
260
    {
261
        return $this->hasMethod($name) ? $this->getReflection()->getMethod($name) : null;
262
    }
263
264
    /**
265
     * @param string $name
266
     *
267
     * @return null|ReflectionProperty
268
     */
269
    final public function getPropertyByName(string $name)
270
    {
271
        return $this->hasProperty($name) ? $this->getReflection()->getProperty($name) : null;
272
    }
273
274
    /**
275
     * @param string $name
276
     *
277
     * @return bool
278
     */
279
    final public function hasProperty(string $name): bool
280
    {
281
        return $this->getReflection()->hasProperty($name);
282
    }
283
284
    /**
285
     * @param string $name
286
     *
287
     * @return bool
288
     */
289
    final public function hasMethod(string $name): bool
290
    {
291
        return $this->getReflection()->hasMethod($name);
292
    }
293
}
294