3 * TPagedList, TPagedListFetchDataEventParameter, TPagedListPageChangedEventParameter class file
5 * @author Qiang Xue <qiang.xue@gmail.com>
6 * @link https://github.com/pradosoft/prado
7 * @copyright Copyright © 2005-2016 The PRADO Group
8 * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
9 * @package System.Collections
15 * TPagedList implements a list with paging functionality.
17 * TPagedList works in one of two modes, managed paging or customized paging,
18 * specified by {@link setCustomPaging CustomPaging}.
19 * - Managed paging ({@link setCustomPaging CustomPaging}=false) :
20 * the list is assumed to contain all data and it will manage which page
21 * of data are available to user.
22 * - Customized paging ({@link setCustomPaging CustomPaging}=true) :
23 * the list is assumed to contain only one page of data. An {@link onFetchData OnFetchData}
24 * event will be raised if the list changes to a different page.
25 * Developers can attach a handler to the event and supply the needed data.
26 * The event handler can be written as follows,
28 * public function fetchData($sender,$param)
30 * $offset=$param->Offset; // beginning index of the data needed
31 * $limit=$param->Limit; // maximum number of data items needed
32 * // get data according to the above two parameters
37 * Data in TPagedList can be accessed like an integer-indexed array and can
38 * be traversed using foreach. For example,
40 * $count=$list->Count;
41 * for($index=0;$index<$count;++$index)
43 * foreach($list as $index=>$item) // traverse each item in the list
46 * The {@link setPageSize PageSize} property specifies the number of items in each page.
47 * To access different page of data in the list, set {@link setCurrentPageIndex CurrentPageIndex}
48 * or call {@link nextPage()}, {@link previousPage()}, or {@link gotoPage()}.
49 * The total number of pages can be obtained by {@link getPageCount() PageCount}.
52 * @author Qiang Xue <qiang.xue@gmail.com>
53 * @package System.Collections
56 class TPagedList extends TList
59 * @var boolean whether to allow custom paging
61 private $_customPaging=false;
63 * @var integer number of items in each page
65 private $_pageSize=10;
67 * @var integer current page index
69 private $_currentPageIndex=-1;
71 * @var integer user-assigned number of items in data source
73 private $_virtualCount=-1;
77 * @param array|Iterator the initial data. Default is null, meaning no initialization.
78 * @param boolean whether the list is read-only. Always true for paged list.
80 public function __construct($data=null,$readOnly=false)
82 parent::__construct($data,true);
86 * @return boolean whether to use custom paging. Defaults to false.
88 public function getCustomPaging()
90 return $this->_customPaging;
94 * @param boolean whether to allow custom paging
96 public function setCustomPaging($value)
98 $this->_customPaging=TPropertyValue::ensureBoolean($value);
102 * @return integer number of items in each page. Defaults to 10.
104 public function getPageSize()
106 return $this->_pageSize;
110 * @param integer number of items in each page
112 public function setPageSize($value)
114 if(($value=TPropertyValue::ensureInteger($value))>0)
115 $this->_pageSize=$value;
117 throw new TInvalidDataValueException('pagedlist_pagesize_invalid');
121 * @return integer current page index. Defaults to 0.
123 public function getCurrentPageIndex()
125 return $this->_currentPageIndex;
129 * @param integer current page index
130 * @throws TInvalidDataValueException if the page index is out of range
132 public function setCurrentPageIndex($value)
134 if($this->gotoPage($value=TPropertyValue::ensureInteger($value))===false)
135 throw new TInvalidDataValueException('pagedlist_currentpageindex_invalid');
139 * Raises <b>OnPageIndexChanged</b> event.
140 * This event is raised each time when the list changes to a different page.
141 * @param TPagedListPageChangedEventParameter event parameter
143 public function onPageIndexChanged($param)
145 $this->raiseEvent('OnPageIndexChanged',$this,$param);
149 * Raises <b>OnFetchData</b> event.
150 * This event is raised each time when the list changes to a different page
151 * and needs the new page of data. This event can only be raised when
152 * {@link setCustomPaging CustomPaging} is true.
153 * @param TPagedListFetchDataEventParameter event parameter
155 public function onFetchData($param)
157 $this->raiseEvent('OnFetchData',$this,$param);
161 * Changes to a page with the specified page index.
162 * @param integer page index
163 * @return integer|boolean the new page index, false if page index is out of range.
165 public function gotoPage($pageIndex)
167 if($pageIndex===$this->_currentPageIndex)
169 if($this->_customPaging)
171 if($pageIndex>=0 && ($this->_virtualCount<0 || $pageIndex<$this->getPageCount()))
173 $param=new TPagedListFetchDataEventParameter($pageIndex,$this->_pageSize*$pageIndex,$this->_pageSize);
174 $this->onFetchData($param);
175 if(($data=$param->getData())!==null)
177 $this->setReadOnly(false);
178 $this->copyFrom($data);
179 $this->setReadOnly(true);
180 $oldPage=$this->_currentPageIndex;
181 $this->_currentPageIndex=$pageIndex;
182 $this->onPageIndexChanged(new TPagedListPageChangedEventParameter($oldPage));
193 if($pageIndex>=0 && $pageIndex<$this->getPageCount())
195 $this->_currentPageIndex=$pageIndex;
196 $this->onPageIndexChanged(null);
205 * Switches to the next page.
206 * @return integer|boolean the new page index, false if next page is not available.
208 public function nextPage()
210 return $this->gotoPage($this->_currentPageIndex+1);
214 * Switches to the previous page.
215 * @return integer|boolean the new page index, false if previous page is not available.
217 public function previousPage()
219 return $this->gotoPage($this->_currentPageIndex-1);
223 * @return integer user-assigned number of items in data source. Defaults to 0.
225 public function getVirtualCount()
227 return $this->_virtualCount;
231 * @param integer user-assigned number of items in data source
233 public function setVirtualCount($value)
235 if(($value=TPropertyValue::ensureInteger($value))<0)
237 $this->_virtualCount=$value;
241 * @return integer number of pages, -1 if under custom paging mode and {@link setVirtualCount VirtualCount} is not set.
243 public function getPageCount()
245 if($this->_customPaging)
247 if($this->_virtualCount>=0)
248 return (int)(($this->_virtualCount+$this->_pageSize-1)/$this->_pageSize);
253 return (int)((parent::getCount()+$this->_pageSize-1)/$this->_pageSize);
257 * @return boolean whether the current page is the first page
259 public function getIsFirstPage()
261 return $this->_currentPageIndex===0;
265 * @return boolean whether the current page is the last page
267 public function getIsLastPage()
269 return $this->_currentPageIndex===$this->getPageCount()-1;
273 * @return integer the number of items in current page
275 public function getCount()
277 if($this->_customPaging)
278 return parent::getCount();
281 if($this->_currentPageIndex===$this->getPageCount()-1)
282 return parent::getCount()-$this->_pageSize*$this->_currentPageIndex;
284 return $this->_pageSize;
289 * @return Iterator iterator
291 public function getIterator()
293 if($this->_customPaging)
294 return parent::getIterator();
297 $data=$this->toArray();
298 return new ArrayIterator($data);
303 * Returns the item at the specified offset.
304 * This method is exactly the same as {@link offsetGet}.
305 * @param integer the index of the item
306 * @return mixed the item at the index
307 * @throws TInvalidDataValueException if the index is out of the range
309 public function itemAt($index)
311 if($this->_customPaging)
312 return parent::itemAt($index);
314 return parent::itemAt($this->_pageSize*$this->_currentPageIndex+$index);
318 * @param mixed the item
319 * @return integer the index of the item in the list (0 based), -1 if not found.
321 public function indexOf($item)
323 $c=$this->getCount();
325 if($this->itemAt($i)===$item)
331 * Returns whether there is an item at the specified offset.
332 * This method is required by the interface ArrayAccess.
333 * @param integer the offset to check on
336 public function offsetExists($offset)
338 return ($offset>=0 && $offset<$this->getCount());
342 * Returns the item at the specified offset.
343 * This method is required by the interface ArrayAccess.
344 * @param integer the offset to retrieve item.
345 * @return mixed the item at the offset
346 * @throws TInvalidDataValueException if the offset is invalid
348 public function offsetGet($offset)
350 return $this->itemAt($offset);
354 * @return array the list of items in array
356 public function toArray()
358 $c=$this->getCount();
361 $array[$i]=$this->itemAt($i);
367 * TPagedListPageChangedEventParameter class.
368 * TPagedListPageChangedEventParameter is used as the parameter for
369 * {@link TPagedList::onPageChanged OnPageChanged} event.
370 * To obtain the page index before it was changed, use {@link getOldPageIndex OldPageIndex}.
372 * @author Qiang Xue <qiang.xue@gmail.com>
373 * @package System.Collections
376 class TPagedListPageChangedEventParameter extends TEventParameter
382 * @param integer old page index
384 public function __construct($oldPage)
386 $this->_oldPage=$oldPage;
390 * @return integer the index of the page before the list changed to the new page
392 public function getOldPageIndex()
394 return $this->_oldPage;
399 * TPagedListFetchDataEventParameter class.
401 * TPagedListFetchDataEventParameter is used as the parameter for
402 * {@link TPagedList::onFetchData OnFetchData} event.
403 * To obtain the new page index, use {@link getNewPageIndex NewPageIndex}.
404 * The {@link getOffset Offset} property refers to the index
405 * of the first item in the new page, while {@link getLimit Limit}
406 * specifies how many items are requested for the page.
407 * Newly fetched data should be saved in {@link setData Data} property.
409 * @author Qiang Xue <qiang.xue@gmail.com>
410 * @package System.Collections
413 class TPagedListFetchDataEventParameter extends TEventParameter
422 * @param integer new page index
423 * @param integer offset of the first item in the new page
424 * @param integer number of items in the new page desired
426 public function __construct($pageIndex,$offset,$limit)
428 $this->_pageIndex=$pageIndex;
429 $this->_offset=$offset;
430 $this->_limit=$limit;
434 * @return integer the zero-based index of the new page
436 public function getNewPageIndex()
438 return $this->_pageIndex;
442 * @return integer offset of the first item in the new page
444 public function getOffset()
446 return $this->_offset;
450 * @return integer number of items in the new page
452 public function getLimit()
454 return $this->_limit;
458 * @return mixed new page data
460 public function getData()
466 * @param mixed new page data
468 public function setData($value)