1: <?php
2:
3: /**
4: * Jyxo PHP Library
5: *
6: * LICENSE
7: *
8: * This source file is subject to the new BSD license that is bundled
9: * with this package in the file license.txt.
10: * It is also available through the world-wide-web at this URL:
11: * https://github.com/jyxo/php/blob/master/license.txt
12: */
13:
14: namespace Jyxo\Spl;
15:
16: /**
17: * \LimitIterator which supports \Countable for transparent wrapping.
18: *
19: * @category Jyxo
20: * @package Jyxo\Spl
21: * @copyright Copyright (c) 2005-2011 Jyxo, s.r.o.
22: * @license https://github.com/jyxo/php/blob/master/license.txt
23: * @author Jakub Tománek
24: */
25: class CountableLimitIterator extends \LimitIterator implements \Countable
26: {
27: /**
28: * Result counting mode - returns all inner iterator data count.
29: *
30: * @var integer
31: */
32: const MODE_PASS = 1;
33:
34: /**
35: * Result counting mode - returns number of data after applying limit
36: * For proper function inner iterator must return exact number of its items.
37: *
38: * @var integer
39: */
40: const MODE_LIMIT = 2;
41:
42: /**
43: * Defined offset.
44: *
45: * @var integer
46: */
47: private $offset;
48:
49: /**
50: * Defined maximum item count.
51: *
52: * @var integer
53: */
54: private $count;
55:
56: /**
57: * Result counting mode - see self::MODE_* constants.
58: *
59: * @var integer
60: */
61: private $mode = self::MODE_PASS;
62:
63: /**
64: * Constructor.
65: *
66: * @param \Iterator $iterator Source data
67: * @param integer $offset Offset (Optional)
68: * @param integer $count Maximum item count (Optional)
69: * @param integer $mode Result counting mode
70: * @throws \InvalidArgumentException Inner iterator is not countable
71: */
72: public function __construct (\Iterator $iterator, $offset = 0, $count = -1, $mode = self::MODE_PASS)
73: {
74: if (!($iterator instanceof \Countable)) {
75: throw new \InvalidArgumentException('Supplied iterator must be countable');
76: }
77:
78: parent::__construct($iterator, $offset, $count);
79: $this->offset = $offset;
80: $this->count = $count;
81: $this->mode = $mode;
82: }
83:
84: /**
85: * Returns number of items based on result counting mode (all inner or final count after applying limit).
86: *
87: * @return integer
88: */
89: public function count()
90: {
91: $count = count($this->getInnerIterator());
92: if (self::MODE_LIMIT === $this->mode) {
93: // We want real number of results - after applying limit
94:
95: if (0 !== $this->offset) {
96: // Offset from beginning
97: $count -= $this->offset;
98: }
99: if (-1 !== $this->count && $count > $this->count) {
100: // Maximum number of items
101: $count = $this->count;
102: }
103: if ($count < 0) {
104: // We moved after end of inner iterator - offset is higher than count($this->getInnerIterator())
105: $count = 0;
106: }
107: }
108: return $count;
109: }
110: }
111: