Completed
Push — dev-1.6.x ( f43552...3412fc )
by Boudry
16:50
created

ArrayManager::offsetGet()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 20
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 5.1158

Importance

Changes 0
Metric Value
dl 0
loc 20
ccs 10
cts 12
cp 0.8333
rs 8.8571
c 0
b 0
f 0
cc 5
eloc 18
nc 5
nop 1
crap 5.1158
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 101
    public function offsetSet($offset, $value) : void
70
    {
71 101
        if ($offset === null) :
72 101
            $this->_Container[++$this->_maxKey] = $value;
73 101
            ++$this->_counter;
74
        else :
75 1
            $state = $this->keyExist($offset);
76 1
            $this->_Container[$offset] = $value;
77
78 1
            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 1
            elseif ($this->_DataHandler !== null) :
87 1
                $this->_DataHandler->deleteOneEntity($offset, true);
88
            endif;
89
90 1
            $this->clearCache();
91
        endif;
92
93 101
        $this->checkRegularize();
94 101
    }
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) : void
103
    {
104 7
        if ($this->keyExist($offset)) :
105 7
            if (array_key_exists($offset, $this->_Container)) :
106 7
                $this->preDeletedTask($this->_Container[$offset]);
107 7
                unset($this->_Container[$offset]);
108
            else :
109 1
                if (array_key_exists($offset, $this->_Cache)) :
110 1
                    $this->preDeletedTask($this->_Cache[$offset]);
111 1
                    unset($this->_Cache[$offset]);
112
                endif;
113
114 1
                $this->_DataHandler->deleteOneEntity($offset, false);
115
            endif;
116
117 7
            --$this->_counter;
118
        endif;
119 7
    }
120
121 84
    public function offsetGet($offset)
122
    {
123 84
        if (isset($this->_Container[$offset])) :
124 83
            return $this->_Container[$offset];
125 3
        elseif ($this->_DataHandler !== null) :
126 3
            if (array_key_exists($offset, $this->_Cache)) :
127 3
                return $this->_Cache[$offset];
128
            else :
129 3
                $oneEntity = $this->_DataHandler->selectOneEntity($offset);
130 3
                if ($oneEntity === false) :
131
                    return null;
132
                else : 
133 3
                    $this->_Cache[$offset] = $oneEntity;
134 3
                    return $oneEntity;
135
                endif;
136
            endif;
137
        else :
138
            return null;
139
        endif;
140
    }
141
142
143
/////////// Implement Iterator ///////////
144
145
    protected $valid = true;
146
147 83
    public function rewind() : void {
148 83
        $this->_cursor = null;
149 83
        $this->valid = true;
150
151 83
        reset($this->_Cache);
152 83
        reset($this->_Container);
153 83
    }
154
155 83
    public function current() {
156 83
        return $this->offsetGet($this->key());
157
    }
158
159 83
    public function key() : ?int
160
    {
161 83
        if ($this->_counter === 0) :
162
            return null;
163
        else :
164 83
            return ($this->_cursor === null) ? $this->getFirstKey() : $this->_cursor;
165
        endif;
166
    }
167
168 83
    public function next() : void
169
    {
170 83
        $oldCursor = $this->_cursor;
171
172 83
        if ($this->_cursor >= $this->_maxKey) :
173
            // Do nothing
174 71
        elseif (!$this->isUsingHandler()) :
175 69
            $this->setCursorOnNextKeyInArray($this->_Container);
176
        else :
177 3
            $this->populateCache();
178 3
            $this->setCursorOnNextKeyInArray($this->_Cache);
179
        endif;
180
181 83
        if ($this->_cursor === $oldCursor) :
182 83
            $this->valid = false;
183
        endif;
184 83
    }
185
186 71
        protected function setCursorOnNextKeyInArray (array &$array)
187
        {
188 71
            next($array);
189 71
            $arrayKey = key($array);
190
191 71
            if ($arrayKey > $this->key()) :
192 71
                return $this->_cursor = $arrayKey;
193
            endif;
194 2
        }
195
196 83
    public function valid() : bool {
197 83
        return ($this->_counter !== 0) ? $this->valid : false;
198
    }
199
200
201
/////////// Implement Countable ///////////
202
203 11
    public function count () : int {
204 11
        return $this->_counter;
205
    }
206
207
/////////// Array Methods ///////////
208
209 16
    public function getFullDataSet () : array
210
    {
211 16
        if ($this->isUsingHandler()) :
212 3
            $this->regularize();
213 3
            $this->clearCache();
214
215 3
            return $this->_Cache = $this->_DataHandler->selectRangeEntitys(0,$this->_maxKey + 1);
216
        else :
217 14
            return $this->_Container;
218
        endif;
219
    }
220
221 8
    public function keyExist ($offset) : bool
