ArrayManager::checkRegularize()   A
last analyzed

Complexity

Conditions 3
Paths 2

Size

Total Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
nc 2
nop 0
dl 0
loc 9
ccs 5
cts 5
cp 1
crap 3
rs 9.9666
c 0
b 0
f 0
1
<?php
2
/*
3
    Condorcet PHP - Election manager and results calculator.
4
    Designed for the Condorcet method. Integrating a large number of algorithms extending Condorcet. Expandable for all types of voting systems.
5
6
    By Julien Boudry and contributors - MIT LICENSE (Please read LICENSE.txt)
7
    https://github.com/julien-boudry/Condorcet
8
*/
9
declare(strict_types=1);
10
11
namespace CondorcetPHP\Condorcet\DataManager;
12
13
use CondorcetPHP\Condorcet\CondorcetVersion;
14
use CondorcetPHP\Condorcet\DataManager\DataHandlerDrivers\DataHandlerDriverInterface;
15
use CondorcetPHP\Condorcet\Throwable\CondorcetException;
16
17
abstract class ArrayManager implements \ArrayAccess, \Countable, \Iterator
18
{
19
    use CondorcetVersion;
20
21
        //////
22
23
    public static $CacheSize = 2000;
24
    public static $MaxContainerLength = 2000;
25
26
    protected $_Container = [];
27
    protected $_DataHandler = null;
28
    protected $_link = [];
29
30
    protected $_Cache = [];
31
    protected $_CacheMaxKey = 0;
32
    protected $_CacheMinKey = 0;
33
34
    protected $_cursor = null;
35
    protected $_counter = 0;
36
    protected $_maxKey = -1;
37
38
    public function __construct () {}
39
40
    public function __destruct ()
41
    {
42
        $this->regularize();
43
    }
44
45 1
    public function __clone ()
46
    {
47 1
        $this->_link = [];
48 1
    }
49
50 2
    public function __sleep () : array
51
    {
52 2
        $this->regularize();
53 2
        $this->clearCache();
54 2
        $this->rewind();
55
56 2
        return ['_Container','_DataHandler','_link'];
57
    }
58
59 2
    public function __wakeup ()
60
    {
61 2
        $this->resetMaxKey();
62 2
        $this->resetCounter();
63 2
    }
64
65
66
/////////// Implement ArrayAccess ///////////
67
68 131
    public function offsetSet($offset, $value) : void
69
    {
70 131
        if ($offset === null) :
71 131
            $this->_Container[++$this->_maxKey] = $value;
72 131
            ++$this->_counter;
73
        else :
74 1
            $state = $this->keyExist($offset);
75 1
            $this->_Container[$offset] = $value;
76
77 1
            if (!$state) :
78
                ++$this->_counter;
79
80
                if ($offset > $this->_maxKey) :
81
                    $this->_maxKey = $offset;
82
                endif;
83
84
                ksort($this->_Container,SORT_NUMERIC);
85 1
            elseif ($this->_DataHandler !== null) :
86 1
                $this->_DataHandler->deleteOneEntity($offset, true);
87
            endif;
88
89 1
            $this->clearCache();
90
        endif;
91
92 131
        $this->checkRegularize();
93 131
    }
94
95
    // Use by isset() function, must return false if offset value is null.
96
    public function offsetExists($offset) : bool
97
    {
98
        return ( isset($this->_Container[$offset]) || ($this->_DataHandler !== null && $this->_DataHandler->selectOneEntity($offset) !== false) ) ? true : false ;
99
    }
100
101 8
    public function offsetUnset($offset) : void
102
    {
103 8
        if ($this->keyExist($offset)) :
104 8
            if (array_key_exists($offset, $this->_Container)) :
105 8
                $this->preDeletedTask($this->_Container[$offset]);
106 8
                unset($this->_Container[$offset]);
107
            else :
108 1
                if (array_key_exists($offset, $this->_Cache)) :
109 1
                    $this->preDeletedTask($this->_Cache[$offset]);
110 1
                    unset($this->_Cache[$offset]);
111
                endif;
112
113 1
                $this->_DataHandler->deleteOneEntity($offset, false);
114
            endif;
115
116 8
            --$this->_counter;
117
        endif;
118 8
    }
119
120 104
    public function offsetGet($offset)
121
    {
122 104
        if (isset($this->_Container[$offset])) :
123 102
            return $this->_Container[$offset];
124 4
        elseif ($this->_DataHandler !== null) :
125 4
            if (array_key_exists($offset, $this->_Cache)) :
126 4
                return $this->_Cache[$offset];
127
            else :
128 4
                $oneEntity = $this->_DataHandler->selectOneEntity($offset);
129 4
                if ($oneEntity === false) :
130
                    return null;
131
                else : 
132 4
                    $this->_Cache[$offset] = $oneEntity;
133 4
                    return $oneEntity;
134
                endif;
135
            endif;
136
        else :
137
            return null;
138
        endif;
139
    }
140
141
142
/////////// Implement Iterator ///////////
143
144
    protected $valid = true;
145
146 103
    public function rewind() : void {
147 103
        $this->_cursor = null;
148 103
        $this->valid = true;
149
150 103
        reset($this->_Cache);
151 103
        reset($this->_Container);
152 103
    }
153
154 103
    public function current() {
155 103
        return $this->offsetGet($this->key());
156
    }
157
158 103
    public function key() : ?int
159
    {
160 103
        if ($this->_counter === 0) :
161
            return null;
162
        else :
163 103
            return $this->_cursor ?? $this->getFirstKey();
164
        endif;
165
    }
166
167 103
    public function next() : void
168
    {
169 103
        $oldCursor = $this->_cursor;
170
171 103
        if ($this->_cursor >= $this->_maxKey) :
172
            // Do nothing
173 87
        elseif (!$this->isUsingHandler()) :
174 84
            $this->setCursorOnNextKeyInArray($this->_Container);
175
        else :
176 4
            $this->populateCache();
177 4
            $this->setCursorOnNextKeyInArray($this->_Cache);
178
        endif;
179
180 103
        if ($this->_cursor === $oldCursor) :
181 102
            $this->valid = false;
182
        endif;
183 103
    }
184
185 87
        protected function setCursorOnNextKeyInArray (array &$array) : void
186
        {
187 87
            next($array);
188 87
            $arrayKey = key($array);
189
190 87
            if ($arrayKey > $this->key()) :
191 87
                $this->_cursor = $arrayKey;
192
            endif;
193 87
        }
194
195 103
    public function valid() : bool {
196 103
        return ($this->_counter !== 0) ? $this->valid : false;
197
    }
198
199
200
/////////// Implement Countable ///////////
201
202 16
    public function count () : int {
203 16
        return $this->_counter;
204
    }
205
206
/////////// Array Methods ///////////
207
208 14
    public function getFullDataSet () : array
209
    {
210 14
        if ($this->isUsingHandler()) :
211 1
            $this->regularize();
212 1
            $this->clearCache();
213
214 1
            return $this->_Cache = $this->_DataHandler->selectRangeEntitys(0,$this->_maxKey + 1);
215
        else :
216 13
            return $this->_Container;
217
        endif;
218
    }
219
220 9
    public function keyExist ($offset) : bool
221
    {
222 9
        if ( array_key_exists($offset, $this->_Container) || ($this->_DataHandler !== null && $this->_DataHandler->selectOneEntity($offset) !== false) ) :
223 9
            return true;
224
        else  :
225 1
            return false;
226
        endif;
227
    }
228
229 103
    public function getFirstKey () : int
230
    {
231 103
        $r = array_keys($this->_Container);
232
233 103
        if ($this->_DataHandler !== null) :
234 4
            $r[] = $this->_DataHandler->selectMinKey();
235
        endif;
236
237 103
        return (int) min($r);
238
    }
239
240 9
    public function getContainerSize () : int
241
    {
242 9
        return count($this->_Container);
243
    }
244
245 1
    public function getCacheSize () : int
246
    {
247 1
        return count($this->_Cache);
248
    }
249
250 1
    public function debugGetCache () : array
251
    {
252 1
        return $this->_Cache;
253
    }
254
255
256
/////////// HANDLER API ///////////
257
258
    abstract protected function preDeletedTask ($object) : void;
259
260 9
    public function regularize () : bool
261
    {
262 9
        if (!$this->isUsingHandler() || empty($this->_Container)) :
263 9
            return false;
264
        else :
265 6
            $this->_DataHandler->insertEntitys($this->_Container);
266 6
            $this->_Container = [];
267 6
            return true;
268
        endif;
269
    }
270
271 131
    public function checkRegularize () : bool
272
    {
273 131
        if ( $this->_DataHandler !== null && self::$MaxContainerLength <= $this->getContainerSize() ) :
274 4
            $this->regularize();
275 4
            return true;
276
        else :
277 131
            return false;
278
        endif;
279
    }
280
281 4
    protected function populateCache () : void
282
    {
283 4
        $this->regularize();
284
285 4
        $currentKey = $this->key();
286
287 4
        if ( empty($this->_Cache) || $currentKey >= $this->_CacheMaxKey || $currentKey < $this->_CacheMinKey ) :
288 4
            $this->clearCache();
289 4
            $this->_Cache = $this->_DataHandler->selectRangeEntitys($currentKey, self::$CacheSize);
290
291 4
            $keys = array_keys($this->_Cache);
292 4
            $this->_CacheMaxKey = max($keys);
293 4
            $this->_CacheMinKey = min($keys);
294
        endif;
295 4
    }
296
297 7
    public function clearCache () : void
298
    {
299 7
        foreach ($this->_Cache as $e) :
300 5
            $this->preDeletedTask($e);
301
        endforeach;
302
303 7
        $this->_Cache = [];
304 7
        $this->_CacheMaxKey = 0;
305 7
        $this->_CacheMinKey = 0;
306 7
    }
307
308 100
    public function isUsingHandler ()
309
    {
310 100
        return $this->_DataHandler !== null;
311
    }
312
313
/////////// HANDLER INTERRACTION ///////////
314
315 9
    public function resetCounter () : int
316
    {
317 9
        return $this->_counter = $this->getContainerSize() + ( $this->isUsingHandler() ? $this->_DataHandler->countEntitys() : 0 );
318
    }
319
320 9
    public function resetMaxKey () : ?int
321
    {
322 9
        $this->resetCounter();
323
324 9
        if ($this->count() < 1) :
325 7
            $this->_maxKey = -1;
326 7
            return null;
327
        else :
328 3
            $maxContainerKey = empty($this->_Container) ? null : max(array_keys($this->_Container));
329 3
            $maxHandlerKey = $this->_DataHandler !== null ? $this->_DataHandler->selectMaxKey() : null;
330
331 3
            return $this->_maxKey = max( $maxContainerKey,$maxHandlerKey );
332
        endif;
333
    }
334
335 7
    public function importHandler (DataHandlerDriverInterface $handler) : bool
336
    {
337 7
        if ($handler->countEntitys() === 0) :
338 7
            $this->_DataHandler = $handler;
339 7
            $this->_DataHandler->_dataContextObject = $this->getDataContextObject();
0 ignored issues
show
Bug introduced by
Accessing _dataContextObject on the interface CondorcetPHP\Condorcet\D...aHandlerDriverInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
340
341
            try {
342 7
                $this->regularize();
343
            } catch (\Exception $e) {
344
                $this->_DataHandler = null;
345
                $this->resetCounter();
346
                $this->resetMaxKey();
347
                throw $e;
348
            }
349
350 7
            $this->resetCounter();
351 7
            $this->resetMaxKey();
352
353 7
            return true;
354
        else :
355
            throw new CondorcetException;
356
        endif;
357
    }
358
359 1
    public function closeHandler () : void
360
    {
361 1
        if ($this->_DataHandler !== null) :
362 1
            $this->regularize();
363 1
            $this->clearCache();
364
365 1
            $this->_Container = $this->_DataHandler->selectRangeEntitys(0,$this->_maxKey + 1);
366
367 1
            $this->_DataHandler = null;
368
369 1
            $this->resetCounter();
370 1
            $this->resetMaxKey();
371
        endif;
372 1
    }
373
374
    abstract public function getDataContextObject () : DataContextInterface;
375
}
376