Completed
Pull Request — master (#2116)
by
unknown
24:13
created

UnrewindableIterator::getIterator()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 0
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
11
/**
12
 * Iterator for wrapping a Traversable and caching its results.
13
 *
14
 * By caching results, this iterators allows a Traversable to be counted and
15
 * rewound multiple times, even if the wrapped object does not natively support
16
 * those operations (e.g. MongoDB\Driver\Cursor).
17
 *
18
 * @internal
19
 */
20
final class UnrewindableIterator implements Iterator
21
{
22
    /** @var Generator|null */
23
    private $iterator;
24
25
    /** @var bool */
26
    private $iteratorAdvanced = false;
27
28
    /**
29
     * Initialize the iterator. This effectively rewinds the Traversable and 
30
     * the wrapping Generator, which will execute up to its first yield statement. 
31
     * Additionally, this mimics behavior of the SPL iterators and allows users 
32
     * to omit an explicit call to rewind() before using the other methods.
33
     */
34
    public function __construct(Traversable $iterator)
35
    {
36
        $this->iterator = $this->wrapTraversable($iterator);
37
        $this->storeCurrentItem();
38
    }
39
40
    public function toArray() : array
41
    {
42
        $this->preventRewinding(__METHOD__);
43
44
        $toArray = function () {
45
            yield $this->key() => $this->current();
46
            yield from $this->getIterator();
47
        };
48
        
49
        return iterator_to_array($toArray());
50
    }
51
52
    /**
53
     * @see http://php.net/iterator.current
54
     *
55
     * @return mixed
56
     */
57
    public function current()
58
    {
59
        return $this->getIterator()->current();
60
    }
61
62
    /**
63
     * @see http://php.net/iterator.mixed
64
     *
65
     * @return mixed
66
     */
67
    public function key()
68
    {
69
        return $this->getIterator()->key();
70
    }
71
72
    /**
73
     * @see http://php.net/iterator.next
74
     */
75
    public function next() : void
76
    {
77
        if ($iterator = $this->getIterator()) {
78
            $iterator->next();
79
        }
80
    }
81
82
    /**
83
     * @see http://php.net/iterator.rewind
84
     */
85
    public function rewind() : void
86
    {
87
        $this->preventRewinding(__METHOD__);
88
    }
89
90
    /**
91
     * @see http://php.net/iterator.valid
92
     */
93
    public function valid() : bool
94
    {
95
        return $this->key() !== null;
96
    }
97
98
    private function preventRewinding(string $method): void
99
    {
100
        if ($this->iteratorAdvanced) {
101
            throw new \LogicException(sprintf(
102
                'Cannot call %s for iterator that already yielded results',
103
                $method
104
            ));
105
        }
106
    }
107
108
    private function getIterator() : Generator
109
    {
110
        if ($this->iterator === null) {
111
            throw new RuntimeException('Iterator has already been destroyed');
112
        }
113
114
        return $this->iterator;
115
    }
116
117
118
    /**
119
     * Stores the current item in the cache.
120
     */
121
    private function storeCurrentItem() : void
122
    {
123
        $key = $this->iterator->key();
124
125
        if ($key === null) {
126
            return;
127
        }
128
    }
129
130 View Code Duplication
    private function wrapTraversable(Traversable $traversable) : Generator
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
131
    {
132
        foreach ($traversable as $key => $value) {
133
            yield $key => $value;
134
            $this->iteratorAdvanced = true;
135
        }
136
137
        $this->iterator = null;
138
    }
139
}
140