Completed
Push — master ( 18f9b1...e2cca3 )
by Dawid
07:34
created

LazyCollection   A

Complexity

Total Complexity 42

Size/Duplication

Total Lines 179
Duplicated Lines 0 %

Test Coverage

Coverage 51.09%

Importance

Changes 0
Metric Value
dl 0
loc 179
ccs 47
cts 92
cp 0.5109
rs 9.0399
c 0
b 0
f 0
wmc 42

14 Methods

Rating   Name   Duplication   Size   Complexity  
A last() 0 8 2
B current() 0 19 8
A rewind() 0 4 1
A previous() 0 4 2
A key() 0 6 2
A index() 0 3 1
A valid() 0 20 4
A __construct() 0 3 1
A count() 0 8 2
A contains() 0 9 3
A next() 0 13 5
B at() 0 29 7
A toArray() 0 8 2
A first() 0 7 2

How to fix   Complexity   

Complex Class

Complex classes like LazyCollection often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use LazyCollection, and based on these observations, apply Extract Interface, too.

1
<?php declare(strict_types=1);
2
3
namespace Igni\Storage\Mapping\Collection;
4
5
use Igni\Exception\OutOfBoundsException;
6
use Igni\Storage\Driver\Cursor;
7
8
class LazyCollection implements \Igni\Storage\Mapping\Collection
9
{
10
    protected $cursor;
11
    protected $length;
12
    protected $current;
13
    protected $items = [];
14
    protected $pointer = 0;
15
    protected $complete = false;
16
17 14
    public function __construct(Cursor $cursor)
18
    {
19 14
        $this->cursor = $cursor;
20 14
    }
21
22
    public function contains($item): bool
23
    {
24
        foreach ($this as $element) {
25
            if ($element === $item) {
26
                return true;
27
            }
28
        }
29
30
        return false;
31
    }
32
33
    public function first()
34
    {
35
        $this->pointer = 0;
36
        if ($this->pointer < $this->length) {
37
            return $this->current = $this->items[$this->pointer];
38
        }
39
        return $this->current();
40
    }
41
42 3
    public function last()
43
    {
44 3
        while ($this->valid()) {
45 3
            $this->current();
46 3
            $this->next();
47
        }
48
49 3
        return $this->current();
50
    }
51
52 2
    public function at(int $index)
53
    {
54 2
        $item = null;
55 2
        if ($index < $this->length) {
56 2
            return $this->current = $this->items[$index];
57
        }
58
59
        if ($this->complete) {
60
            throw OutOfBoundsException::forInvalidOffset($index);
0 ignored issues
show
Bug introduced by
The method forInvalidOffset() does not exist on Igni\Exception\OutOfBoundsException. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

60
            throw OutOfBoundsException::/** @scrutinizer ignore-call */ forInvalidOffset($index);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
61
        }
62
63
        $savedPointer = $this->pointer;
64
        while ($this->pointer <= $index) {
65
            $item = $this->current();
66
            if (!$this->valid()) {
67
                break;
68
            }
69
            $this->next();
70
        }
71
72
        if ($this->pointer < $index && $this->complete) {
73
            $offset = $this->pointer;
74
            $this->pointer = $savedPointer;
75
            throw OutOfBoundsException::forInvalidOffset($offset);
76
        }
77
78
        $this->pointer = $savedPointer;
79
80
        return $item;
81
    }
82
83 4
    public function current()
84
    {
85
        // Empty resultset or out of bounds.
86 4
        if ($this->cursor === null &&
87 4
            $this->current === null &&
88 4
            ($this->pointer > $this->length || ($this->length === null && $this->complete))
89
        ) {
90
            throw OutOfBoundsException::forInvalidOffset($this->pointer);
91
        }
92
93 4
        if (null === $this->current) {
94 4
            if ($this->pointer < $this->length) {
95
                $this->current = $this->items[$this->pointer];
96
            } else {
97 4
                $this->items[$this->pointer] = $this->current = $this->cursor->current();
98
            }
99
        }
100
101 4
        return $this->current;
102
    }
103
104 3
    public function next(): void
105
    {
106 3
        $this->pointer++;
107
108 3
        if ($this->pointer < $this->length) {
109
            $this->current = $this->items[$this->pointer];
110 3
        } else if ($this->cursor) {
111 3
            if ($this->pointer > $this->length) {
112 3
                $this->length = $this->pointer;
113
            }
114 3
            $this->cursor->next();
115 3
            if ($this->cursor->valid()) {
116 3
                $this->items[$this->pointer] = $this->current = $this->cursor->current();
117
            }
118
        }
119 3
    }
120
121
    public function previous(): void
122
    {
123
        if ($this->pointer > 0) {
124
            $this->pointer--;
125
        }
126
    }
127
128
    public function key()
129
    {
130
        if (!$this->current) {
131
            $this->current();
132
        }
133
        return $this->pointer;
134
    }
135
136
    public function index(): int
137
    {
138
        return $this->pointer;
139
    }
140
141 3
    public function valid(): bool
142
    {
143 3
        if ($this->pointer < $this->length) {
144
            return true;
145
        }
146
147 3
        if ($this->cursor) {
148 3
            $valid = $this->cursor->valid();
149
150 3
            if (!$valid) {
151 3
                $this->complete = true;
152
153 3
                $this->cursor->close();
154 3
                $this->cursor = null;
155
            }
156
157 3
            return $valid;
158
        }
159
160
        return false;
161
    }
162
163
    public function rewind(): void
164
    {
165
        $this->pointer = 0;
166
        $this->current = null;
167
    }
168
169 2
    public function count(): int
170
    {
171 2
        if ($this->complete) {
172
            return $this->length;
173
        }
174 2
        $this->last();
175
176 2
        return $this->length;
177
    }
178
179 1
    public function toArray(): array
180
    {
181 1
        if ($this->complete) {
182
            return $this->items;
183
        }
184 1
        $this->last();
185
186 1
        return $this->items;
187
    }
188
}
189