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