]> git.sur5r.net Git - bacula/bacula/blob - gui/baculum/framework/Collections/TPagedList.php
baculum: New Baculum API and Baculum Web
[bacula/bacula] / gui / baculum / framework / Collections / TPagedList.php
1 <?php
2 /**
3  * TPagedList, TPagedListFetchDataEventParameter, TPagedListPageChangedEventParameter class file
4  *
5  * @author Qiang Xue <qiang.xue@gmail.com>
6  * @link https://github.com/pradosoft/prado
7  * @copyright Copyright &copy; 2005-2016 The PRADO Group
8  * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
9  * @package System.Collections
10  */
11
12 /**
13  * TPagedList class
14  *
15  * TPagedList implements a list with paging functionality.
16  *
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,
27  * <code>
28  *  public function fetchData($sender,$param)
29  *  {
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
33  *    $param->Data=$data;
34  *  }
35  * </code>
36  *
37  * Data in TPagedList can be accessed like an integer-indexed array and can
38  * be traversed using foreach. For example,
39  * <code>
40  * $count=$list->Count;
41  * for($index=0;$index<$count;++$index)
42  *     echo $list[$index];
43  * foreach($list as $index=>$item) // traverse each item in the list
44  * </code>
45  *
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}.
50  *
51  *
52  * @author Qiang Xue <qiang.xue@gmail.com>
53  * @package System.Collections
54  * @since 3.0
55  */
56 class TPagedList extends TList
57 {
58         /**
59          * @var boolean whether to allow custom paging
60          */
61         private $_customPaging=false;
62         /**
63          * @var integer number of items in each page
64          */
65         private $_pageSize=10;
66         /**
67          * @var integer current page index
68          */
69         private $_currentPageIndex=-1;
70         /**
71          * @var integer user-assigned number of items in data source
72          */
73         private $_virtualCount=-1;
74
75         /**
76          * Constructor.
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.
79          */
80         public function __construct($data=null,$readOnly=false)
81         {
82                 parent::__construct($data,true);
83         }
84
85         /**
86          * @return boolean whether to use custom paging. Defaults to false.
87          */
88         public function getCustomPaging()
89         {
90                 return $this->_customPaging;
91         }
92
93         /**
94          * @param boolean whether to allow custom paging
95          */
96         public function setCustomPaging($value)
97         {
98                 $this->_customPaging=TPropertyValue::ensureBoolean($value);
99         }
100
101         /**
102          * @return integer number of items in each page. Defaults to 10.
103          */
104         public function getPageSize()
105         {
106                 return $this->_pageSize;
107         }
108
109         /**
110          * @param integer number of items in each page
111          */
112         public function setPageSize($value)
113         {
114                 if(($value=TPropertyValue::ensureInteger($value))>0)
115                         $this->_pageSize=$value;
116                 else
117                         throw new TInvalidDataValueException('pagedlist_pagesize_invalid');
118         }
119
120         /**
121          * @return integer current page index. Defaults to 0.
122          */
123         public function getCurrentPageIndex()
124         {
125                 return $this->_currentPageIndex;
126         }
127
128         /**
129          * @param integer current page index
130          * @throws TInvalidDataValueException if the page index is out of range
131          */
132         public function setCurrentPageIndex($value)
133         {
134                 if($this->gotoPage($value=TPropertyValue::ensureInteger($value))===false)
135                         throw new TInvalidDataValueException('pagedlist_currentpageindex_invalid');
136         }
137
138         /**
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
142          */
143         public function onPageIndexChanged($param)
144         {
145                 $this->raiseEvent('OnPageIndexChanged',$this,$param);
146         }
147
148         /**
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
154          */
155         public function onFetchData($param)
156         {
157                 $this->raiseEvent('OnFetchData',$this,$param);
158         }
159
160         /**
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.
164          */
165         public function gotoPage($pageIndex)
166         {
167                 if($pageIndex===$this->_currentPageIndex)
168                         return $pageIndex;
169                 if($this->_customPaging)
170                 {
171                         if($pageIndex>=0 && ($this->_virtualCount<0 || $pageIndex<$this->getPageCount()))
172                         {
173                                 $param=new TPagedListFetchDataEventParameter($pageIndex,$this->_pageSize*$pageIndex,$this->_pageSize);
174                                 $this->onFetchData($param);
175                                 if(($data=$param->getData())!==null)
176                                 {
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));
183                                         return $pageIndex;
184                                 }
185                                 else
186                                         return false;
187                         }
188                         else
189                                 return false;
190                 }
191                 else
192                 {
193                         if($pageIndex>=0 && $pageIndex<$this->getPageCount())
194                         {
195                                 $this->_currentPageIndex=$pageIndex;
196                                 $this->onPageIndexChanged(null);
197                                 return $pageIndex;
198                         }
199                         else
200                                 return false;
201                 }
202         }
203
204         /**
205          * Switches to the next page.
206          * @return integer|boolean the new page index, false if next page is not available.
207          */
208         public function nextPage()
209         {
210                 return $this->gotoPage($this->_currentPageIndex+1);
211         }
212
213         /**
214          * Switches to the previous page.
215          * @return integer|boolean the new page index, false if previous page is not available.
216          */
217         public function previousPage()
218         {
219                 return $this->gotoPage($this->_currentPageIndex-1);
220         }
221
222         /**
223          * @return integer user-assigned number of items in data source. Defaults to 0.
224          */
225         public function getVirtualCount()
226         {
227                 return $this->_virtualCount;
228         }
229
230         /**
231          * @param integer user-assigned number of items in data source
232          */
233         public function setVirtualCount($value)
234         {
235                 if(($value=TPropertyValue::ensureInteger($value))<0)
236                         $value=-1;
237                 $this->_virtualCount=$value;
238         }
239
240         /**
241          * @return integer number of pages, -1 if under custom paging mode and {@link setVirtualCount VirtualCount} is not set.
242          */
243         public function getPageCount()
244         {
245                 if($this->_customPaging)
246                 {
247                         if($this->_virtualCount>=0)
248                                 return (int)(($this->_virtualCount+$this->_pageSize-1)/$this->_pageSize);
249                         else
250                                 return -1;
251                 }
252                 else
253                         return (int)((parent::getCount()+$this->_pageSize-1)/$this->_pageSize);
254         }
255
256         /**
257          * @return boolean whether the current page is the first page
258          */
259         public function getIsFirstPage()
260         {
261                 return $this->_currentPageIndex===0;
262         }
263
264         /**
265          * @return boolean whether the current page is the last page
266          */
267         public function getIsLastPage()
268         {
269                 return $this->_currentPageIndex===$this->getPageCount()-1;
270         }
271
272         /**
273          * @return integer the number of items in current page
274          */
275         public function getCount()
276         {
277                 if($this->_customPaging)
278                         return parent::getCount();
279                 else
280                 {
281                         if($this->_currentPageIndex===$this->getPageCount()-1)
282                                 return parent::getCount()-$this->_pageSize*$this->_currentPageIndex;
283                         else
284                                 return $this->_pageSize;
285                 }
286         }
287
288         /**
289          * @return Iterator iterator
290          */
291         public function getIterator()
292         {
293                 if($this->_customPaging)
294                         return parent::getIterator();
295                 else
296                 {
297                         $data=$this->toArray();
298                         return new ArrayIterator($data);
299                 }
300         }
301
302         /**
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
308          */
309         public function itemAt($index)
310         {
311                 if($this->_customPaging)
312                         return parent::itemAt($index);
313                 else
314                         return parent::itemAt($this->_pageSize*$this->_currentPageIndex+$index);
315         }
316
317         /**
318          * @param mixed the item
319          * @return integer the index of the item in the list (0 based), -1 if not found.
320          */
321         public function indexOf($item)
322         {
323                 $c=$this->getCount();
324                 for($i=0;$i<$c;++$i)
325                         if($this->itemAt($i)===$item)
326                                 return $i;
327                 return -1;
328         }
329
330         /**
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
334          * @return boolean
335          */
336         public function offsetExists($offset)
337         {
338                 return ($offset>=0 && $offset<$this->getCount());
339         }
340
341         /**
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
347          */
348         public function offsetGet($offset)
349         {
350                 return $this->itemAt($offset);
351         }
352
353         /**
354          * @return array the list of items in array
355          */
356         public function toArray()
357         {
358                 $c=$this->getCount();
359                 $array=array();
360                 for($i=0;$i<$c;++$i)
361                         $array[$i]=$this->itemAt($i);
362                 return $array;
363         }
364 }
365
366 /**
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}.
371  *
372  * @author Qiang Xue <qiang.xue@gmail.com>
373  * @package System.Collections
374  * @since 3.0
375  */
376 class TPagedListPageChangedEventParameter extends TEventParameter
377 {
378         private $_oldPage;
379
380         /**
381          * Constructor.
382          * @param integer old page index
383          */
384         public function __construct($oldPage)
385         {
386                 $this->_oldPage=$oldPage;
387         }
388
389         /**
390          * @return integer the index of the page before the list changed to the new page
391          */
392         public function getOldPageIndex()
393         {
394                 return $this->_oldPage;
395         }
396 }
397
398 /**
399  * TPagedListFetchDataEventParameter class.
400  *
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.
408  *
409  * @author Qiang Xue <qiang.xue@gmail.com>
410  * @package System.Collections
411  * @since 3.0
412  */
413 class TPagedListFetchDataEventParameter extends TEventParameter
414 {
415         private $_pageIndex;
416         private $_offset;
417         private $_limit;
418         private $_data=null;
419
420         /**
421          * Constructor.
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
425          */
426         public function __construct($pageIndex,$offset,$limit)
427         {
428                 $this->_pageIndex=$pageIndex;
429                 $this->_offset=$offset;
430                 $this->_limit=$limit;
431         }
432
433         /**
434          * @return integer the zero-based index of the new page
435          */
436         public function getNewPageIndex()
437         {
438                 return $this->_pageIndex;
439         }
440
441         /**
442          * @return integer offset of the first item in the new page
443          */
444         public function getOffset()
445         {
446                 return $this->_offset;
447         }
448
449         /**
450          * @return integer number of items in the new page
451          */
452         public function getLimit()
453         {
454                 return $this->_limit;
455         }
456
457         /**
458          * @return mixed new page data
459          */
460         public function getData()
461         {
462                 return $this->_data;
463         }
464
465         /**
466          * @param mixed new page data
467          */
468         public function setData($value)
469         {
470                 $this->_data=$value;
471         }
472 }
473