Completed
Push — work-fleets ( 71ccb1...0d1d7f )
by SuperNova.WS
06:04
created

PropertyHider::_adjustValueString()   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 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
c 1
b 0
f 0
nc 1
nop 2
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
1
<?php
2
3
/**
4
 * Class PropertyHider
5
 *
6
 * Hides properties from visibility
7
 * Implements new set of methods adjXXX
8
 * - adjXXX method returns value of property adjusted by $diff
9
 */
10
class PropertyHider extends stdClass {
11
12
  /**
13
   * Property list
14
   *
15
   * @var array[]
16
   */
17
  protected static $_properties = array();
18
19
  /**
20
   * List of property names that was changed since last DB operation
21
   *
22
   * @var boolean[]
23
   */
24
  protected $propertiesChanged = array();
25
  /**
26
   * List of property names->$delta that was adjusted since last DB operation - and then need to be processed as Deltas
27
   *
28
   * @var array
29
   */
30
  protected $propertiesAdjusted = array();
31
32
  //+
33
  /**
34
   * @param array $properties
35
   */
36 1
  public static function setProperties($properties) {
37
    // TODO - reset internals??
38 1
    static::$_properties = $properties;
39 1
  }
40
41
  //+
42 1
  public static function getProperties() {
43 1
    return static::$_properties;
44
  }
45
46
  //+
47
  /**
48
   * PropertyHider constructor.
49
   */
50 1
  public function __construct() {
51 1
  }
52
53
  //+
54 2
  protected function checkPropertyExists($name) {
55 2 View Code Duplication
    if (!array_key_exists($name, static::$_properties)) {
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...
56 1
      throw new ExceptionPropertyNotExists('Property [' . get_called_class() . '::' . $name . '] not exists', ERR_ERROR);
57
    }
58 1
  }
59
60
  //+
61 2
  protected function checkOverwriteAdjusted($name) {
62 2 View Code Duplication
    if (array_key_exists($name, $this->propertiesAdjusted)) {
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...
63 1
      throw new PropertyAccessException('Property [' . get_called_class() . '::' . $name . '] already was adjusted so no SET is possible until dbSave', ERR_ERROR);
64
    }
65 1
  }
66
67
  //+
68 1
  private function getPhysicalPropertyName($name) {
69 1
    return '_' . $name;
70
  }
71
72
  //+
73 1
  protected function isPropertyDeclared($name) {
74 1
    return property_exists($this, $this->getPhysicalPropertyName($name));
75
  }
76
77
  //+
78
  /**
79
   * Getter with support of protected methods
80
   *
81
   * @param $name
82
   *
83
   * @return mixed
84
   * @throws ExceptionPropertyNotExists
85
   */
86 3 View Code Duplication
  public function __get($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...
87 3
    $this->checkPropertyExists($name);
88
89 2
    $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...
90
    // Now deciding - will we call a protected setter or will we work with protected property
91 2
    if (method_exists($this, $methodName = 'get' . ucfirst($name))) {
92
      // If method exists - just calling it
93 1
      $result = call_user_func_array(array($this, $methodName), array());
94 2
    } elseif ($this->isPropertyDeclared($name)) {
95
      // No getter exists - works directly with protected property
96 1
      $result = $this->{$this->getPhysicalPropertyName($name)};
97 1
    } else {
98 1
      throw new ExceptionPropertyNotExists('Property [' . get_called_class() . '::' . $name . '] does not have getter/property to get', ERR_ERROR);
99
    }
100
101 1
    return $result;
102
  }
103
104
  //+
105
  /**
106
   * Unsafe setter - w/o checking if the property was already adjusted
107
   *
108
   * @param string $name
109
   * @param mixed  $value
110
   *
111
   * @return mixed|null
112
   * @throws ExceptionPropertyNotExists
113
   */
114 3 View Code Duplication
  protected function _setUnsafe($name, $value) {
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...
115 3
    $result = null;
116
    // Now deciding - will we call a protected setter or will we work with protected property
117 3
    if (method_exists($this, $methodName = 'set' . ucfirst($name))) {
118
      // If method exists - just calling it
119
      // TODO - should return TRUE if value changed or FALSE otherwise
120 1
      $result = call_user_func_array(array($this, $methodName), array($value));
121 3
    } elseif ($this->isPropertyDeclared($name)) {
122
      // No setter exists - works directly with protected property
123
//      if($result = $this->$propertyName !== $value) {
124 1
      $this->{$this->getPhysicalPropertyName($name)} = $value;
125
//      }
126 1
    } else {
127 2
      throw new ExceptionPropertyNotExists('Property [' . get_called_class() . '::' . $name . '] does not have setter/property to set', ERR_ERROR);
128
    }
129
130
    // TODO - should be primed only if value changed
131
//    if($result) {
132 1
    $this->propertiesChanged[$name] = true;
133
134
//    }
135
136 1
    return $result;
137
  }
138
139
  /**
140
   * Setter wrapper with support of protected properties/methods
141
   *
142
   * @param string $name
143
   * @param mixed  $value
144
   *
145
   * @return mixed|null
146
   * @throws ExceptionPropertyNotExists
147
   */
148
  // TODO - сеттер должен параллельно изменять значение db_row - for now...
149
  // TODO - Проверка, а действительно ли данные были изменены?? Понадобится определение типов - разные типы сравниваются по-разному
150 1
  public function __set($name, $value) {
151 1
    $this->checkPropertyExists($name);
152 1
    $this->checkOverwriteAdjusted($name);
153
154 1
    return $this->_setUnsafe($name, $value);
155
  }
156
157
158
  /**
159
   * @param string $name
160
   * @param int    $diff
161
   *
162
   * @return int
163
   */
164 2
  protected function _adjustValueInteger($name, $diff) {
165 2
    return intval($this->$name) + intval($diff);
166
  }
167
168
  /**
169
   * @param string $name
170
   * @param float  $diff
171
   *
172
   * @return float
173
   */
174 1
  protected function _adjustValueDouble($name, $diff) {
175 1
    return floatval($this->$name) + floatval($diff);
176
  }
177
178
  /**
179
   * @param string $name
180
   * @param string $diff
181
   *
182
   * @return string
183
   */
184 1
  protected function _adjustValueString($name, $diff) {
185 1
    return (string)$this->$name . (string)$diff;
186
  }
187
188
  /**
189
   * @param string $name
190
   * @param array $diff
191
   *
192
   * @return array
193
   */
194 1
  protected function _adjustValueArray($name, $diff) {
195 1
    $copy = (array)$this->$name;
196 1
    HelperArray::merge($copy, (array)$diff, HelperArray::MERGE_PHP);
197 1
    return $copy;
198
  }
199
200
  /**
201
   * @param string $name
202
   * @param int    $diff
203
   *
204
   * @return int
205
   */
206 2
  protected function _adjustValueIntegerDiff($name, $diff) {
207 2
    return (int)HelperArray::keyExistsOr($this->propertiesAdjusted, $name, 0) + (int)$diff;
208
  }
209
210
  /**
211
   * @param string $name
212
   * @param float  $diff
213
   *
214
   * @return float
215
   */
216 1
  protected function _adjustValueDoubleDiff($name, $diff) {
217 1
    return (float)HelperArray::keyExistsOr($this->propertiesAdjusted, $name, 0.0) + (float)$diff;
218
  }
219
220
  /**
221
   * @param string $name
222
   * @param string $diff
223
   *
224
   * @return string
225
   */
226 1
  protected function _adjustValueStringDiff($name, $diff) {
227 1
    return (string)HelperArray::keyExistsOr($this->propertiesAdjusted, $name, '') . (string)$diff;
228
  }
229
230
  /**
231
   * @param string $name
232
   * @param array $diff
233
   *
234
   * @return array
235
   */
236 1
  protected function _adjustValueArrayDiff($name, $diff) {
237 1
    $copy = (array)HelperArray::keyExistsOr($this->propertiesAdjusted, $name, array());
238 1
    HelperArray::merge($copy, $diff, HelperArray::MERGE_PHP);
239 1
    return $copy;
240
  }
241
242
  /**
243
   * Get adjusted value by callback with generated name
244
   * Support types: "integer", "double", "string", "array"
245
   * Throws exception on: "boolean", "object", "resource", "NULL", "unknown type",
246
   *
247
   * @param string $name
248
   * @param mixed  $diff
249
   * @param string $suffix
250
   *
251
   * @return mixed
252
   * @throws ExceptionTypeUnsupported
253
   */
254 9
  protected function propertyMethodResult($name, $diff, $suffix = '') {
255
    // TODO - property type checks
256
    // Capitalizing type name
257 9
    $type = explode(' ', gettype($this->$name));
258 9
    array_walk($type, 'DbSqlHelper::UCFirstByRef');
259 9
    $type = implode('', $type);
260
261 9
    if (!method_exists($this, $methodName = '_adjustValue' . $type . $suffix)) {
262 1
      throw new ExceptionTypeUnsupported();
263
    }
264
265 8
    return call_user_func(array($this, $methodName), $name, $diff);
266
  }
267
268
  /**
269
   * Directly adjusts value without Adjuster
270
   *
271
   * @param string $name
272
   * @param mixed  $diff
273
   *
274
   * @return mixed
275
   */
276 1
  protected function _adjustValue($name, $diff) {
277 1
    return $this->propertyMethodResult($name, $diff);
278
  }
279
280
  /**
281
   * Directly adjusts value DIFF without Adjuster
282
   *
283
   * @param string $name
284
   * @param mixed  $diff
285
   *
286
   * @return mixed
287
   */
288 1
  protected function _adjustValueDiff($name, $diff) {
289 1
    return $this->propertyMethodResult($name, $diff, 'Diff');
290
  }
291
292
  /**
293
   * Adjust property value with $diff
294
   * Adjusted values put into DB with UPDATE query
295
   * Adjuster callback adjXXX() should return new value which will be propagated via __set()
296
   * Optionally there can be DIFF-adjuster adjXXXDiff() for complex types
297
   *
298
   * @param string $name
299
   * @param mixed  $diff
300
   *
301
   * @return mixed
302
   */
303 2
  public function __adjust($name, $diff) {
304 2
    $this->checkPropertyExists($name);
305
306
    // Now deciding - will we call a protected setter or will we work with protected property
307 2
    if (method_exists($this, $methodName = 'adj' . ucfirst($name))) {
308
      // If method exists - just calling it
309
      // Method returns new adjusted value
310 2
      $newValue = call_user_func_array(array($this, $methodName), array($diff));
311 2
    } else {
312
      // No adjuster exists - works directly with protected property
313
      // TODO - property type checks
314 1
      $newValue = $this->_adjustValue($name, $diff);
315
    }
316
317
    // Invoking property setter
318 2
    $this->_setUnsafe($name, $newValue);
319
320
    // Initializing value of adjustment
321 2
    if (!array_key_exists($name, $this->propertiesAdjusted)) {
322 2
      $this->propertiesAdjusted[$name] = null;
323 2
    }
324
325
    // Adding diff to adjustment accumulator
326 2
    if (method_exists($this, $methodName = 'adj' . ucfirst($name) . 'Diff')) {
327 1
      call_user_func_array(array($this, $methodName), array($diff));
328 1
    } else {
329
      // TODO - property type checks
330 1
      $this->propertiesAdjusted[$name] = $this->_adjustValueDiff($name, $diff);
331
    }
332
333 2
    return $this->$name;
334
  }
335
336
}
337