Passed
Push — master ( efdb33...92d8b0 )
by Dawid
02:41
created

LazyCollection::next()   A

Complexity

Conditions 5
Paths 6

Size

Total Lines 13
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 5

Importance

Changes 0
Metric Value
cc 5
eloc 9
nc 6
nop 0
dl 0
loc 13
ccs 10
cts 10
cp 1
crap 5
rs 9.6111
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
3
namespace Igni\Storage\Mapping\Collection;
4
5
use ArrayIterator;
6
use Igni\Storage\Driver\Cursor;
7
use Igni\Storage\Exception\CollectionException;
8
9
/**
10
 * Lazy collection fetches items from cursor only if the item is requested and it is immutable.
11
 *
12
 * @package Igni\Storage\Mapping\Collection
13
 */
14
class LazyCollection implements \Igni\Storage\Mapping\Collection
15
{
16
    protected $cursor;
17
    protected $length;
18
    protected $current;
19
    protected $items = [];
20
    protected $pointer = 0;
21
    protected $complete = false;
22
23 15
    public function __construct(Cursor $cursor)
24
    {
25 15
        $this->cursor = $cursor;
26 15
    }
27
28
    public function contains($element): bool
29
    {
30
        foreach ($this as $element) {
0 ignored issues
show
introduced by
$element is overwriting one of the parameters of this function.
Loading history...
31
            if ($element === $element) {
32
                return true;
33
            }
34
        }
35
36
        return false;
37
    }
38
39 1
    public function first()
40
    {
41 1
        $this->pointer = 0;
42 1
        if ($this->pointer < $this->length) {
43 1
            return $this->current = $this->items[$this->pointer];
44
        }
45
46
        return $this->current();
47
    }
48
49 4
    public function last()
50
    {
51 4
        while ($this->valid()) {
52 4
            $this->current();
53 4
            $this->next();
54
        }
55
56 4
        return $this->current();
57
    }
58
59 3
    public function at(int $index)
60
    {
61 3
        if ($index < $this->length) {
62 3
            return $this->current = $this->items[$index];
63
        }
64
65 1
        if ($this->complete) {
66
            throw CollectionException::forOutOfBoundsIndex($index);
67
        }
68
69 1
        $savedPointer = $this->pointer;
70 1
        while ($this->pointer < $index) {
71 1
            if (!$this->valid()) {
72
                break;
73
            }
74 1
            $this->next();
75
        }
76 1
        $item = $this->current();
77
78 1
        if ($this->pointer < $index && $this->complete) {
79
            $offset = $this->pointer;
80
            $this->pointer = $savedPointer;
81
            throw CollectionException::forOutOfBoundsIndex($offset);
82
        }
83
84 1
        $this->pointer = $savedPointer;
85
86 1
        return $item;
87
    }
88
89 5
    public function current()
90
    {
91
        // Empty result-set or out of bounds.
92 5
        if ($this->cursor === null &&
93 5
            $this->current === null &&
94 5
            ($this->pointer > $this->length || ($this->length === null && $this->complete))
95
        ) {
96
            throw CollectionException::forOutOfBoundsIndex($this->pointer);
97
        }
98
99 5
        if (null === $this->current) {
100 5
            if ($this->pointer < $this->length) {
101
                $this->current = $this->items[$this->pointer];
102
            } else {
103 5
                $this->items[$this->pointer] = $this->current = $this->cursor->current();
104
            }
105
        }
106
107 5
        return $this->current;
108
    }
109
110 5
    public function next(): void
111
    {
112 5
        $this->pointer++;
113
114 5
        if ($this->pointer <= $this->length) {
115 1
            $this->current = $this->items[$this->pointer];
116 5
        } elseif ($this->cursor) {
117 5
            if ($this->pointer > $this->length) {
118 5
                $this->length = $this->pointer;
119
            }
120 5
            $this->cursor->next();
121 5
            if ($this->cursor->valid()) {
122 5
                $this->items[$this->pointer] = $this->current = $this->cursor->current();
123
            }
124
        }
125 5
    }
126
127
    public function previous(): void
128
    {
129
        if ($this->pointer > 0) {
130
            $this->pointer--;
131
        }
132
    }
133
134 1
    public function key()
135
    {
136 1
        if (!$this->current) {
137
            $this->current();
138
        }
139 1
        return $this->pointer;
140
    }
141
142 5
    public function valid(): bool
143
    {
144 5
        if ($this->pointer < $this->length) {
145 1
            return true;
146
        }
147
148 5
        if ($this->cursor) {
149 5
            $valid = $this->cursor->valid();
150
151 5
            if (!$valid) {
152 5
                $this->complete = true;
153
154 5
                $this->cursor->close();
155 5
                $this->cursor = null;
156
            }
157
158 5
            return $valid;
159
        }
160
161
        return false;
162
    }
163
164 1
    public function rewind(): void
165
    {
166 1
        $this->pointer = 0;
167 1
        $this->current = null;
168 1
    }
169
170 3
    public function count(): int
171
    {
172 3
        if ($this->complete) {
173 1
            return $this->length;
174
        }
175 2
        $this->last();
176
177 2
        return $this->length;
178
    }
179
180 1
    public function toArray(): array
181
    {
182 1
        if ($this->complete) {
183
            return $this->items;
184
        }
185 1
        $this->last();
186
187 1
        return $this->items;
188
    }
189
190
    public function toCollection(): Collection
191
    {
192
        $this->last();
193
194
        return new Collection(new ArrayIterator($this->items));
195
    }
196
}
197