Completed
Push — master ( 78f1d5...da548b )
by Dawid
04:18
created

LazyCollection::count()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 0
dl 0
loc 8
ccs 5
cts 5
cp 1
crap 2
rs 10
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
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
        $item = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $item is dead and can be removed.
Loading history...
62 3
        if ($index < $this->length) {
63 3
            return $this->current = $this->items[$index];
64
        }
65
66 1
        if ($this->complete) {
67
            throw CollectionException::forOutOfBoundsIndex($index);
68
        }
69
70 1
        $savedPointer = $this->pointer;
71 1
        while ($this->pointer < $index) {
72 1
            if (!$this->valid()) {
73
                break;
74
            }
75 1
            $this->next();
76
        }
77 1
        $item = $this->current();
78
79 1
        if ($this->pointer < $index && $this->complete) {
80
            $offset = $this->pointer;
81
            $this->pointer = $savedPointer;
82
            throw CollectionException::forOutOfBoundsIndex($offset);
83
        }
84
85 1
        $this->pointer = $savedPointer;
86
87 1
        return $item;
88
    }
89
90 5
    public function current()
91
    {
92
        // Empty result-set or out of bounds.
93 5
        if ($this->cursor === null &&
94 5
            $this->current === null &&
95 5
            ($this->pointer > $this->length || ($this->length === null && $this->complete))
96
        ) {
97
            throw CollectionException::forOutOfBoundsIndex($this->pointer);
98
        }
99
100 5
        if (null === $this->current) {
101 5
            if ($this->pointer < $this->length) {
102
                $this->current = $this->items[$this->pointer];
103
            } else {
104 5
                $this->items[$this->pointer] = $this->current = $this->cursor->current();
105
            }
106
        }
107
108 5
        return $this->current;
109
    }
110
111 5
    public function next(): void
112
    {
113 5
        $this->pointer++;
114
115 5
        if ($this->pointer <= $this->length) {
116 1
            $this->current = $this->items[$this->pointer];
117 5
        } elseif ($this->cursor) {
118 5
            if ($this->pointer > $this->length) {
119 5
                $this->length = $this->pointer;
120
            }
121 5
            $this->cursor->next();
122 5
            if ($this->cursor->valid()) {
123 5
                $this->items[$this->pointer] = $this->current = $this->cursor->current();
124
            }
125
        }
126 5
    }
127
128
    public function previous(): void
129
    {
130
        if ($this->pointer > 0) {
131
            $this->pointer--;
132
        }
133
    }
134
135 2
    public function key()
136
    {
137 2
        if (!$this->current) {
138 1
            $this->current();
139
        }
140 2
        return $this->pointer;
141
    }
142
143 5
    public function valid(): bool
144
    {
145 5
        if ($this->pointer < $this->length) {
146 1
            return true;
147
        }
148
149 5
        if ($this->cursor) {
150 5
            $valid = $this->cursor->valid();
151
152 5
            if (!$valid) {
153 5
                $this->complete = true;
154
155 5
                $this->cursor->close();
156 5
                $this->cursor = null;
157
            }
158
159 5
            return $valid;
160
        }
161
162
        return false;
163
    }
164
165 1
    public function rewind(): void
166
    {
167 1
        $this->pointer = 0;
168 1
        $this->current = null;
169 1
    }
170
171 3
    public function count(): int
172
    {
173 3
        if ($this->complete) {
174 1
            return $this->length;
175
        }
176 2
        $this->last();
177
178 2
        return $this->length;
179
    }
180
181 1
    public function toArray(): array
182
    {
183 1
        if ($this->complete) {
184
            return $this->items;
185
        }
186 1
        $this->last();
187
188 1
        return $this->items;
189
    }
190
191
    public function toCollection(): Collection
192
    {
193
        $this->last();
194
195
        return new Collection(new ArrayIterator($this->items));
196
    }
197
}
198