1: <?php
2: /**
3: * CDataProviderIterator class file.
4: *
5: * @author Charles Pick <charles.pick@gmail.com>
6: * @link http://www.yiiframework.com/
7: * @copyright 2008-2013 Yii Software LLC
8: * @license http://www.yiiframework.com/license/
9: */
10:
11: /**
12: * CDataProviderIterator allows iteration over large data sets without holding the entire set in memory.
13: *
14: * CDataProviderIterator iterates over the results of a data provider, starting at the first page
15: * of results and ending at the last page. It is usually only suited for use with {@link CActiveDataProvider}.
16: *
17: * For example, the following code will iterate over all registered users (active record class User) without
18: * running out of memory, even if there are millions of users in the database.
19: * <pre>
20: * $dataProvider = new CActiveDataProvider("User");
21: * $iterator = new CDataProviderIterator($dataProvider);
22: * foreach($iterator as $user) {
23: * echo $user->name."\n";
24: * }
25: * </pre>
26: *
27: * @property CDataProvider $dataProvider the data provider to iterate over
28: * @property integer $totalItemCount the total number of items in the iterator
29: *
30: * @author Charles Pick <charles.pick@gmail.com>
31: * @author Carsten Brandt <mail@cebe.cc>
32: * @package system.web
33: * @since 1.1.13
34: */
35: class CDataProviderIterator extends CComponent implements Iterator, Countable
36: {
37: private $_dataProvider;
38: private $_currentIndex=-1;
39: private $_currentPage=0;
40: private $_totalItemCount=-1;
41: private $_items;
42:
43: /**
44: * Constructor.
45: * @param CDataProvider $dataProvider the data provider to iterate over
46: * @param integer $pageSize pageSize to use for iteration. This is the number of objects loaded into memory at the same time.
47: */
48: public function __construct(CDataProvider $dataProvider, $pageSize=null)
49: {
50: $this->_dataProvider=$dataProvider;
51: $this->_totalItemCount=$dataProvider->getTotalItemCount();
52:
53: if(($pagination=$this->_dataProvider->getPagination())===false)
54: $this->_dataProvider->setPagination($pagination=new CPagination());
55:
56: if($pageSize!==null)
57: $pagination->setPageSize($pageSize);
58: }
59:
60: /**
61: * Returns the data provider to iterate over
62: * @return CDataProvider the data provider to iterate over
63: */
64: public function getDataProvider()
65: {
66: return $this->_dataProvider;
67: }
68:
69: /**
70: * Gets the total number of items to iterate over
71: * @return integer the total number of items to iterate over
72: */
73: public function getTotalItemCount()
74: {
75: return $this->_totalItemCount;
76: }
77:
78: /**
79: * Loads a page of items
80: * @return array the items from the next page of results
81: */
82: protected function loadPage()
83: {
84: $this->_dataProvider->getPagination()->setCurrentPage($this->_currentPage);
85: return $this->_items=$this->dataProvider->getData(true);
86: }
87:
88: /**
89: * Gets the current item in the list.
90: * This method is required by the Iterator interface.
91: * @return mixed the current item in the list
92: */
93: public function current()
94: {
95: return $this->_items[$this->_currentIndex];
96: }
97:
98: /**
99: * Gets the key of the current item.
100: * This method is required by the Iterator interface.
101: * @return integer the key of the current item
102: */
103: public function key()
104: {
105: $pageSize=$this->_dataProvider->getPagination()->getPageSize();
106: return $this->_currentPage*$pageSize+$this->_currentIndex;
107: }
108:
109: /**
110: * Moves the pointer to the next item in the list.
111: * This method is required by the Iterator interface.
112: */
113: public function next()
114: {
115: $pageSize=$this->_dataProvider->getPagination()->getPageSize();
116: $this->_currentIndex++;
117: if($this->_currentIndex >= $pageSize)
118: {
119: $this->_currentPage++;
120: $this->_currentIndex=0;
121: $this->loadPage();
122: }
123: }
124:
125: /**
126: * Rewinds the iterator to the start of the list.
127: * This method is required by the Iterator interface.
128: */
129: public function rewind()
130: {
131: $this->_currentIndex=0;
132: $this->_currentPage=0;
133: $this->loadPage();
134: }
135:
136: /**
137: * Checks if the current position is valid or not.
138: * This method is required by the Iterator interface.
139: * @return boolean true if this index is valid
140: */
141: public function valid()
142: {
143: return $this->key() < $this->_totalItemCount;
144: }
145:
146: /**
147: * Gets the total number of items in the dataProvider.
148: * This method is required by the Countable interface.
149: * @return integer the total number of items
150: */
151: public function count()
152: {
153: return $this->_totalItemCount;
154: }
155: }