1
|
|
|
<?php |
2
|
|
|
/* |
3
|
|
|
Condorcet PHP Class, with Schulze Methods and others ! |
4
|
|
|
|
5
|
|
|
By Julien Boudry - MIT LICENSE (Please read LICENSE.txt) |
6
|
|
|
https://github.com/julien-boudry/Condorcet |
7
|
|
|
*/ |
8
|
|
|
declare(strict_types=1); |
9
|
|
|
|
10
|
|
|
|
11
|
|
|
namespace Condorcet\DataManager; |
12
|
|
|
|
13
|
|
|
use Condorcet\DataManager\DataContextInterface; |
14
|
|
|
use Condorcet\DataManager\DataHandlerDrivers\DataHandlerDriverInterface; |
15
|
|
|
use Condorcet\CondorcetException; |
16
|
|
|
use Condorcet\CondorcetVersion; |
17
|
|
|
|
18
|
|
|
abstract class ArrayManager implements \ArrayAccess, \Countable, \Iterator |
19
|
|
|
{ |
20
|
|
|
use CondorcetVersion; |
21
|
|
|
|
22
|
|
|
////// |
23
|
|
|
|
24
|
|
|
public static $CacheSize = 2000; |
25
|
|
|
public static $MaxContainerLength = 2000; |
26
|
|
|
|
27
|
|
|
protected $_Container = []; |
28
|
|
|
protected $_DataHandler = null; |
29
|
|
|
protected $_link = []; |
30
|
|
|
|
31
|
|
|
protected $_Cache = []; |
32
|
|
|
protected $_CacheMaxKey = 0; |
33
|
|
|
protected $_CacheMinKey = 0; |
34
|
|
|
|
35
|
|
|
protected $_cursor = null; |
36
|
|
|
protected $_counter = 0; |
37
|
|
|
protected $_maxKey = -1; |
38
|
|
|
|
39
|
|
|
public function __construct () {} |
40
|
|
|
|
41
|
1 |
|
public function __destruct () |
42
|
|
|
{ |
43
|
1 |
|
$this->regularize(); |
44
|
1 |
|
} |
45
|
|
|
|
46
|
1 |
|
public function __clone () |
47
|
|
|
{ |
48
|
1 |
|
$this->_link = []; |
49
|
1 |
|
} |
50
|
|
|
|
51
|
2 |
|
public function __sleep () : array |
52
|
|
|
{ |
53
|
2 |
|
$this->regularize(); |
54
|
2 |
|
$this->clearCache(); |
55
|
2 |
|
$this->rewind(); |
56
|
|
|
|
57
|
2 |
|
return ['_Container','_DataHandler','_link']; |
58
|
|
|
} |
59
|
|
|
|
60
|
1 |
|
public function __wakeup () |
61
|
|
|
{ |
62
|
1 |
|
$this->resetMaxKey(); |
63
|
1 |
|
$this->resetCounter(); |
64
|
1 |
|
} |
65
|
|
|
|
66
|
|
|
|
67
|
|
|
/////////// Implement ArrayAccess /////////// |
68
|
|
|
|
69
|
100 |
|
public function offsetSet($offset, $value) : void |
70
|
|
|
{ |
71
|
100 |
|
if ($offset === null) : |
72
|
100 |
|
$this->_Container[++$this->_maxKey] = $value; |
73
|
100 |
|
++$this->_counter; |
74
|
|
|
else : |
75
|
|
|
$state = !$this->keyExist($offset); |
76
|
|
|
$this->_Container[$offset] = $value; |
77
|
|
|
|
78
|
|
|
if ($state) : |
79
|
|
|
++$this->_counter; |
80
|
|
|
|
81
|
|
|
if ($offset > $this->_maxKey) : |
82
|
|
|
$this->_maxKey = $offset; |
83
|
|
|
endif; |
84
|
|
|
|
85
|
|
|
ksort($this->_Container,SORT_NUMERIC); |
86
|
|
|
elseif ($this->_DataHandler !== null) : |
87
|
|
|
$this->_DataHandler->deleteOneEntity($offset, true); |
88
|
|
|
endif; |
89
|
|
|
|
90
|
|
|
$this->clearCache(); |
91
|
|
|
endif; |
92
|
|
|
|
93
|
100 |
|
$this->checkRegularize(); |
94
|
100 |
|
} |
95
|
|
|
|
96
|
|
|
// Use by isset() function, must return false if offset value is null. |
97
|
|
|
public function offsetExists($offset) : bool |
98
|
|
|
{ |
99
|
|
|
return ( isset($this->_Container[$offset]) || ($this->_DataHandler !== null && $this->_DataHandler->selectOneEntity($offset) !== false) ) ? true : false ; |
100
|
|
|
} |
101
|
|
|
|
102
|
7 |
|
public function offsetUnset($offset) : bool |
103
|
|
|
{ |
104
|
7 |
|
if ($this->keyExist($offset)) : |
105
|
7 |
|
if (array_key_exists($offset, $this->_Container)) : |
106
|
7 |
|
unset($this->_Container[$offset]); |
107
|
|
|
else : |
108
|
1 |
|
unset($this->_Cache[$offset]); |
109
|
|
|
|
110
|
1 |
|
$this->_DataHandler->deleteOneEntity($offset, false); |
111
|
|
|
endif; |
112
|
|
|
|
113
|
7 |
|
--$this->_counter; |
114
|
7 |
|
return true; |
115
|
|
|
else : |
116
|
1 |
|
return false; |
117
|
|
|
endif; |
118
|
|
|
} |
119
|
|
|
|
120
|
83 |
|
public function offsetGet($offset) |
121
|
|
|
{ |
122
|
83 |
|
if (isset($this->_Container[$offset])) : |
123
|
83 |
|
return $this->_Container[$offset]; |
124
|
2 |
|
elseif ($this->_DataHandler !== null) : |
125
|
2 |
|
if (array_key_exists($offset, $this->_Cache)) : |
126
|
2 |
|
return $this->_Cache[$offset]; |
127
|
|
|
else : |
128
|
2 |
|
$query = $this->_DataHandler->selectOneEntity($offset); |
129
|
2 |
|
return ($query === false) ? null : $query; |
130
|
|
|
endif; |
131
|
|
|
else : |
132
|
|
|
return null; |
133
|
|
|
endif; |
134
|
|
|
} |
135
|
|
|
|
136
|
|
|
|
137
|
|
|
/////////// Implement Iterator /////////// |
138
|
|
|
|
139
|
|
|
protected $valid = true; |
140
|
|
|
|
141
|
82 |
|
public function rewind() : void { |
142
|
82 |
|
$this->_cursor = null; |
143
|
82 |
|
$this->valid = true; |
144
|
|
|
|
145
|
82 |
|
reset($this->_Cache); |
146
|
82 |
|
reset($this->_Container); |
147
|
82 |
|
} |
148
|
|
|
|
149
|
82 |
|
public function current() { |
150
|
82 |
|
return $this->offsetGet($this->key()); |
151
|
|
|
} |
152
|
|
|
|
153
|
82 |
|
public function key() : ?int |
154
|
|
|
{ |
155
|
82 |
|
if ($this->_counter === 0) : |
156
|
|
|
return null; |
157
|
|
|
else : |
158
|
82 |
|
return ($this->_cursor === null) ? $this->getFirstKey() : $this->_cursor; |
159
|
|
|
endif; |
160
|
|
|
} |
161
|
|
|
|
162
|
82 |
|
public function next() : void |
163
|
|
|
{ |
164
|
82 |
|
$oldCursor = $this->_cursor; |
165
|
|
|
|
166
|
82 |
|
if ($this->_cursor >= $this->_maxKey) : |
|
|
|
|
167
|
|
|
// Do nothing |
168
|
70 |
|
elseif (!$this->isUsingHandler()) : |
169
|
69 |
|
$this->setCursorOnNextKeyInArray($this->_Container); |
170
|
|
|
else : |
171
|
2 |
|
$this->populateCache(); |
172
|
2 |
|
$this->setCursorOnNextKeyInArray($this->_Cache); |
173
|
|
|
endif; |
174
|
|
|
|
175
|
82 |
|
if ($this->_cursor === $oldCursor) : |
176
|
82 |
|
$this->valid = false; |
177
|
|
|
endif; |
178
|
82 |
|
} |
179
|
|
|
|
180
|
70 |
|
protected function setCursorOnNextKeyInArray (array &$array) |
181
|
|
|
{ |
182
|
70 |
|
next($array); |
183
|
70 |
|
$arrayKey = key($array); |
184
|
|
|
|
185
|
70 |
|
if ($arrayKey > $this->key()) : |
186
|
70 |
|
return $this->_cursor = $arrayKey; |
187
|
|
|
endif; |
188
|
2 |
|
} |
189
|
|
|
|
190
|
82 |
|
public function valid() : bool { |
191
|
82 |
|
return $this->valid; |
192
|
|
|
} |
193
|
|
|
|
194
|
|
|
|
195
|
|
|
/////////// Implement Countable /////////// |
196
|
|
|
|
197
|
10 |
|
public function count () : int { |
198
|
10 |
|
return $this->_counter; |
199
|
|
|
} |
200
|
|
|
|
201
|
|
|
/////////// Array Methods /////////// |
202
|
|
|
|
203
|
15 |
|
public function getFullDataSet () : array |
204
|
|
|
{ |
205
|
15 |
|
$this->regularize(); |
206
|
|
|
|
207
|
15 |
|
return (!$this->isUsingHandler()) ? $this->_Container : $this->_DataHandler->selectRangeEntitys(0,$this->_maxKey + 1); |
208
|
|
|
} |
209
|
|
|
|
210
|
7 |
|
public function keyExist ($offset) : bool |
211
|
|
|
{ |
212
|
7 |
|
if ( array_key_exists($offset, $this->_Container) || ($this->_DataHandler !== null && $this->_DataHandler->selectOneEntity($offset) !== false) ) : |
213
|
7 |
|
return true; |
214
|
|
|
else : |
215
|
1 |
|
return false; |
216
|
|
|
endif; |
217
|
|
|
} |
218
|
|
|
|
219
|
82 |
|
public function getFirstKey () : int |
220
|
|
|
{ |
221
|
82 |
|
$r = array_keys($this->_Container); |
222
|
|
|
|
223
|
82 |
|
if ($this->_DataHandler !== null) : |
224
|
2 |
|
$r[] = $this->_DataHandler->selectMinKey(); |
225
|
|
|
endif; |
226
|
|
|
|
227
|
82 |
|
return (int) min($r); |
228
|
|
|
} |
229
|
|
|
|
230
|
4 |
|
public function getContainerSize () : int |
231
|
|
|
{ |
232
|
4 |
|
return count($this->_Container); |
233
|
|
|
} |
234
|
|
|
|
235
|
1 |
|
public function getCacheSize () : int |
236
|
|
|
{ |
237
|
1 |
|
return count($this->_Cache); |
238
|
|
|
} |
239
|
|
|
|
240
|
1 |
|
public function debugGetCache () : array |
241
|
|
|
{ |
242
|
1 |
|
return $this->_Cache; |
243
|
|
|
} |
244
|
|
|
|
245
|
|
|
|
246
|
|
|
/////////// HANDLER API /////////// |
247
|
|
|
|
248
|
17 |
|
public function regularize () : bool |
249
|
|
|
{ |
250
|
17 |
|
if (!$this->isUsingHandler() || empty($this->_Container)) : |
251
|
17 |
|
return false; |
252
|
|
|
else : |
253
|
3 |
|
$this->_DataHandler->insertEntitys($this->_Container); |
254
|
3 |
|
$this->_Container = []; |
255
|
3 |
|
return true; |
256
|
|
|
endif; |
257
|
|
|
} |
258
|
|
|
|
259
|
100 |
|
public function checkRegularize () : bool |
260
|
|
|
{ |
261
|
100 |
|
if ( $this->_DataHandler !== null && self::$MaxContainerLength <= $this->getContainerSize() ) : |
262
|
1 |
|
$this->regularize(); |
263
|
1 |
|
return true; |
264
|
|
|
else : |
265
|
100 |
|
return false; |
266
|
|
|
endif; |
267
|
|
|
} |
268
|
|
|
|
269
|
2 |
|
protected function populateCache () : void |
270
|
|
|
{ |
271
|
2 |
|
$this->regularize(); |
272
|
|
|
|
273
|
2 |
|
$currentKey = $this->key(); |
274
|
|
|
|
275
|
2 |
|
if ( empty($this->_Cache) || $currentKey >= $this->_CacheMaxKey || $currentKey < $this->_CacheMinKey ) : |
276
|
2 |
|
$this->_Cache = $this->_DataHandler->selectRangeEntitys($currentKey, self::$CacheSize); |
277
|
|
|
|
278
|
2 |
|
$keys = array_keys($this->_Cache); |
279
|
2 |
|
$this->_CacheMaxKey = max($keys); |
280
|
2 |
|
$this->_CacheMinKey = min($keys); |
281
|
|
|
endif; |
282
|
2 |
|
} |
283
|
|
|
|
284
|
3 |
|
public function clearCache () : void |
285
|
|
|
{ |
286
|
3 |
|
$this->_Cache = []; |
287
|
3 |
|
$this->_CacheMaxKey = 0; |
288
|
3 |
|
$this->_CacheMinKey = 0; |
289
|
3 |
|
} |
290
|
|
|
|
291
|
77 |
|
public function isUsingHandler () |
292
|
|
|
{ |
293
|
77 |
|
return $this->_DataHandler !== null; |
294
|
|
|
} |
295
|
|
|
|
296
|
|
|
/////////// HANDLER INTERRACTION /////////// |
297
|
|
|
|
298
|
4 |
|
public function resetCounter () : int |
299
|
|
|
{ |
300
|
4 |
|
return $this->_counter = $this->getContainerSize() + ( ($this->isUsingHandler()) ? $this->_DataHandler->countEntitys() : 0 ); |
301
|
|
|
} |
302
|
|
|
|
303
|
4 |
|
public function resetMaxKey () : ?int |
304
|
|
|
{ |
305
|
4 |
|
$this->resetCounter(); |
306
|
|
|
|
307
|
4 |
|
if ($this->count() < 1) : |
308
|
3 |
|
$this->_maxKey = -1; |
309
|
3 |
|
return null; |
310
|
|
|
else : |
311
|
2 |
|
$maxContainerKey = (empty($this->_Container)) ? null : max(array_keys($this->_Container)); |
312
|
2 |
|
$maxHandlerKey = ($this->_DataHandler !== null) ? $this->_DataHandler->selectMaxKey() : null; |
313
|
|
|
|
314
|
2 |
|
return $this->_maxKey = max( $maxContainerKey,$maxHandlerKey ); |
315
|
|
|
endif; |
316
|
|
|
} |
317
|
|
|
|
318
|
3 |
|
public function importHandler (DataHandlerDriverInterface $handler) : bool |
319
|
|
|
{ |
320
|
3 |
|
if ($handler->countEntitys() === 0) : |
321
|
3 |
|
$this->_DataHandler = $handler; |
322
|
3 |
|
$this->_DataHandler->_dataContextObject = $this->getDataContextObject(); |
323
|
|
|
|
324
|
|
|
try { |
325
|
3 |
|
$this->regularize(); |
326
|
|
|
} catch (\Exception $e) { |
327
|
|
|
$this->_DataHandler = null; |
328
|
|
|
$this->resetCounter(); |
329
|
|
|
$this->resetMaxKey(); |
330
|
|
|
throw $e; |
331
|
|
|
} |
332
|
|
|
|
333
|
3 |
|
$this->resetCounter(); |
334
|
3 |
|
$this->resetMaxKey(); |
335
|
|
|
|
336
|
3 |
|
return true; |
337
|
|
|
else : |
338
|
|
|
throw new CondorcetException; |
339
|
|
|
endif; |
340
|
|
|
} |
341
|
|
|
|
342
|
1 |
|
public function closeHandler () : void |
343
|
|
|
{ |
344
|
1 |
|
if ($this->_DataHandler !== null) : |
345
|
1 |
|
$this->regularize(); |
346
|
1 |
|
$this->clearCache(); |
347
|
|
|
|
348
|
1 |
|
$this->_Container = $this->_DataHandler->selectRangeEntitys(0,$this->_maxKey + 1); |
349
|
|
|
|
350
|
1 |
|
$this->_DataHandler = null; |
351
|
|
|
|
352
|
1 |
|
$this->resetCounter(); |
353
|
1 |
|
$this->resetMaxKey(); |
354
|
|
|
endif; |
355
|
1 |
|
} |
356
|
|
|
|
357
|
|
|
public function getDataContextObject () : DataContextInterface |
358
|
|
|
{ |
359
|
|
|
return new Class implements DataContextInterface { |
360
|
|
|
public function dataCallBack ($data) |
361
|
|
|
{ |
362
|
|
|
return $data; |
363
|
|
|
} |
364
|
|
|
|
365
|
|
|
public function dataPrepareStoringAndFormat ($data) |
366
|
|
|
{ |
367
|
|
|
return $data; |
368
|
|
|
} |
369
|
|
|
}; |
370
|
|
|
} |
371
|
|
|
} |
372
|
|
|
|
This check looks for the bodies of
if
statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.These
if
bodies can be removed. If you have an empty if but statements in theelse
branch, consider inverting the condition.could be turned into
This is much more concise to read.