Completed
Push — work-fleets ( dea33d...b19a67 )
by SuperNova.WS
05:56
created

PropertyHider::getPhysicalPropertyName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
c 2
b 0
f 0
nc 1
nop 1
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
1
<?php
2
3
/**
4
 * Class PropertyHider - Hides properties from visibility
5
 *
6
 * - Property access - via property names
7
 * - Allowed property name is an index in static $_properties() array
8
 * - Property XXX can have 4 accessories:
9
 *    - getXXX - getter
10
 *    - setXXX - setter. Setting property is logging in $propertiesChanged array
11
 *    - adjustXXX - adjusts value. Delta from original value is holding in $propertiesAdjusted array
12
 *    - deltaXXX - calculates delta from original value
13
 * - Accessories can have any visibility
14
 * - Public accessories should take care setting elements of $propertiesChanged/$propertiesAdjusted arrays if needed
15
 *
16
 *
17
 * Implements new set of methods adjXXX
18
 * - adjXXX method returns value of property adjusted by $diff
19
 */
20
abstract class PropertyHider extends stdClass {
21
22
  /**
23
   * Getting value
24
   */
25
  const ACTION_GET = 'get';
26
  /**
27
   * Setting value
28
   */
29
  const ACTION_SET = 'set';
30
  /**
31
   * Adjusting value
32
   */
33
  const ACTION_ADJUST = 'adjust';
34
  /**
35
   * Calculating value
36
   */
37
  const ACTION_DELTA = 'delta';
38
39
  /**
40
   * Property list
41
   *
42
   * @var array[]
43
   */
44
  protected static $_properties = array();
45
46
  /**
47
   * List of property names that was changed since last DB operation
48
   *
49
   * @var boolean[]
50
   */
51
  protected $propertiesChanged = array();
52 1
  /**
53
   * List of property names->$delta that was adjusted since last DB operation - and then need to be processed as Deltas
54 1
   *
55 1
   * @var array
56
   */
57 1
  protected $propertiesAdjusted = array();
58 1
59
  /**
60
   * @param array $properties
61
   */
62
  public static function setProperties($properties) {
63
    // TODO - reset internals??
64 1
    static::$_properties = $properties;
65 1
  }
66
67 2
  public static function getPropertiesStatic() {
68 2
    return static::$_properties;
69 1
  }
70
71 1
  public function getProperties() {
72
    return static::$_properties;
73 2
  }
74 2
75 1
  /**
76
   * PropertyHider constructor.
77 1
   */
78
  public function __construct() {
79 1
  }
80 1
81
  protected function checkPropertyExists($name) {
82
    if (!array_key_exists($name, static::$_properties)) {
83
      throw new ExceptionPropertyNotExists('Property [' . get_called_class() . '::' . $name . '] not exists', ERR_ERROR);
84
    }
85
  }
86
87
  protected function checkOverwriteAdjusted($name) {
88
    if (array_key_exists($name, $this->propertiesAdjusted)) {
89
      throw new PropertyAccessException('Property [' . get_called_class() . '::' . $name . '] already was adjusted so no SET is possible until dbSave', ERR_ERROR);
90
    }
91 1
  }
92
93 1
  /**
94
   * Method checks if action is available for named property
95
   *
96
   * @param string $name
97
   * @param string $action
98
   *
99
   * @return bool
100
   */
101
  abstract protected function isPropertyActionAvailable($name, $action = '');
102
  /**
103
   * Internal method that make real changes to property value
104
   * May be override in child class
105
   *
106
   * @param string $name
107
   * @param mixed  $value
108
   *
109
   * @return mixed
110
   */
111
  abstract protected function setProperty($name, $value);
112
  /**
113
   * Internal method that make really reads property value
114
   * May be override in child class
115
   *
116
   * @param string $name
117
   * @param mixed  $value - ignored. Used for compatibility
118
   *
119
   * @return mixed
120
   */
121
  abstract protected function getProperty($name, $value = null);
122
  /**
123
   * Magic method that checks if named property is set
124
   * May be override in child class
125
   *
126
   * @param $name
127
   *
128
   * @return bool
129
   */
130
  abstract public function __isset($name);
131
132
  /**
133 1
   * Directly adjusts value without Adjuster
134 1
   *
135
   * @param string $name
136
   * @param mixed  $diff
137
   *
138
   * @return mixed
139
   */
140
  protected function adjustProperty($name, $diff) {
141
    return $this->propertyMethodResult($name, $diff, 'adjustProperty');
142
  }
143
144
  /**
145 1
   * Directly adjusts value Delta for properties without Adjuster
146 1
   *
147
   * @param string $name
148
   * @param mixed  $diff
149
   *
150
   * @return mixed
151
   */
152
  protected function deltaProperty($name, $diff) {
153
    return $this->propertyMethodResult($name, $diff, 'delta');
154
  }
155
156
  /**
157
   * Performs '$action' on property with $name - possible with $value
158
   *
159
   * Universal method for call getter, setter, adjuster or delta calculator
160
   *
161
   * @param string $action
162
   * @param string $name
163
   * @param mixed  $value
164
   *
165
   * @return mixed|null
166
   * @throws ExceptionPropertyNotExists
167
   */
168
  protected function actionProperty($action, $name, $value) {
169
    $result = null;
0 ignored issues
show
Unused Code introduced by
$result is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
170
    // Now deciding - will we call a protected setter or will we work with protected property
171
    // Todo - on init recalc all method_exists
172
    if (method_exists($this, $methodName = $action . ucfirst($name))) {
173
      // If method exists - just calling it
174 3
      // TODO - should return TRUE if value changed or FALSE otherwise
175 3
      $result = call_user_func_array(array($this, $methodName), array($value));
176
    } elseif ($this->isPropertyActionAvailable($name, $action)) {
177 2
      // No setter exists - works directly with protected property
178
      $result = $this->{$action . 'Property'}($name, $value);
179 1
    } else {
180
      throw new ExceptionPropertyNotExists('Property [' . get_called_class() . '::' . $name . '] does not have ' . $action . 'ter/property to ' . $action, ERR_ERROR);
181
    }
182
183
    return $result;
184
  }
185
186
  /**
187
   * Getter with support of protected methods
188
   *
189
   * @param $name
190
   *
191
   * @return mixed
192
   * @throws ExceptionPropertyNotExists
193 3
   */
194 3
  public function __get($name) {
195
    $this->checkPropertyExists($name);
196
197
    $result = $this->actionProperty('get', $name, null);
198 1
199
    return $result;
200
  }
201
202 1
203
  //+
204
  /**
205
   * Unsafe setter - w/o checking if the property was already adjusted
206
   *
207
   * @param string $name
208
   * @param mixed  $value
209
   *
210
   * @return mixed|null
211
   * @throws ExceptionPropertyNotExists
212
   */
213
  protected function _setUnsafe($name, $value) {
214
    $result = $this->actionProperty('set', $name, $value);
215
216 1
    // TODO - should be primed only if value changed
217 1
//    if($result) {
218 1
    $this->propertiesChanged[$name] = true;
219
220 1
//    }
221
222
    return $result;
223
  }
224
225
  /**
226
   * Setter wrapper with support of protected properties/methods
227
   *
228
   * @param string $name
229
   * @param mixed  $value
230 2
   *
231 2
   * @return mixed|null
232
   * @throws ExceptionPropertyNotExists
233
   */
234
  // TODO - сеттер должен параллельно изменять значение db_row - for now...
235
  // TODO - Проверка, а действительно ли данные были изменены?? Понадобится определение типов - разные типы сравниваются по-разному
236
  public function __set($name, $value) {
237
    $this->checkOverwriteAdjusted($name);
238
    $this->checkPropertyExists($name);
239
240 1
    return $this->_setUnsafe($name, $value);
241 1
  }
242
243
244
  /**
245
   * @param string $name
246
   * @param int    $diff
247
   *
248
   * @return int
249
   */
250 1
  protected function adjustPropertyInteger($name, $diff) {
251 1
    return intval($this->$name) + intval($diff);
252
  }
253
254
  /**
255
   * @param string $name
256
   * @param float  $diff
257
   *
258
   * @return float
259
   */
260 1
  protected function adjustPropertyDouble($name, $diff) {
261 1
    return floatval($this->$name) + floatval($diff);
262 1
  }
263
264 1
  /**
265
   * @param string $name
266
   * @param string $diff
267
   *
268
   * @return string
269
   */
270
  protected function adjustPropertyString($name, $diff) {
271
    return (string)$this->$name . (string)$diff;
272
  }
273 2
274 2
  /**
275
   * @param string $name
276
   * @param array  $diff
277
   *
278
   * @return array
279
   */
280
  protected function adjustPropertyArray($name, $diff) {
281
    $copy = (array)$this->$name;
282
    HelperArray::merge($copy, (array)$diff, HelperArray::MERGE_PHP);
283 1
284 1
    return $copy;
285
  }
286
287
  /**
288
   * @param string $name
289
   * @param int    $diff
290
   *
291
   * @return int
292
   */
293 1
  protected function deltaInteger($name, $diff) {
294 1
    return (int)HelperArray::keyExistsOr($this->propertiesAdjusted, $name, 0) + (int)$diff;
295
  }
296
297
  /**
298
   * @param string $name
299
   * @param float  $diff
300
   *
301
   * @return float
302
   */
303 1
  protected function deltaDouble($name, $diff) {
304 1
    return (float)HelperArray::keyExistsOr($this->propertiesAdjusted, $name, 0.0) + (float)$diff;
305 1
  }
306
307 1
  /**
308
   * @param string $name
309
   * @param string $diff
310
   *
311
   * @return string
312
   */
313
  protected function deltaString($name, $diff) {
314
    return (string)HelperArray::keyExistsOr($this->propertiesAdjusted, $name, '') . (string)$diff;
315
  }
316
317
  /**
318
   * @param string $name
319
   * @param array  $diff
320
   *
321
   * @return array
322 13
   */
323 13
  protected function deltaArray($name, $diff) {
324
    $copy = (array)HelperArray::keyExistsOr($this->propertiesAdjusted, $name, array());
325 13
    HelperArray::merge($copy, $diff, HelperArray::MERGE_PHP);
326 13
327 13
    return $copy;
328
  }
329 13
330 5
  /**
331
   * Get adjusted value by callback with generated name
332
   * Support types: "integer", "double", "string", "array"
333 8
   * Throws exception on: "boolean", "object", "resource", "NULL", "unknown type",
334
   *
335
   * @param string $name
336
   * @param mixed  $diff
337
   * @param string $prefix
338
   *
339
   * @return mixed
340
   * @throws ExceptionTypeUnsupported
341
   */
342
  protected function propertyMethodResult($name, $diff, $prefix = '') {
343
    $type = gettype($this->$name);
344
    // Capitalizing type name
345
    $methodName = explode(' ', $type);
346
    array_walk($methodName, 'DbSqlHelper::UCFirstByRef');
347 2
    $methodName = $prefix . implode('', $methodName);
348 2
349
    if (!method_exists($this, $methodName)) {
350 2
      throw new ExceptionTypeUnsupported('Type "' . $type . '" is unsupported in PropertyHider::propertyMethodResult');
351
    }
352
353 2
    return call_user_func(array($this, $methodName), $name, $diff);
354
  }
355
356 2
  /**
357 2
   * Adjust property value with $diff
358 2
   * Adjusted values put into DB with UPDATE query
359
   * Adjuster callback adjXXX() should return new value which will be propagated via __set()
360 2
   * Optionally there can be DIFF-adjuster adjXXXDiff() for complex types
361
   *
362 2
   * @param string $name
363
   * @param mixed  $diff
364
   *
365
   * @return mixed
366
   */
367
  public function __adjust($name, $diff) {
368
    $this->checkPropertyExists($name);
369
370
    $result = $this->actionProperty('adjust', $name, $diff);
371
372
    // Invoking property setter
373
    $this->_setUnsafe($name, $result);
374
375
    // Initializing value of adjustment
376
    if (!array_key_exists($name, $this->propertiesAdjusted)) {
377
      $this->propertiesAdjusted[$name] = null;
378
    }
379
380
    $this->propertiesAdjusted[$name] = $this->actionProperty('delta', $name, $diff);
381
382
    return $this->$name;
383
  }
384
385
}
386