1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Created by Gorlum 16.06.2017 14:32 |
4
|
|
|
*/ |
5
|
|
|
|
6
|
|
|
namespace Common; |
7
|
|
|
|
8
|
|
|
|
9
|
|
|
use Exception; |
10
|
|
|
|
11
|
|
|
/** |
12
|
|
|
* Class AccessLogged |
13
|
|
|
* |
14
|
|
|
* Logs property changes. It's necessary for delta and/or partial DB updates |
15
|
|
|
* |
16
|
|
|
* On first property change it goes to start values |
17
|
|
|
* |
18
|
|
|
* @package Common |
19
|
|
|
*/ |
20
|
|
|
class AccessLogged extends AccessMagic { |
21
|
|
|
const ACCESS_SET = null; |
22
|
|
|
const ACCESS_DELTA_INC = +1; |
23
|
|
|
const ACCESS_DELTA_DEC = -1; |
24
|
|
|
|
25
|
|
|
/** |
26
|
|
|
* Starting values of properties |
27
|
|
|
* |
28
|
|
|
* @var array $_startValues |
29
|
|
|
*/ |
30
|
|
|
protected $_startValues = []; |
31
|
|
|
/** |
32
|
|
|
* Changed values |
33
|
|
|
* |
34
|
|
|
* @var array $_changes |
35
|
|
|
*/ |
36
|
|
|
protected $_changes = []; |
37
|
|
|
/** |
38
|
|
|
* Increment/Decrement results AKA deltas |
39
|
|
|
* |
40
|
|
|
* @var array $_deltas |
41
|
|
|
*/ |
42
|
|
|
protected $_deltas = []; |
43
|
|
|
|
44
|
|
|
/** |
45
|
|
|
* Current operation: direct store or positive/negative delta which would be applied on next __set() call |
46
|
|
|
* |
47
|
|
|
* @var int|float $_currentOperation |
48
|
|
|
*/ |
49
|
|
|
protected $_currentOperation = self::ACCESS_SET; |
50
|
|
|
|
51
|
2 |
|
public function __set($name, $value) { |
52
|
2 |
|
if ($this->_currentOperation === self::ACCESS_SET) { |
53
|
2 |
|
$this->valueSet($name, $value); |
54
|
2 |
|
} else { |
55
|
2 |
|
$this->valueDelta($name, $value); |
56
|
|
|
} |
57
|
2 |
|
} |
58
|
|
|
|
59
|
1 |
|
public function clear() { |
60
|
1 |
|
parent::clear(); |
61
|
1 |
|
$this->commit(); |
62
|
1 |
|
} |
63
|
|
|
|
64
|
|
|
/** |
65
|
|
|
* @param string $name |
66
|
|
|
* |
67
|
|
|
* @throws Exception |
68
|
|
|
*/ |
69
|
1 |
|
protected function blockChange($name) { |
70
|
1 |
|
if (array_key_exists($name, $this->_deltas)) { |
71
|
1 |
|
throw new Exception(get_called_class() . '::' . $name . ' already INCREMENTED/DECREMENTED - can not CHANGE', ERR_ERROR); |
72
|
|
|
} |
73
|
1 |
|
} |
74
|
|
|
|
75
|
|
|
/** |
76
|
|
|
* @param string $name |
77
|
|
|
* |
78
|
|
|
* @throws Exception |
79
|
|
|
*/ |
80
|
1 |
|
protected function blockDelta($name) { |
81
|
1 |
|
if (array_key_exists($name, $this->_changes)) { |
82
|
1 |
|
throw new Exception(get_called_class() . '::' . $name . ' already changed - can not use DELTA', ERR_ERROR); |
83
|
|
|
} |
84
|
1 |
|
} |
85
|
|
|
|
86
|
|
|
/** |
87
|
|
|
* @param string $name |
88
|
|
|
* @param $value |
89
|
|
|
* |
90
|
|
|
* @throws Exception |
91
|
|
|
*/ |
92
|
2 |
|
protected function valueSet($name, $value) { |
93
|
2 |
|
if ($this->__isset($name)) { |
94
|
2 |
|
$this->blockChange($name); |
95
|
|
|
|
96
|
2 |
|
$this->_changes[$name] = $value; |
97
|
2 |
|
} else { |
98
|
2 |
|
$this->_startValues[$name] = $value; |
99
|
|
|
} |
100
|
|
|
|
101
|
2 |
|
parent::__set($name, $value); |
102
|
2 |
|
} |
103
|
|
|
|
104
|
|
|
/** |
105
|
|
|
* @param string $name |
106
|
|
|
* @param mixed $value |
107
|
|
|
* |
108
|
|
|
* @throws Exception |
109
|
|
|
*/ |
110
|
1 |
|
protected function valueDelta($name, $value) { |
111
|
1 |
|
$this->blockDelta($name); |
112
|
|
|
|
113
|
1 |
|
!isset($this->_deltas[$name]) ? $this->_deltas[$name] = 0 : false; |
114
|
1 |
|
!isset($this->_startValues[$name]) ? $this->_startValues[$name] = 0 : false; |
115
|
|
|
|
116
|
1 |
|
$value *= $this->_currentOperation === self::ACCESS_DELTA_DEC ? -1 : +1; |
117
|
|
|
|
118
|
1 |
|
$this->_deltas[$name] += $value; |
119
|
|
|
|
120
|
1 |
|
parent::__set($name, parent::__get($name) + $value); |
121
|
|
|
|
122
|
1 |
|
$this->_currentOperation = self::ACCESS_SET; |
123
|
1 |
|
} |
124
|
|
|
|
125
|
|
|
/** |
126
|
|
|
* Mark next set operation as delta increment |
127
|
|
|
* |
128
|
|
|
* @return $this |
129
|
|
|
*/ |
130
|
1 |
|
public function inc() { |
131
|
1 |
|
$this->_currentOperation = self::ACCESS_DELTA_INC; |
132
|
|
|
|
133
|
1 |
|
return $this; |
134
|
|
|
} |
135
|
|
|
|
136
|
|
|
/** |
137
|
|
|
* Mark next set operation as delta decrement |
138
|
|
|
* |
139
|
|
|
* @return $this |
140
|
|
|
*/ |
141
|
1 |
|
public function dec() { |
142
|
1 |
|
$this->_currentOperation = self::ACCESS_DELTA_DEC; |
143
|
|
|
|
144
|
1 |
|
return $this; |
145
|
|
|
} |
146
|
|
|
|
147
|
|
|
/** |
148
|
|
|
* Accepts changes |
149
|
|
|
* |
150
|
|
|
* Makes current values a start one and resets changes/deltas |
151
|
|
|
*/ |
152
|
1 |
|
public function commit() { |
153
|
1 |
|
$this->_startValues = $this->values; |
|
|
|
|
154
|
1 |
|
$this->_currentOperation = self::ACCESS_SET; |
155
|
1 |
|
$this->_changes = []; |
156
|
1 |
|
$this->_deltas = []; |
157
|
1 |
|
} |
158
|
|
|
|
159
|
|
|
/** |
160
|
|
|
* Rolls changes back |
161
|
|
|
*/ |
162
|
1 |
|
public function rollback() { |
163
|
1 |
|
$this->values = $this->_startValues; |
164
|
1 |
|
$this->_currentOperation = self::ACCESS_SET; |
165
|
1 |
|
$this->_changes = []; |
166
|
1 |
|
$this->_deltas = []; |
167
|
1 |
|
} |
168
|
|
|
|
169
|
|
|
/** |
170
|
|
|
* Is container was changed? |
171
|
|
|
* |
172
|
|
|
* @return bool |
173
|
|
|
*/ |
174
|
1 |
|
public function isChanged() { |
175
|
|
|
return |
176
|
1 |
|
! empty($this->_changes) |
177
|
1 |
|
|| |
178
|
1 |
|
! empty($this->_deltas); |
179
|
|
|
} |
180
|
|
|
|
181
|
1 |
|
public function getChanges() { |
182
|
1 |
|
return $this->_changes; |
183
|
|
|
} |
184
|
|
|
|
185
|
1 |
|
public function getDeltas() { |
186
|
1 |
|
return $this->_deltas; |
187
|
|
|
} |
188
|
|
|
|
189
|
|
|
} |
190
|
|
|
|
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountId
that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theid
property of an instance of theAccount
class. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.