1: <?php
2:
3: /**
4: * This file is part of the Nette Framework (https://nette.org)
5: * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
6: */
7:
8: namespace Nette\Iterators;
9:
10: use Nette;
11:
12:
13: /**
14: * Smarter caching iterator.
15: *
16: * @property-read bool $first
17: * @property-read bool $last
18: * @property-read bool $empty
19: * @property-read bool $odd
20: * @property-read bool $even
21: * @property-read int $counter
22: * @property-read mixed $nextKey
23: * @property-read mixed $nextValue
24: */
25: class CachingIterator extends \CachingIterator implements \Countable
26: {
27: use Nette\SmartObject;
28:
29: /** @var int */
30: private $counter = 0;
31:
32:
33: public function __construct($iterator)
34: {
35: if (is_array($iterator) || $iterator instanceof \stdClass) {
36: $iterator = new \ArrayIterator($iterator);
37:
38: } elseif ($iterator instanceof \IteratorAggregate) {
39: do {
40: $iterator = $iterator->getIterator();
41: } while ($iterator instanceof \IteratorAggregate);
42:
43: } elseif ($iterator instanceof \Traversable) {
44: if (!$iterator instanceof \Iterator) {
45: $iterator = new \IteratorIterator($iterator);
46: }
47: } else {
48: throw new Nette\InvalidArgumentException(sprintf('Invalid argument passed to %s; array or Traversable expected, %s given.', __CLASS__, is_object($iterator) ? get_class($iterator) : gettype($iterator)));
49: }
50:
51: parent::__construct($iterator, 0);
52: }
53:
54:
55: /**
56: * Is the current element the first one?
57: * @param int grid width
58: * @return bool
59: */
60: public function isFirst($width = null)
61: {
62: return $this->counter === 1 || ($width && $this->counter !== 0 && (($this->counter - 1) % $width) === 0);
63: }
64:
65:
66: /**
67: * Is the current element the last one?
68: * @param int grid width
69: * @return bool
70: */
71: public function isLast($width = null)
72: {
73: return !$this->hasNext() || ($width && ($this->counter % $width) === 0);
74: }
75:
76:
77: /**
78: * Is the iterator empty?
79: * @return bool
80: */
81: public function isEmpty()
82: {
83: return $this->counter === 0;
84: }
85:
86:
87: /**
88: * Is the counter odd?
89: * @return bool
90: */
91: public function isOdd()
92: {
93: return $this->counter % 2 === 1;
94: }
95:
96:
97: /**
98: * Is the counter even?
99: * @return bool
100: */
101: public function isEven()
102: {
103: return $this->counter % 2 === 0;
104: }
105:
106:
107: /**
108: * Returns the counter.
109: * @return int
110: */
111: public function getCounter()
112: {
113: return $this->counter;
114: }
115:
116:
117: /**
118: * Returns the count of elements.
119: * @return int
120: */
121: public function count()
122: {
123: $inner = $this->getInnerIterator();
124: if ($inner instanceof \Countable) {
125: return $inner->count();
126:
127: } else {
128: throw new Nette\NotSupportedException('Iterator is not countable.');
129: }
130: }
131:
132:
133: /**
134: * Forwards to the next element.
135: * @return void
136: */
137: public function next()
138: {
139: parent::next();
140: if (parent::valid()) {
141: $this->counter++;
142: }
143: }
144:
145:
146: /**
147: * Rewinds the Iterator.
148: * @return void
149: */
150: public function rewind()
151: {
152: parent::rewind();
153: $this->counter = parent::valid() ? 1 : 0;
154: }
155:
156:
157: /**
158: * Returns the next key.
159: * @return mixed
160: */
161: public function getNextKey()
162: {
163: return $this->getInnerIterator()->key();
164: }
165:
166:
167: /**
168: * Returns the next element.
169: * @return mixed
170: */
171: public function getNextValue()
172: {
173: return $this->getInnerIterator()->current();
174: }
175: }
176: