1<?php
2
3namespace ipl\Orm;
4
5use ArrayIterator;
6use Iterator;
7use Traversable;
8
9class ResultSet implements Iterator
10{
11    protected $cache;
12
13    protected $generator;
14
15    protected $limit;
16
17    protected $position;
18
19    public function __construct(Traversable $traversable, $limit = null)
20    {
21        $this->cache = new ArrayIterator();
22        $this->generator = $this->yieldTraversable($traversable);
23        $this->limit = $limit;
24    }
25
26    public function hasMore()
27    {
28        return $this->generator->valid();
29    }
30
31    public function hasResult()
32    {
33        return $this->generator->valid();
34    }
35
36    public function current()
37    {
38        if ($this->position === null) {
39            $this->advance();
40        }
41
42        return $this->cache->current();
43    }
44
45    public function next()
46    {
47        $this->cache->next();
48
49        if (! $this->cache->valid()) {
50            $this->generator->next();
51            $this->advance();
52        }
53    }
54
55    public function key()
56    {
57        if ($this->position === null) {
58            $this->advance();
59        }
60
61        return $this->cache->key();
62    }
63
64    public function valid()
65    {
66        if ($this->limit !== null && $this->position === $this->limit) {
67            return false;
68        }
69
70        return $this->cache->valid() || $this->generator->valid();
71    }
72
73    public function rewind()
74    {
75        $this->cache->rewind();
76
77        if ($this->position === null) {
78            $this->advance();
79        } else {
80            $this->position = 0;
81        }
82    }
83
84    protected function advance()
85    {
86        if (! $this->generator->valid()) {
87            return;
88        }
89
90        $this->cache[$this->generator->key()] = $this->generator->current();
91
92        // Only required on PHP 5.6, 7+ does it automatically
93        $this->cache->seek($this->generator->key());
94
95        if ($this->position === null) {
96            $this->position = 0;
97        } else {
98            $this->position += 1;
99        }
100    }
101
102    protected function yieldTraversable(Traversable $traversable)
103    {
104        foreach ($traversable as $key => $value) {
105            yield $key => $value;
106        }
107    }
108}
109