222
    {
223 8
        if ( array_key_exists($offset, $this->_Container) || ($this->_DataHandler !== null && $this->_DataHandler->selectOneEntity($offset) !== false) ) :
224 8
            return true;
225
        else  :
226 1
            return false;
227
        endif;
228
    }
229
230 83
    public function getFirstKey () : int
231
    {
232 83
        $r = array_keys($this->_Container);
233
234 83
        if ($this->_DataHandler !== null) :
235 3
            $r[] = $this->_DataHandler->selectMinKey();
236
        endif;
237
238 83
        return (int) min($r);
239
    }
240
241 5
    public function getContainerSize () : int
242
    {
243 5
        return count($this->_Container);
244
    }
245
246 1
    public function getCacheSize () : int
247
    {
248 1
        return count($this->_Cache);
249
    }
250
251 1
    public function debugGetCache () : array
252
    {
253 1
        return $this->_Cache;
254
    }
255
256
257
/////////// HANDLER API ///////////
258
259
    abstract protected function preDeletedTask ($object) : void;
260
261 6
    public function regularize () : bool
262
    {
263 6
        if (!$this->isUsingHandler() || empty($this->_Container)) :
264 6
            return false;
265
        else :
266 4
            $this->_DataHandler->insertEntitys($this->_Container);
267 4
            $this->_Container = [];
268 4
            return true;
269
        endif;
270
    }
271
272 101
    public function checkRegularize () : bool
273
    {
274 101
        if ( $this->_DataHandler !== null && self::$MaxContainerLength <= $this->getContainerSize() ) :
275 2
            $this->regularize();
276 2
            return true;
277
        else :
278 101
            return false;
279
        endif;
280
    }
281
282 3
    protected function populateCache () : void
283
    {
284 3
        $this->regularize();
285
286 3
        $currentKey = $this->key();
287
288 3
        if ( empty($this->_Cache) || $currentKey >= $this->_CacheMaxKey || $currentKey < $this->_CacheMinKey ) :
289 3
            $this->clearCache();
290 3
            $this->_Cache = $this->_DataHandler->selectRangeEntitys($currentKey, self::$CacheSize);
291
292 3
            $keys = array_keys($this->_Cache);
293 3
            $this->_CacheMaxKey = max($keys);
294 3
            $this->_CacheMinKey = min($keys);
295
        endif;
296 3
    }
297
298 6
    public function clearCache () : void
299
    {
300 6
        foreach ($this->_Cache as $e) :
301 4
            $this->preDeletedTask($e);
302
        endforeach;
303
304 6
        $this->_Cache = [];
305 6
        $this->_CacheMaxKey = 0;
306 6
        $this->_CacheMinKey = 0;
307 6
    }
308
309 81
    public function isUsingHandler ()
310
    {
311 81
        return $this->_DataHandler !== null;
312
    }
313
314
/////////// HANDLER INTERRACTION ///////////
315
316 5
    public function resetCounter () : int
317
    {
318 5
        return $this->_counter = $this->getContainerSize() + ( ($this->isUsingHandler()) ? $this->_DataHandler->countEntitys() : 0 );
319
    }
320
321 5
    public function resetMaxKey () : ?int
322
    {
323 5
        $this->resetCounter();
324
325 5
        if ($this->count() < 1) :
326 4
            $this->_maxKey = -1;
327 4
            return null;
328
        else :
329 2
            $maxContainerKey = (empty($this->_Container)) ? null : max(array_keys($this->_Container));
330 2
            $maxHandlerKey = ($this->_DataHandler !== null) ? $this->_DataHandler->selectMaxKey() : null;
331
332 2
            return $this->_maxKey = max( $maxContainerKey,$maxHandlerKey );
333
        endif;
334
    }
335
336 4
    public function importHandler (DataHandlerDriverInterface $handler) : bool
337
    {
338 4
        if ($handler->countEntitys() === 0) :
339 4
            $this->_DataHandler = $handler;
340 4
            $this->_DataHandler->_dataContextObject = $this->getDataContextObject();
341
342
            try {
343 4
                $this->regularize();
344
            } catch (\Exception $e) {
345
                $this->_DataHandler = null;
346
                $this->resetCounter();
347
                $this->resetMaxKey();
348
                throw $e;
349
            }
350
351 4
            $this->resetCounter();
352 4
            $this->resetMaxKey();
353
354 4
            return true;
355
        else :
356
            throw new CondorcetException;
357
        endif;
358
    }
359
360 1
    public function closeHandler () : void
361
    {
362 1
        if ($this->_DataHandler !== null) :
363 1
            $this->regularize();
364 1
            $this->clearCache();
365
366 1
            $this->_Container = $this->_DataHandler->selectRangeEntitys(0,$this->_maxKey + 1);
367
368 1
            $this->_DataHandler = null;
369
370 1
            $this->resetCounter();
371 1
            $this->resetMaxKey();
372
        endif;
373 1
    }
374
375
    abstract public function getDataContextObject () : DataContextInterface;
376
}
377