1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10:
11:
12: namespace Nette;
13:
14: use Nette;
15:
16:
17:
18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28:
29: class SmartCachingIterator extends \CachingIterator implements \Countable
30: {
31:
32: private $counter = 0;
33:
34:
35:
36: public function __construct($iterator)
37: {
38: if (is_array($iterator) || $iterator instanceof \stdClass) {
39: $iterator = new \ArrayIterator($iterator);
40:
41: } elseif ($iterator instanceof \Traversable) {
42: if ($iterator instanceof \IteratorAggregate) {
43: $iterator = $iterator->getIterator();
44:
45: } elseif (!($iterator instanceof \Iterator)) {
46: $iterator = new \IteratorIterator($iterator);
47: }
48:
49: } else {
50: throw new \InvalidArgumentException("Invalid argument passed to foreach resp. " . __CLASS__ . "; array or Traversable expected, " . (is_object($iterator) ? get_class($iterator) : gettype($iterator)) ." given.");
51: }
52:
53: parent::__construct($iterator, 0);
54: }
55:
56:
57:
58: 59: 60: 61: 62:
63: public function isFirst($width = NULL)
64: {
65: return $this->counter === 1 || ($width && $this->counter !== 0 && (($this->counter - 1) % $width) === 0);
66: }
67:
68:
69:
70: 71: 72: 73: 74:
75: public function isLast($width = NULL)
76: {
77: return !$this->hasNext() || ($width && ($this->counter % $width) === 0);
78: }
79:
80:
81:
82: 83: 84: 85:
86: public function isEmpty()
87: {
88: return $this->counter === 0;
89: }
90:
91:
92:
93: 94: 95: 96:
97: public function isOdd()
98: {
99: return $this->counter % 2 === 1;
100: }
101:
102:
103:
104: 105: 106: 107:
108: public function isEven()
109: {
110: return $this->counter % 2 === 0;
111: }
112:
113:
114:
115: 116: 117: 118:
119: public function getCounter()
120: {
121: return $this->counter;
122: }
123:
124:
125:
126: 127: 128: 129:
130: public function count()
131: {
132: $inner = $this->getInnerIterator();
133: if ($inner instanceof \Countable) {
134: return $inner->count();
135:
136: } else {
137: throw new \NotSupportedException('Iterator is not countable.');
138: }
139: }
140:
141:
142:
143: 144: 145: 146:
147: public function next()
148: {
149: parent::next();
150: if (parent::valid()) {
151: $this->counter++;
152: }
153: }
154:
155:
156:
157: 158: 159: 160:
161: public function rewind()
162: {
163: parent::rewind();
164: $this->counter = parent::valid() ? 1 : 0;
165: }
166:
167:
168:
169: 170: 171: 172:
173: public function getNextKey()
174: {
175: return $this->getInnerIterator()->key();
176: }
177:
178:
179:
180: 181: 182: 183:
184: public function getNextValue()
185: {
186: return $this->getInnerIterator()->current();
187: }
188:
189:
190:
191:
192:
193:
194:
195: 196: 197: 198: 199: 200: 201:
202: public function __call($name, $args)
203: {
204: return ObjectMixin::call($this, $name, $args);
205: }
206:
207:
208:
209: 210: 211: 212: 213: 214:
215: public function &__get($name)
216: {
217: return ObjectMixin::get($this, $name);
218: }
219:
220:
221:
222: 223: 224: 225: 226: 227: 228:
229: public function __set($name, $value)
230: {
231: return ObjectMixin::set($this, $name, $value);
232: }
233:
234:
235:
236: 237: 238: 239: 240:
241: public function __isset($name)
242: {
243: return ObjectMixin::has($this, $name);
244: }
245:
246:
247:
248: 249: 250: 251: 252: 253:
254: public function __unset($name)
255: {
256: $class = get_class($this);
257: throw new \MemberAccessException("Cannot unset the property $class::\$$name.");
258: }
259:
260:
261: }
262: