|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
/** |
|
4
|
|
|
* Class PropertyHider |
|
5
|
|
|
* |
|
6
|
|
|
* Hides properties from visibility |
|
7
|
|
|
*/ |
|
8
|
|
|
class PropertyHider extends stdClass { |
|
9
|
|
|
|
|
10
|
|
|
/** |
|
11
|
|
|
* Property list |
|
12
|
|
|
* |
|
13
|
|
|
* @var array[] |
|
14
|
|
|
*/ |
|
15
|
|
|
protected static $_properties = array(); |
|
16
|
|
|
|
|
17
|
|
|
/** |
|
18
|
|
|
* List of property names that was changed since last DB operation |
|
19
|
|
|
* |
|
20
|
|
|
* @var string[] |
|
21
|
|
|
*/ |
|
22
|
|
|
protected $propertiesChanged = array(); |
|
23
|
|
|
/** |
|
24
|
|
|
* List of property names->$delta that was adjusted since last DB operation - and then need to be processed as Deltas |
|
25
|
|
|
* |
|
26
|
|
|
* @var string[] |
|
27
|
|
|
*/ |
|
28
|
|
|
protected $propertiesAdjusted = array(); |
|
29
|
|
|
|
|
30
|
|
|
/** |
|
31
|
|
|
* @param array $properties |
|
32
|
|
|
*/ |
|
33
|
1 |
|
public static function setProperties($properties) { |
|
34
|
|
|
// TODO - reset internals?? |
|
35
|
1 |
|
static::$_properties = $properties; |
|
36
|
1 |
|
} |
|
37
|
|
|
|
|
38
|
1 |
|
public static function getProperties() { |
|
39
|
1 |
|
return static::$_properties; |
|
40
|
|
|
} |
|
41
|
|
|
|
|
42
|
|
|
/** |
|
43
|
|
|
* PropertyHider constructor. |
|
44
|
|
|
*/ |
|
45
|
1 |
|
public function __construct() { |
|
46
|
1 |
|
} |
|
47
|
|
|
|
|
48
|
|
|
// protected function checkForGetSet($name, $left3) { |
|
|
|
|
|
|
49
|
|
|
// // If method is not getter or setter OR property name not exists in $_properties - raising exception |
|
50
|
|
|
// // Descendants can catch this Exception to make own __call magic |
|
51
|
|
|
// if ($left3 != 'get' && $left3 != 'set') { |
|
52
|
|
|
// throw new ExceptionNotGetterOrSetter('Magic call is not getter or setter ' . get_called_class() . '::' . $name, ERR_ERROR); |
|
53
|
|
|
// } |
|
54
|
|
|
// } |
|
55
|
|
|
// |
|
56
|
|
|
// protected function checkForPropertyExists($name, $propertyName) { |
|
57
|
|
|
// if (empty(static::$_properties[$propertyName])) { |
|
58
|
|
|
// throw new ExceptionPropertyNotExists('Property ' . $propertyName . ' not exists when calling getter/setter ' . get_called_class() . '::' . $name, ERR_ERROR); |
|
59
|
|
|
// } |
|
60
|
|
|
// } |
|
61
|
|
|
|
|
62
|
|
|
// protected function checkForDoubleAdjust($name, $left3, $propertyName) { |
|
|
|
|
|
|
63
|
|
|
// if ($left3 == 'set' && array_key_exists($propertyName, $this->propertiesAdjusted)) { |
|
64
|
|
|
// throw new PropertyAccessException('Property ' . $propertyName . ' already was adjusted so no SET is possible until dbSave in ' . get_called_class() . '::' . $name, ERR_ERROR); |
|
65
|
|
|
// } |
|
66
|
|
|
// } |
|
67
|
|
|
|
|
68
|
|
|
// /** |
|
|
|
|
|
|
69
|
|
|
// * Handles getters and setters |
|
70
|
|
|
// * |
|
71
|
|
|
// * @param string $name |
|
72
|
|
|
// * @param array $arguments |
|
73
|
|
|
// * |
|
74
|
|
|
// * @return mixed |
|
75
|
|
|
// * @throws ExceptionNotGetterOrSetter |
|
76
|
|
|
// * @throws ExceptionPropertyNotExists |
|
77
|
|
|
// * @throws PropertyAccessException |
|
78
|
|
|
// */ |
|
79
|
|
|
// protected function callGetSet($name, $arguments) { |
|
80
|
|
|
// $this->checkForGetSet($name, $left3 = substr($name, 0, 3)); |
|
81
|
|
|
// $this->checkForPropertyExists($name, $propertyName = lcfirst(substr($name, 3))); |
|
82
|
|
|
// // TODO check for read-only |
|
83
|
|
|
// $this->checkForDoubleAdjust($name, $left3, $propertyName); |
|
84
|
|
|
// |
|
85
|
|
|
// $result = null; |
|
86
|
|
|
// |
|
87
|
|
|
// // Now deciding - will we call a protected setter or will we work with protected property |
|
88
|
|
|
// if (method_exists($this, $name)) { |
|
89
|
|
|
// // If method exists - just calling it |
|
90
|
|
|
// $result = call_user_func_array(array($this, $name), $arguments); |
|
91
|
|
|
// } else { |
|
92
|
|
|
// // No getter/setter exists - works directly with protected property |
|
93
|
|
|
// if ($left3 === 'set') { |
|
94
|
|
|
// $this->{'_' . $propertyName} = $arguments[0]; |
|
95
|
|
|
// } elseif ($left3 === 'get') { |
|
96
|
|
|
// $result = $this->{'_' . $propertyName}; |
|
97
|
|
|
// } |
|
98
|
|
|
// } |
|
99
|
|
|
// |
|
100
|
|
|
// if ($left3 === 'set') { |
|
101
|
|
|
// $this->propertiesChanged[$propertyName] = true; |
|
102
|
|
|
// } |
|
103
|
|
|
// |
|
104
|
|
|
// return $result; |
|
105
|
|
|
// } |
|
106
|
|
|
|
|
107
|
|
|
// public function __call($name, $arguments) { |
|
|
|
|
|
|
108
|
|
|
// $this->callGetSet($name, $arguments); |
|
109
|
|
|
// } |
|
110
|
|
|
|
|
111
|
5 |
|
protected function checkPropertyExists($name) { |
|
112
|
5 |
|
if (!array_key_exists($name, static::$_properties)) { |
|
113
|
2 |
|
throw new ExceptionPropertyNotExists('Property [' . get_called_class() . '::' . $name . '] not exists when accessing via __get/__set', ERR_ERROR); |
|
114
|
|
|
} |
|
115
|
3 |
|
} |
|
116
|
|
|
|
|
117
|
3 |
|
protected function checkOverwriteAdjusted($name) { |
|
118
|
3 |
|
if (array_key_exists($name, $this->propertiesAdjusted)) { |
|
119
|
1 |
|
throw new PropertyAccessException('Property [' . get_called_class() . '::' . $name . '] already was adjusted so no SET is possible until dbSave', ERR_ERROR); |
|
120
|
|
|
} |
|
121
|
2 |
|
} |
|
122
|
|
|
|
|
123
|
|
|
|
|
124
|
|
|
/** |
|
125
|
|
|
* Getter with support of protected methods |
|
126
|
|
|
* |
|
127
|
|
|
* @param $name |
|
128
|
|
|
* |
|
129
|
|
|
* @return mixed |
|
130
|
|
|
* @throws ExceptionPropertyNotExists |
|
131
|
|
|
*/ |
|
132
|
4 |
View Code Duplication |
public function __get($name) { |
|
|
|
|
|
|
133
|
4 |
|
$this->checkPropertyExists($name); |
|
134
|
|
|
|
|
135
|
3 |
|
$result = null; |
|
|
|
|
|
|
136
|
|
|
// Now deciding - will we call a protected setter or will we work with protected property |
|
137
|
3 |
|
if (method_exists($this, $methodName = 'get' . ucfirst($name))) { |
|
138
|
|
|
// If method exists - just calling it |
|
139
|
2 |
|
$result = call_user_func_array(array($this, $methodName), array()); |
|
140
|
3 |
|
} elseif (property_exists($this, $propertyName = '_' . $name)) { |
|
141
|
|
|
// No getter exists - works directly with protected property |
|
142
|
2 |
|
$result = $this->$propertyName; |
|
143
|
2 |
|
} else { |
|
144
|
1 |
|
throw new ExceptionPropertyNotExists('Property [' . get_called_class() . '::' . $name . '] does not have getter/property to get', ERR_ERROR); |
|
145
|
|
|
} |
|
146
|
|
|
|
|
147
|
2 |
|
return $result; |
|
148
|
|
|
} |
|
149
|
|
|
|
|
150
|
|
|
/** |
|
151
|
|
|
* Real setter function |
|
152
|
|
|
* |
|
153
|
|
|
* @param string $name |
|
154
|
|
|
* @param mixed $value |
|
155
|
|
|
* |
|
156
|
|
|
* @return mixed|null |
|
157
|
|
|
* @throws ExceptionPropertyNotExists |
|
158
|
|
|
*/ |
|
159
|
4 |
View Code Duplication |
protected function ___set($name, $value) { |
|
|
|
|
|
|
160
|
4 |
|
$result = null; |
|
161
|
|
|
// Now deciding - will we call a protected setter or will we work with protected property |
|
162
|
4 |
|
if (method_exists($this, $methodName = 'set' . ucfirst($name))) { |
|
163
|
|
|
// If method exists - just calling it |
|
164
|
|
|
// TODO - should return TRUE if value changed or FALSE otherwise |
|
165
|
2 |
|
$result = call_user_func_array(array($this, $methodName), array($value)); |
|
166
|
4 |
|
} elseif (property_exists($this, $propertyName = '_' . $name)) { |
|
167
|
|
|
// No setter exists - works directly with protected property |
|
168
|
3 |
|
$this->$propertyName = $value; |
|
169
|
3 |
|
} else { |
|
170
|
1 |
|
throw new ExceptionPropertyNotExists('Property [' . get_called_class() . '::' . $name . '] does not have setter/property to set', ERR_ERROR); |
|
171
|
|
|
} |
|
172
|
|
|
|
|
173
|
|
|
// TODO - should be primed only if value changed |
|
174
|
3 |
|
$this->propertiesChanged[$name] = true; |
|
175
|
|
|
|
|
176
|
3 |
|
return $result; |
|
177
|
|
|
} |
|
178
|
|
|
|
|
179
|
|
|
/** |
|
180
|
|
|
* Setter wrapper with support of protected properties/methods |
|
181
|
|
|
* |
|
182
|
|
|
* @param string $name |
|
183
|
|
|
* @param mixed $value |
|
184
|
|
|
* |
|
185
|
|
|
* @return mixed|null |
|
186
|
|
|
* @throws ExceptionPropertyNotExists |
|
187
|
|
|
*/ |
|
188
|
|
|
// TODO - сеттер должен параллельно изменять значение db_row - for now... |
|
189
|
|
|
// TODO - Проверка, а действительно ли данные были изменены?? Понадобится определение типов - разные типы сравниваются по-разному |
|
190
|
4 |
|
public function __set($name, $value) { |
|
191
|
4 |
|
$this->checkPropertyExists($name); |
|
192
|
3 |
|
$this->checkOverwriteAdjusted($name); |
|
193
|
|
|
|
|
194
|
2 |
|
$result = $this->___set($name, $value); |
|
195
|
|
|
|
|
196
|
1 |
|
return $result; |
|
197
|
|
|
} |
|
198
|
|
|
|
|
199
|
|
|
/** |
|
200
|
|
|
* Adjust property value with $diff |
|
201
|
|
|
* Adjusted values put into DB with UPDATE query |
|
202
|
|
|
* Adjuster callback adjXXX() should return new value which will be propagated via ___set() |
|
203
|
|
|
* |
|
204
|
|
|
* @param string $name |
|
205
|
|
|
* @param mixed $diff |
|
206
|
|
|
* |
|
207
|
|
|
* @return mixed |
|
208
|
|
|
*/ |
|
209
|
1 |
|
public function __adjust($name, $diff) { |
|
210
|
1 |
|
$this->checkPropertyExists($name); |
|
211
|
|
|
|
|
212
|
|
|
// Now deciding - will we call a protected setter or will we work with protected property |
|
213
|
1 |
|
if (method_exists($this, $methodName = 'adj' . ucfirst($name))) { |
|
214
|
|
|
// If method exists - just calling it |
|
215
|
|
|
// TODO - should return TRUE if value changed or FALSE otherwise |
|
216
|
1 |
|
$newValue = call_user_func_array(array($this, $methodName), array($diff)); |
|
217
|
1 |
|
} else { |
|
218
|
|
|
// No adjuster exists - works directly with protected property |
|
219
|
|
|
// TODO - property type checks |
|
220
|
1 |
|
$newValue = $this->$name + $diff; |
|
221
|
|
|
} |
|
222
|
|
|
|
|
223
|
1 |
|
$this->___set($name, $newValue); |
|
224
|
|
|
|
|
225
|
1 |
|
if (!array_key_exists($name, $this->propertiesAdjusted)) { |
|
226
|
1 |
|
$this->propertiesAdjusted[$name] = null; |
|
227
|
1 |
|
} |
|
228
|
|
|
|
|
229
|
1 |
|
$this->propertiesAdjusted[$name] += $diff; |
|
230
|
|
|
|
|
231
|
1 |
|
return $this->$name; |
|
232
|
|
|
} |
|
233
|
|
|
|
|
234
|
|
|
} |
|
235
|
|
|
|
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.