1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace drupol\DynamicObjects; |
4
|
|
|
|
5
|
|
|
use drupol\Memoize\MemoizeTrait; |
6
|
|
|
|
7
|
|
|
/** |
8
|
|
|
* Trait DynamicObjectsTrait. |
9
|
|
|
* |
10
|
|
|
* @package drupol\DynamicObjects |
11
|
|
|
*/ |
12
|
|
|
trait DynamicObjectsTrait |
13
|
|
|
{ |
14
|
|
|
use MemoizeTrait; |
15
|
|
|
|
16
|
|
|
/** |
17
|
|
|
* @var array |
18
|
|
|
*/ |
19
|
|
|
protected static $dynamicMethods = array(); |
20
|
|
|
|
21
|
|
|
/** |
22
|
|
|
* @var array |
23
|
|
|
*/ |
24
|
|
|
protected static $dynamicProperties = array(); |
25
|
|
|
|
26
|
|
|
/** |
27
|
|
|
* Add a dynamic property. |
28
|
|
|
* |
29
|
|
|
* @param string|array $names |
30
|
|
|
* The property name or an array of property names. |
31
|
|
|
* @param mixed $value |
32
|
|
|
* The property value. |
33
|
|
|
* @param bool $memoize |
34
|
|
|
* Memoize parameter. |
35
|
|
|
*/ |
36
|
5 |
View Code Duplication |
public static function addDynamicProperty($names, $value, $memoize = false) |
|
|
|
|
37
|
|
|
{ |
38
|
5 |
|
if (!is_array($names)) { |
39
|
5 |
|
$names = [$names]; |
40
|
|
|
} |
41
|
|
|
|
42
|
5 |
|
foreach ($names as $property) { |
43
|
5 |
|
static::$dynamicProperties[get_called_class()][$property] = [ |
44
|
5 |
|
'name' => $property, |
45
|
5 |
|
'factory' => $value, |
46
|
5 |
|
'memoize' => $memoize, |
47
|
|
|
]; |
48
|
|
|
} |
49
|
5 |
|
} |
50
|
|
|
|
51
|
|
|
/** |
52
|
|
|
* Add a dynamic method. |
53
|
|
|
* |
54
|
|
|
* @param string|array $names |
55
|
|
|
* The method name or an array of method names. |
56
|
|
|
* @param \Closure $func |
57
|
|
|
* The method. |
58
|
|
|
* @param bool $memoize |
59
|
|
|
* Memoize parameter. |
60
|
|
|
* @param bool $static |
61
|
|
|
* Static flag parameter. |
62
|
|
|
*/ |
63
|
5 |
View Code Duplication |
public static function addDynamicMethod($names, \Closure $func, $memoize = false, $static = false) |
|
|
|
|
64
|
|
|
{ |
65
|
5 |
|
if (!is_array($names)) { |
66
|
5 |
|
$names = [$names]; |
67
|
|
|
} |
68
|
|
|
|
69
|
5 |
|
foreach ($names as $method) { |
70
|
5 |
|
static::$dynamicMethods[get_called_class()][$method] = [ |
71
|
5 |
|
'name' => $method, |
72
|
5 |
|
'factory' => $func, |
73
|
5 |
|
'memoize' => $memoize, |
74
|
5 |
|
'static' => $static, |
75
|
|
|
]; |
76
|
|
|
} |
77
|
5 |
|
} |
78
|
|
|
|
79
|
|
|
/** |
80
|
|
|
* Check if a dynamic property exists. |
81
|
|
|
* |
82
|
|
|
* @param string $name |
83
|
|
|
* The property name. |
84
|
|
|
* @return bool |
85
|
|
|
* True if the property exists, false otherwise. |
86
|
|
|
*/ |
87
|
8 |
|
public static function hasDynamicProperty($name) |
88
|
|
|
{ |
89
|
8 |
|
return isset(static::$dynamicProperties[get_called_class()][$name]); |
90
|
|
|
} |
91
|
|
|
|
92
|
|
|
/** |
93
|
|
|
* Check if a dynamic method exists. |
94
|
|
|
* |
95
|
|
|
* @param string $name |
96
|
|
|
* The property name. |
97
|
|
|
* @return bool |
98
|
|
|
* True if the property exists, false otherwise. |
99
|
|
|
*/ |
100
|
7 |
|
public static function hasDynamicMethod($name) |
101
|
|
|
{ |
102
|
7 |
|
return isset(static::$dynamicMethods[get_called_class()][$name]); |
103
|
|
|
} |
104
|
|
|
|
105
|
|
|
/** |
106
|
|
|
* Get a dynamic property. |
107
|
|
|
* |
108
|
|
|
* @param $name |
109
|
|
|
* The property name. |
110
|
|
|
* @return mixed|null |
111
|
|
|
* The property value if it exists, null otherwise. |
112
|
|
|
*/ |
113
|
4 |
|
public static function getDynamicProperty($name) |
114
|
|
|
{ |
115
|
4 |
|
if (static::hasDynamicProperty($name)) { |
116
|
3 |
|
return static::$dynamicProperties[get_called_class()][$name]; |
117
|
|
|
} |
118
|
|
|
|
119
|
1 |
|
return null; |
120
|
|
|
} |
121
|
|
|
|
122
|
|
|
/** |
123
|
|
|
* Get a dynamic method. |
124
|
|
|
* |
125
|
|
|
* @param $name |
126
|
|
|
* The method name. |
127
|
|
|
* @return array|null |
128
|
|
|
* The method data if it exists, null otherwise. |
129
|
|
|
*/ |
130
|
4 |
|
public static function getDynamicMethod($name) |
131
|
|
|
{ |
132
|
4 |
|
return (static::hasDynamicMethod($name)) ? |
133
|
4 |
|
static::$dynamicMethods[get_called_class()][$name] : null; |
134
|
|
|
} |
135
|
|
|
|
136
|
|
|
/** |
137
|
|
|
* Clear dynamic properties. |
138
|
|
|
*/ |
139
|
1 |
|
public static function clearDynamicProperties() |
140
|
|
|
{ |
141
|
1 |
|
static::$dynamicProperties[get_called_class()] = array(); |
142
|
1 |
|
} |
143
|
|
|
|
144
|
|
|
/** |
145
|
|
|
* Clear dynamic methods. |
146
|
|
|
*/ |
147
|
1 |
|
public static function clearDynamicMethods() |
148
|
|
|
{ |
149
|
1 |
|
static::$dynamicMethods[get_called_class()] = array(); |
150
|
1 |
|
} |
151
|
|
|
|
152
|
|
|
/** |
153
|
|
|
* Remove a dynamic property. |
154
|
|
|
* |
155
|
|
|
* @param string $name |
156
|
|
|
* The property name. |
157
|
|
|
*/ |
158
|
1 |
|
public static function removeDynamicProperty($name) |
159
|
|
|
{ |
160
|
1 |
|
unset(static::$dynamicProperties[get_called_class()][$name]); |
161
|
1 |
|
} |
162
|
|
|
|
163
|
|
|
/** |
164
|
|
|
* Remove a dynamic method. |
165
|
|
|
* |
166
|
|
|
* @param string $name |
167
|
|
|
* The method name. |
168
|
|
|
*/ |
169
|
1 |
|
public static function removeDynamicMethod($name) |
170
|
|
|
{ |
171
|
1 |
|
unset(static::$dynamicMethods[get_called_class()][$name]); |
172
|
1 |
|
} |
173
|
|
|
|
174
|
|
|
/** |
175
|
|
|
* Execute a closure. |
176
|
|
|
* |
177
|
|
|
* @param \Closure $func |
178
|
|
|
* The closure. |
179
|
|
|
* @param array $parameters |
180
|
|
|
* The closure's parameters. |
181
|
|
|
* @param bool $memoize |
182
|
|
|
* The memoize parameter. |
183
|
|
|
* |
184
|
|
|
* @return mixed|null |
185
|
|
|
* The return of the closure. |
186
|
|
|
* |
187
|
|
|
* @throws \Psr\SimpleCache\InvalidArgumentException |
188
|
|
|
*/ |
189
|
5 |
|
public function doDynamicRequest(\Closure $func, array $parameters = [], $memoize = false) |
190
|
|
|
{ |
191
|
5 |
|
if (!class_exists('\drupol\Memoize\Memoize') || false === $memoize) { |
192
|
5 |
|
$memoize = false; |
193
|
|
|
} |
194
|
|
|
|
195
|
5 |
|
if (true === $memoize) { |
196
|
2 |
|
return $this->memoize($func, $parameters); |
197
|
|
|
} |
198
|
|
|
|
199
|
5 |
|
$class = get_called_class(); |
200
|
5 |
|
$reflexion = new \ReflectionClass($class); |
201
|
|
|
|
202
|
5 |
|
if (!$reflexion->isAnonymous()) { |
203
|
5 |
|
$func = $func->bindTo($this, $class); |
204
|
|
|
} |
205
|
|
|
|
206
|
5 |
|
return call_user_func_array($func, $parameters); |
207
|
|
|
} |
208
|
|
|
|
209
|
|
|
/** |
210
|
|
|
* Extend the dynamic object. |
211
|
|
|
* |
212
|
|
|
* @param mixed $extensions |
213
|
|
|
* A file that returns a callable or a callable. |
214
|
|
|
* |
215
|
|
|
* @return $this |
216
|
|
|
* |
217
|
|
|
* @throws \InvalidArgumentException |
218
|
|
|
*/ |
219
|
1 |
|
public function extend($extensions = null) |
220
|
|
|
{ |
221
|
1 |
|
if (is_string($extensions) && file_exists($extensions)) { |
222
|
1 |
|
$extensions = include $extensions; |
223
|
|
|
} |
224
|
|
|
|
225
|
1 |
|
if (is_callable($extensions)) { |
226
|
1 |
|
call_user_func($extensions, $this); |
227
|
|
|
|
228
|
1 |
|
return $this; |
229
|
|
|
} |
230
|
|
|
|
231
|
1 |
|
if (is_null($extensions)) { |
232
|
1 |
|
return $this; |
233
|
|
|
} |
234
|
|
|
|
235
|
1 |
|
throw new \InvalidArgumentException( |
236
|
1 |
|
'DynamicObjectsTrait::extend() requires a callable or a file that returns one.' |
237
|
|
|
); |
238
|
|
|
} |
239
|
|
|
|
240
|
|
|
/** |
241
|
|
|
* @param $method |
242
|
|
|
* @param array $parameters |
243
|
|
|
* |
244
|
|
|
* @return mixed |
245
|
|
|
* @throws \Psr\SimpleCache\InvalidArgumentException |
246
|
|
|
*/ |
247
|
4 |
|
public function __call($method, array $parameters = array()) |
248
|
|
|
{ |
249
|
4 |
|
if ($data = static::getDynamicMethod($method)) { |
250
|
3 |
|
return $this->doDynamicRequest($data['factory'], $parameters, $data['memoize']); |
251
|
|
|
} |
252
|
|
|
|
253
|
1 |
|
throw new \BadMethodCallException(sprintf('Undefined method: %s().', $method)); |
254
|
|
|
} |
255
|
|
|
|
256
|
|
|
/** |
257
|
|
|
* @param $method |
258
|
|
|
* @param array $parameters |
259
|
|
|
* |
260
|
|
|
* @return mixed |
261
|
|
|
* @throws \Psr\SimpleCache\InvalidArgumentException |
262
|
|
|
*/ |
263
|
2 |
|
public static function __callStatic($method, array $parameters = array()) |
264
|
|
|
{ |
265
|
2 |
|
$instance = new static(); |
266
|
|
|
|
267
|
2 |
|
if ($data = static::getDynamicMethod($method)) { |
268
|
1 |
|
if (true == $data['static']) { |
269
|
1 |
|
return $instance->doDynamicRequest($data['factory'], $parameters, $data['memoize']); |
270
|
|
|
} |
271
|
|
|
} |
272
|
|
|
|
273
|
1 |
|
throw new \BadMethodCallException(sprintf('Undefined static method: %s().', $method)); |
274
|
|
|
} |
275
|
|
|
|
276
|
|
|
/** |
277
|
|
|
* {inheritdoc} |
278
|
|
|
*/ |
279
|
4 |
|
public function __get($property) |
280
|
|
|
{ |
281
|
4 |
|
if ($data = static::getDynamicProperty($property)) { |
282
|
3 |
|
$return = $data['factory']; |
283
|
|
|
|
284
|
3 |
|
if (is_callable($data['factory'])) { |
285
|
2 |
|
$return = $this->doDynamicRequest($data['factory'], [], $data['memoize']); |
286
|
|
|
} |
287
|
|
|
|
288
|
3 |
|
return $return; |
289
|
|
|
} |
290
|
|
|
|
291
|
1 |
|
throw new \DomainException(sprintf('Undefined property: %s.', $property)); |
292
|
|
|
} |
293
|
|
|
|
294
|
|
|
/** |
295
|
|
|
* {inheritdoc} |
296
|
|
|
*/ |
297
|
3 |
|
public function __set($property, $value) |
298
|
|
|
{ |
299
|
3 |
|
if (static::hasDynamicProperty($property)) { |
300
|
1 |
|
static::addDynamicProperty($property, $value); |
301
|
|
|
} |
302
|
3 |
|
} |
303
|
|
|
} |
304
|
|
|
|
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.