Passed
Branch dev-1.5.x (fb93e4)
by Boudry
04:14
created

anonymous//lib/DataManager/ArrayManager.php$0   A

Complexity

Total Complexity 2

Size/Duplication

Total Lines 9
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 2
dl 0
loc 9
ccs 0
cts 4
cp 0
rs 10
c 0
b 0
f 0
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
0 ignored issues
show
Coding Style introduced by
Expected 1 space before "Countable"; 0 found
Loading history...
Coding Style introduced by
Expected 1 space before "Iterator"; 0 found
Loading history...
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
    public function __destruct ()
42
    {
43
        $this->regularize();
44
    }
45
46
    public function __sleep () : array
47
    {
48
        $this->regularize();
49
        $this->clearCache();
50
        $this->rewind();
51
52
        return ['_Container','_DataHandler','_link'];
53
    }
54
55
    public function __wakeup ()
56
    {
57
        $this->resetMaxKey();
58
        $this->resetCounter();
59
    }
60
61
62
/////////// Implement ArrayAccess ///////////
63
64 4
    public function offsetSet($offset, $value) : void
65
    {
66 4
        if ($offset === null) :
67 4
            $this->_Container[++$this->_maxKey] = $value;
68 4
            ++$this->_counter;
69
        else :
70
            $state = !$this->keyExist($offset);
71
            $this->_Container[$offset] = $value;
72
73
            if ($state) :
74
                ++$this->_counter;
75
76
                if ($offset > $this->_maxKey) :
77
                    $this->_maxKey = $offset;
78
                endif;
79
80
                ksort($this->_Container,SORT_NUMERIC);
81
            elseif ($this->_DataHandler !== null) :
82
                $this->_DataHandler->deleteOneEntity($offset, true);
83
            endif;
84
85
            $this->clearCache();
86
        endif;
87
88 4
        $this->checkRegularize();
89 4
    }
90
91
    // Use by isset() function, must return false if offset value is null.
92
    public function offsetExists($offset) : bool
93
    {
94
        return ( isset($this->_Container[$offset]) || ($this->_DataHandler !== null && $this->_DataHandler->selectOneEntity($offset) !== false) ) ? true : false ;
95
    }
96
97 3
    public function offsetUnset($offset) : bool
98
    {
99 3
        if ($this->keyExist($offset)) :
100 3
            if (array_key_exists($offset, $this->_Container)) :
101 3
                unset($this->_Container[$offset]);
102
            else :
103
                unset($this->_Cache[$offset]);
104
105
                $this->_DataHandler->deleteOneEntity($offset, false);
106
            endif;
107
108 3
            --$this->_counter;
109 3
            return true;
0 ignored issues
show
Bug Best Practice introduced by
The expression return true returns the type true which is incompatible with the return type mandated by ArrayAccess::offsetUnset() of void.

In the issue above, the returned value is violating the contract defined by the mentioned interface.

Let's take a look at an example:

interface HasName {
    /** @return string */
    public function getName();
}

class Name {
    public $name;
}

class User implements HasName {
    /** @return string|Name */
    public function getName() {
        return new Name('foo'); // This is a violation of the ``HasName`` interface
                                // which only allows a string value to be returned.
    }
}
Loading history...
110
        else :
111
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the return type mandated by ArrayAccess::offsetUnset() of void.

In the issue above, the returned value is violating the contract defined by the mentioned interface.

Let's take a look at an example:

interface HasName {
    /** @return string */
    public function getName();
}

class Name {
    public $name;
}

class User implements HasName {
    /** @return string|Name */
    public function getName() {
        return new Name('foo'); // This is a violation of the ``HasName`` interface
                                // which only allows a string value to be returned.
    }
}
Loading history...
112
        endif;
113
    }
114
115 4
    public function offsetGet($offset)
116
    {
117 4
        if (isset($this->_Container[$offset])) :
118 4
            return $this->_Container[$offset];
119
        elseif ($this->_DataHandler !== null) :
120
            if (array_key_exists($offset, $this->_Cache)) :
121
                return $this->_Cache[$offset];
122
            else :
123
                $query = $this->_DataHandler->selectOneEntity($offset);
124
                return ($query === false) ? null : $query;
125
            endif;
126
        else :
127
            return null;
128
        endif;
129
    }
130
131
132
/////////// Implement Iterator ///////////
133
134
    protected $valid = true;
135
136 4
    public function rewind() : void {
137 4
        $this->_cursor = null;
138 4
        $this->valid = true;
139
140 4
        reset($this->_Cache);
141 4
        reset($this->_Container);
142 4
    }
143
144 4
    public function current() {
145 4
        return $this->offsetGet($this->key());
146
    }
147
148 4
    public function key() : ?int
149
    {
150 4
        if ($this->_counter === 0) :
151
            return null;
152
        else :
153 4
            return ($this->_cursor === null) ? $this->getFirstKey() : $this->_cursor;
154
        endif;
155
    }
156
157 4
    public function next() : void
158
    {
159 4
        $oldCursor = $this->_cursor;
160
161 4
        if ($this->_cursor >= $this->_maxKey) :
1 ignored issue
show
Unused Code introduced by
This if statement is empty and can be removed.

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 the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
162
            // Do nothing
163 4
        elseif (!$this->isUsingHandler()) :
164 4
            $this->setCursorOnNextKeyInArray($this->_Container);
165
        else :
166
            $this->populateCache();
167
            $this->setCursorOnNextKeyInArray($this->_Cache);
168
        endif;
169
170 4
        if ($this->_cursor === $oldCursor) :
171 4
            $this->valid = false;
172
        endif;
173 4
    }
174
175 4
        protected function setCursorOnNextKeyInArray (array &$array)
