Completed
Pull Request — master (#2116)
by
unknown
14:25 queued 44s
created

UnrewindableIterator::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 5
ccs 4
cts 4
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
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
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 8
    public function __construct(Traversable $iterator)
35
    {
36 8
        $this->iterator = $this->wrapTraversable($iterator);
37 8
        $this->iterator->key();
38 8
    }
39
40 3
    public function toArray() : array
41
    {
42 3
        $this->preventRewinding(__METHOD__);
43
44
        $toArray = function () {
45 2
            if (!$this->valid()) {
46 1
                return;
47
            }
48 1
            yield $this->key() => $this->current();
49 1
            yield from $this->getIterator();
50 2
        };
51
        
52 2
        return iterator_to_array($toArray());
53
    }
54
55
    /**
56
     * @see http://php.net/iterator.current
57
     *
58
     * @return mixed
59
     */
60 6
    public function current()
61
    {
62 6
        return $this->getIterator()->current();
63
    }
64
65
    /**
66
     * @see http://php.net/iterator.mixed
67
     *
68
     * @return mixed
69
     */
70 8
    public function key()
71
    {
72 8
        if ($this->iterator) {
73 6
            return $this->iterator->key();
74
        }
75
        
76 3
        return null;
77
    }
78
79
    /**
80
     * @see http://php.net/iterator.next
81
     */
82 4
    public function next() : void
83
    {
84 4
        if ($this->iterator) {
85 4
            $this->iterator->next();
86
        }
87 4
    }
88
89
    /**
90
     * @see http://php.net/iterator.rewind
91
     */
92 5
    public function rewind() : void
93
    {
94 5
        $this->preventRewinding(__METHOD__);
95 5
    }
96
97
    /**
98
     * @see http://php.net/iterator.valid
99
     */
100 8
    public function valid() : bool
101
    {
102 8
        return $this->key() !== null;
103
    }
104
105 7
    private function preventRewinding(string $method): void
106
    {
107 7
        if ($this->iteratorAdvanced) {
108 2
            throw new \LogicException(sprintf(
109 2
                'Cannot call %s for iterator that already yielded results',
110 2
                $method
111
            ));
112
        }
113 7
    }
114
115 6
    private function getIterator() : Generator
116
    {
117 6
        if ($this->iterator === null) {
118
            throw new RuntimeException('Iterator has already been destroyed');
119
        }
120
121 6
        return $this->iterator;
122
    }
123
124 8 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...
125
    {
126 8
        foreach ($traversable as $key => $value) {
127 6
            yield $key => $value;
128 5
            $this->iteratorAdvanced = true;
129
        }
130
131 4
        $this->iterator = null;
132 4
    }
133
}
134