Completed
Pull Request — master (#2116)
by
unknown
19:57
created

CachingIterator::__destruct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\ODM\MongoDB\Iterator;
6
7
use Generator;
8
use RuntimeException;
9
use Traversable;
10
use function current;
11
use function key;
12
use function next;
13
use function reset;
14
15
/**
16
 * Iterator for wrapping a Traversable and caching its results.
17
 *
18
 * By caching results, this iterators allows a Traversable to be counted and
19
 * rewound multiple times, even if the wrapped object does not natively support
20
 * those operations (e.g. MongoDB\Driver\Cursor).
21
 *
22
 * @internal
23
 */
24
final class CachingIterator implements Iterator
25
{
26
    /** @var array */
27
    private $items = [];
28
29
    /** @var Generator|null */
30
    private $iterator;
31
32
    /** @var bool */
33
    private $iteratorAdvanced = false;
34
35
    /**
36
     * Initialize the iterator and stores the first item in the cache. This
37
     * effectively rewinds the Traversable and the wrapping Generator, which
38
     * will execute up to its first yield statement. Additionally, this mimics
39
     * behavior of the SPL iterators and allows users to omit an explicit call
40
     * to rewind() before using the other methods.
41
     */
42 145
    public function __construct(Traversable $iterator)
43
    {
44 145
        $this->iterator = $this->wrapTraversable($iterator);
45 145
        $this->storeCurrentItem();
46 145
    }
47
48 106
    public function __destruct()
49
    {
50 106
        $this->iterator = null;
51 106
    }
52
53 82
    public function toArray() : array
54
    {
55 82
        $this->exhaustIterator();
56
57 82
        return $this->items;
58
    }
59
60
    /**
61
     * @see http://php.net/iterator.current
62
     *
63
     * @return mixed
64
     */
65 91
    public function current()
66
    {
67 91
        return current($this->items);
68
    }
69
70
    /**
71
     * @see http://php.net/iterator.mixed
72
     *
73
     * @return mixed
74
     */
75 34
    public function key()
76
    {
77 34
        return key($this->items);
78
    }
79
80
    /**
81
     * @see http://php.net/iterator.next
82
     */
83 85
    public function next() : void
84
    {
85 85
        if ($this->iterator) {
86 85
            $this->iterator->next();
87
        }
88
89 85
        next($this->items);
90 85
    }
91
92
    /**
93
     * @see http://php.net/iterator.rewind
94
     */
95 30
    public function rewind() : void
96
    {
97
        /* If the iterator has advanced, exhaust it now so that future iteration
98
         * can rely on the cache.
99
         */
100 30
        if ($this->iteratorAdvanced) {
101 20
            $this->exhaustIterator();
102
        }
103
104 30
        reset($this->items);
105 30
    }
106
107
    /**
108
     * @see http://php.net/iterator.valid
109
     */
110 34
    public function valid() : bool
111
    {
112 34
        return $this->key() !== null;
113
    }
114
115
    /**
116
     * Ensures that the inner iterator is fully consumed and cached.
117
     */
118 86
    private function exhaustIterator() : void
119
    {
120 86
        while ($this->iterator) {
121 75
            $this->next();
122
        }
123
124 86
        $this->iterator = null;
125 86
    }
126
127
    /**
128
     * Stores the current item in the cache.
129
     */
130 145
    private function storeCurrentItem() : void
131
    {
132 145
        $key = $this->iterator->key();
133
134 145
        if ($key === null) {
135 17
            return;
136
        }
137
138 135
        $this->items[$key] = $this->iterator->current();
139 135
    }
140
141 145
    private function wrapTraversable(Traversable $traversable) : Generator
142
    {
143 145 View Code Duplication
        foreach ($traversable as $key => $value) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
144 135
            $this->items[$key] = $value;
145 135
            yield $key => $value;
146 85
            $this->iteratorAdvanced = true;
147
        }
148
149 96
        $this->iterator = null;
150 96
    }
151
}
152