176
        {
177 4
            next($array);
178 4
            $arrayKey = key($array);
179
180 4
            if ($arrayKey > $this->key()) :
181 4
                return $this->_cursor = $arrayKey;
182
            endif;
183 1
        }
184
185 4
    public function valid() : bool {
186 4
        return $this->valid;
187
    }
188
189
190
/////////// Implement Countable ///////////
191
192 4
    public function count () : int {
193 4
        return $this->_counter;
194
    }
195
196
/////////// Array Methods ///////////
197
198 4
    public function getFullDataSet () : array
199
    {
200 4
        $this->regularize();
201
202 4
        return (!$this->isUsingHandler()) ? $this->_Container : $this->_DataHandler->selectRangeEntitys(0,$this->_maxKey + 1);
203
    }
204
205 3
    public function keyExist ($offset) : bool
206
    {
207 3
        if ( array_key_exists($offset, $this->_Container) || ($this->_DataHandler !== null && $this->_DataHandler->selectOneEntity($offset) !== false) ) :
208 3
            return true;
209
        else  :
210
            return false;
211
        endif;
212
    }
213
214 4
    public function getFirstKey () : int
215
    {
216 4
        $r = array_keys($this->_Container);
217
218 4
        if ($this->_DataHandler !== null) :
219
            $r[] = $this->_DataHandler->selectMinKey();
220
        endif;
221
222 4
        return (int) min($r);
223
    }
224
225
    public function getContainerSize () : int
226
    {
227
        return count($this->_Container);
228
    }
229
230
    public function getCacheSize () : int
231
    {
232
        return count($this->_Cache);
233
    }
234
235
    public function debugGetCache () : array
236
    {
237
        return $this->_Cache;
238
    }
239
240
241
/////////// HANDLER API ///////////
242
243 4
    public function regularize () : bool
244
    {
245 4
        if (!$this->isUsingHandler() || empty($this->_Container)) :
246 4
            return false;
247
        else :
248
            $this->_DataHandler->insertEntitys($this->_Container);
249
            $this->_Container = [];
250
            return true;
251
        endif;
252
    }
253
254 4
    public function checkRegularize () : bool
255
    {
256 4
        if ( $this->_DataHandler !== null && self::$MaxContainerLength <= $this->getContainerSize() ) :
257
            $this->regularize();
258
            return true;
259
        else :
260 4
            return false;
261
        endif;
262
    }
263
264
    protected function populateCache () : void
265
    {
266
        $this->regularize();
267
268
        $currentKey = $this->key();
269
270
        if ( empty($this->_Cache) || $currentKey >= $this->_CacheMaxKey || $currentKey < $this->_CacheMinKey ) :
271
            $this->_Cache = $this->_DataHandler->selectRangeEntitys($currentKey, self::$CacheSize);
272
273
            $keys = array_keys($this->_Cache);
274
            $this->_CacheMaxKey = max($keys);
275
            $this->_CacheMinKey = min($keys);
276
        endif;
277
    }
278
279
    public function clearCache () : void
280
    {
281
        $this->_Cache = [];
282
        $this->_CacheMaxKey = 0;
283
        $this->_CacheMinKey = 0;
284
    }
285
286 4
    public function isUsingHandler ()
287
    {
288 4
        return $this->_DataHandler !== null;
289
    }
290
291
/////////// HANDLER INTERRACTION ///////////
292
293
    public function resetCounter () : int
294
    {
295
        return $this->_counter = $this->getContainerSize() + ( ($this->isUsingHandler()) ? $this->_DataHandler->countEntitys() : 0 );
296
    }
297
298
    public function resetMaxKey () : ?int
299
    {
300
        $this->resetCounter();
301
302
        if ($this->count() < 1) :
303
            $this->_maxKey = -1;
304
            return null;
305
        else :
306
            $maxContainerKey = (empty($this->_Container)) ? null : max(array_keys($this->_Container));
307
            $maxHandlerKey = ($this->_DataHandler !== null) ? $this->_DataHandler->selectMaxKey() : null;
308
309
            return $this->_maxKey = max( $maxContainerKey,$maxHandlerKey );
310
        endif;
311
    }
312
313
    public function importHandler (DataHandlerDriverInterface $handler) : bool
314
    {
315
        if ($handler->countEntitys() === 0) :
316
            $this->_DataHandler = $handler;
317
            $this->_DataHandler->_dataContextObject = $this->getDataContextObject();
1 ignored issue
show
Bug introduced by
Accessing _dataContextObject on the interface Condorcet\DataManager\Da...aHandlerDriverInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
318
319
            try {
320
                $this->regularize();
321
            } catch (\Exception $e) {
322
                $this->_DataHandler = null;
323
                $this->resetCounter();
324
                $this->resetMaxKey();
325
                throw $e;
326
            }
327
328
            $this->resetCounter();
329
            $this->resetMaxKey();
330
331
            return true;
332
        else :
333
            throw new CondorcetException;
334
        endif;
335
    }
336
337
    public function closeHandler () : void
338
    {
339
        if ($this->_DataHandler !== null) :
340
            $this->regularize();
341
            $this->clearCache();
342
343
            $this->_Container = $this->_DataHandler->selectRangeEntitys(0,$this->_maxKey + 1);
344
345
            $this->_DataHandler = null;
346
347
            $this->resetCounter();
348
            $this->resetMaxKey();
349
        endif;
350
    }
351
352
    public function getDataContextObject ()
353
    {
354
        return new Class implements DataContextInterface {
355
            public function dataCallBack ($data)
356
            {
357
                return $data;
358
            }
359
360
            public function dataPrepareStoringAndFormat ($data)
361
            {
362
                return $data;
363
            }
364
        };
365
    }
366
}
367