/framework/Collections/TPagedDataSource.php

https://bitbucket.org/volatileeight/prado · PHP · 442 lines · 217 code · 38 blank · 187 comment · 31 complexity · 0bf0a77413af39f140fe0a3d756ea9cd MD5 · raw file

  1. <?php
  2. /**
  3. * TPagedDataSource, TPagedListIterator, TPagedMapIterator classes
  4. *
  5. * @author Qiang Xue <qiang.xue@gmail.com>
  6. * @link http://www.pradosoft.com/
  7. * @copyright Copyright &copy; 2005-2014 PradoSoft
  8. * @license http://www.pradosoft.com/license/
  9. * @package System.Collections
  10. */
  11. /**
  12. * TPagedDataSource class
  13. *
  14. * TPagedDataSource implements an integer-indexed collection class with paging functionality.
  15. *
  16. * Data items in TPagedDataSource can be traversed using <b>foreach</b>
  17. * PHP statement like the following,
  18. * <code>
  19. * foreach($pagedDataSource as $dataItem)
  20. * </code>
  21. * The data are fetched from {@link setDataSource DataSource}. Only the items
  22. * within the specified page will be returned and traversed.
  23. *
  24. * @author Qiang Xue <qiang.xue@gmail.com>
  25. * @package System.Collections
  26. * @since 3.0
  27. */
  28. class TPagedDataSource extends TComponent implements IteratorAggregate,Countable
  29. {
  30. /**
  31. * @var mixed original data source
  32. */
  33. private $_dataSource=null;
  34. /**
  35. * @var integer number of items in each page
  36. */
  37. private $_pageSize=10;
  38. /**
  39. * @var integer current page index
  40. */
  41. private $_currentPageIndex=0;
  42. /**
  43. * @var boolean whether to allow paging
  44. */
  45. private $_allowPaging=false;
  46. /**
  47. * @var boolean whether to allow custom paging
  48. */
  49. private $_allowCustomPaging=false;
  50. /**
  51. * @var integer user-assigned number of items in data source
  52. */
  53. private $_virtualCount=0;
  54. /**
  55. * @return mixed original data source. Defaults to null.
  56. */
  57. public function getDataSource()
  58. {
  59. return $this->_dataSource;
  60. }
  61. /**
  62. * @param mixed original data source
  63. */
  64. public function setDataSource($value)
  65. {
  66. if(!($value instanceof TMap) && !($value instanceof TList))
  67. {
  68. if(is_array($value))
  69. $value=new TMap($value);
  70. else if($value instanceof Traversable)
  71. $value=new TList($value);
  72. else if($value!==null)
  73. throw new TInvalidDataTypeException('pageddatasource_datasource_invalid');
  74. }
  75. $this->_dataSource=$value;
  76. }
  77. /**
  78. * @return integer number of items in each page. Defaults to 10.
  79. */
  80. public function getPageSize()
  81. {
  82. return $this->_pageSize;
  83. }
  84. /**
  85. * @param integer number of items in each page
  86. */
  87. public function setPageSize($value)
  88. {
  89. if(($value=TPropertyValue::ensureInteger($value))>0)
  90. $this->_pageSize=$value;
  91. else
  92. throw new TInvalidDataValueException('pageddatasource_pagesize_invalid');
  93. }
  94. /**
  95. * @return integer current page index. Defaults to 0.
  96. */
  97. public function getCurrentPageIndex()
  98. {
  99. return $this->_currentPageIndex;
  100. }
  101. /**
  102. * @param integer current page index
  103. */
  104. public function setCurrentPageIndex($value)
  105. {
  106. if(($value=TPropertyValue::ensureInteger($value))<0)
  107. $value=0;
  108. $this->_currentPageIndex=$value;
  109. }
  110. /**
  111. * @return boolean whether to allow paging. Defaults to false.
  112. */
  113. public function getAllowPaging()
  114. {
  115. return $this->_allowPaging;
  116. }
  117. /**
  118. * @param boolean whether to allow paging
  119. */
  120. public function setAllowPaging($value)
  121. {
  122. $this->_allowPaging=TPropertyValue::ensureBoolean($value);
  123. }
  124. /**
  125. * @return boolean whether to allow custom paging. Defaults to false.
  126. */
  127. public function getAllowCustomPaging()
  128. {
  129. return $this->_allowCustomPaging;
  130. }
  131. /**
  132. * @param boolean whether to allow custom paging
  133. */
  134. public function setAllowCustomPaging($value)
  135. {
  136. $this->_allowCustomPaging=TPropertyValue::ensureBoolean($value);
  137. }
  138. /**
  139. * @return integer user-assigned number of items in data source Defaults to 0.
  140. */
  141. public function getVirtualItemCount()
  142. {
  143. return $this->_virtualCount;
  144. }
  145. /**
  146. * @param integer user-assigned number of items in data source
  147. */
  148. public function setVirtualItemCount($value)
  149. {
  150. if(($value=TPropertyValue::ensureInteger($value))>=0)
  151. $this->_virtualCount=$value;
  152. else
  153. throw new TInvalidDataValueException('pageddatasource_virtualitemcount_invalid');
  154. }
  155. /**
  156. * @return integer number of items in current page
  157. */
  158. public function getCount()
  159. {
  160. if($this->_dataSource===null)
  161. return 0;
  162. if(!$this->_allowPaging)
  163. return $this->getDataSourceCount();
  164. if(!$this->_allowCustomPaging && $this->getIsLastPage())
  165. return $this->getDataSourceCount()-$this->getFirstIndexInPage();
  166. return $this->_pageSize;
  167. }
  168. /**
  169. * Returns the number of items in the current page.
  170. * This method is required by Countable interface.
  171. * @return integer number of items in the current page.
  172. */
  173. public function count()
  174. {
  175. return $this->getCount();
  176. }
  177. /**
  178. * @return integer number of pages
  179. */
  180. public function getPageCount()
  181. {
  182. if($this->_dataSource===null)
  183. return 0;
  184. $count=$this->getDataSourceCount();
  185. if(!$this->_allowPaging || $count<=0)
  186. return 1;
  187. return (int)(($count+$this->_pageSize-1)/$this->_pageSize);
  188. }
  189. /**
  190. * @return boolean whether the current page is the first page Defaults to false.
  191. */
  192. public function getIsFirstPage()
  193. {
  194. if($this->_allowPaging)
  195. return $this->_currentPageIndex===0;
  196. else
  197. return true;
  198. }
  199. /**
  200. * @return boolean whether the current page is the last page
  201. */
  202. public function getIsLastPage()
  203. {
  204. if($this->_allowPaging)
  205. return $this->_currentPageIndex===$this->getPageCount()-1;
  206. else
  207. return true;
  208. }
  209. /**
  210. * @return integer the index of the item in data source, where the item is the first in
  211. * current page
  212. */
  213. public function getFirstIndexInPage()
  214. {
  215. if($this->_dataSource!==null && $this->_allowPaging && !$this->_allowCustomPaging)
  216. return $this->_currentPageIndex*$this->_pageSize;
  217. else
  218. return 0;
  219. }
  220. /**
  221. * @return integer number of items in data source, if available
  222. */
  223. public function getDataSourceCount()
  224. {
  225. if($this->_dataSource===null)
  226. return 0;
  227. else if($this->_allowCustomPaging)
  228. return $this->_virtualCount;
  229. else
  230. return $this->_dataSource->getCount();
  231. }
  232. /**
  233. * @return Iterator iterator
  234. */
  235. public function getIterator()
  236. {
  237. if($this->_dataSource instanceof TList)
  238. return new TPagedListIterator($this->_dataSource,$this->getFirstIndexInPage(),$this->getCount());
  239. else if($this->_dataSource instanceof TMap)
  240. return new TPagedMapIterator($this->_dataSource,$this->getFirstIndexInPage(),$this->getCount());
  241. else
  242. return null;
  243. }
  244. }
  245. /**
  246. * TPagedListIterator class
  247. *
  248. * TPagedListIterator implements Iterator interface.
  249. *
  250. * TPagedListIterator is used by {@link TPagedDataSource}. It allows TPagedDataSource
  251. * to return a new iterator for traversing the items in a {@link TList} object.
  252. *
  253. * @author Qiang Xue <qiang.xue@gmail.com>
  254. * @package System.Collections
  255. * @since 3.0
  256. */
  257. class TPagedListIterator implements Iterator
  258. {
  259. private $_list;
  260. private $_startIndex;
  261. private $_count;
  262. private $_index;
  263. /**
  264. * Constructor.
  265. * @param TList the data to be iterated through
  266. * @param integer start index
  267. * @param integer number of items to be iterated through
  268. */
  269. public function __construct(TList $list,$startIndex,$count)
  270. {
  271. $this->_list=$list;
  272. $this->_index=0;
  273. $this->_startIndex=$startIndex;
  274. if($startIndex+$count>$list->getCount())
  275. $this->_count=$list->getCount()-$startIndex;
  276. else
  277. $this->_count=$count;
  278. }
  279. /**
  280. * Rewinds internal array pointer.
  281. * This method is required by the interface Iterator.
  282. */
  283. public function rewind()
  284. {
  285. $this->_index=0;
  286. }
  287. /**
  288. * Returns the key of the current array item.
  289. * This method is required by the interface Iterator.
  290. * @return integer the key of the current array item
  291. */
  292. public function key()
  293. {
  294. return $this->_index;
  295. }
  296. /**
  297. * Returns the current array item.
  298. * This method is required by the interface Iterator.
  299. * @return mixed the current array item
  300. */
  301. public function current()
  302. {
  303. return $this->_list->itemAt($this->_startIndex+$this->_index);
  304. }
  305. /**
  306. * Moves the internal pointer to the next array item.
  307. * This method is required by the interface Iterator.
  308. */
  309. public function next()
  310. {
  311. $this->_index++;
  312. }
  313. /**
  314. * Returns whether there is an item at current position.
  315. * This method is required by the interface Iterator.
  316. * @return boolean
  317. */
  318. public function valid()
  319. {
  320. return $this->_index<$this->_count;
  321. }
  322. }
  323. /**
  324. * TPagedMapIterator class
  325. *
  326. * TPagedMapIterator implements Iterator interface.
  327. *
  328. * TPagedMapIterator is used by {@link TPagedDataSource}. It allows TPagedDataSource
  329. * to return a new iterator for traversing the items in a {@link TMap} object.
  330. *
  331. * @author Qiang Xue <qiang.xue@gmail.com>
  332. * @package System.Collections
  333. * @since 3.0
  334. */
  335. class TPagedMapIterator implements Iterator
  336. {
  337. private $_map;
  338. private $_startIndex;
  339. private $_count;
  340. private $_index;
  341. private $_iterator;
  342. /**
  343. * Constructor.
  344. * @param array the data to be iterated through
  345. */
  346. public function __construct(TMap $map,$startIndex,$count)
  347. {
  348. $this->_map=$map;
  349. $this->_index=0;
  350. $this->_startIndex=$startIndex;
  351. if($startIndex+$count>$map->getCount())
  352. $this->_count=$map->getCount()-$startIndex;
  353. else
  354. $this->_count=$count;
  355. $this->_iterator=$map->getIterator();
  356. }
  357. /**
  358. * Rewinds internal array pointer.
  359. * This method is required by the interface Iterator.
  360. */
  361. public function rewind()
  362. {
  363. $this->_iterator->rewind();
  364. for($i=0;$i<$this->_startIndex;++$i)
  365. $this->_iterator->next();
  366. $this->_index=0;
  367. }
  368. /**
  369. * Returns the key of the current array item.
  370. * This method is required by the interface Iterator.
  371. * @return integer the key of the current array item
  372. */
  373. public function key()
  374. {
  375. return $this->_iterator->key();
  376. }
  377. /**
  378. * Returns the current array item.
  379. * This method is required by the interface Iterator.
  380. * @return mixed the current array item
  381. */
  382. public function current()
  383. {
  384. return $this->_iterator->current();
  385. }
  386. /**
  387. * Moves the internal pointer to the next array item.
  388. * This method is required by the interface Iterator.
  389. */
  390. public function next()
  391. {
  392. $this->_index++;
  393. $this->_iterator->next();
  394. }
  395. /**
  396. * Returns whether there is an item at current position.
  397. * This method is required by the interface Iterator.
  398. * @return boolean
  399. */
  400. public function valid()
  401. {
  402. return $this->_index<$this->_count;
  403. }
  404. }