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: