Subversion-Projekte lars-tiefland.prado

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
/**
3
 * TPagedList, TPagedListFetchDataEventParameter, TPagedListPageChangedEventParameter class file
4
 *
5
 * @author Qiang Xue <qiang.xue@gmail.com>
6
 * @link http://www.pradosoft.com/
7
 * @copyright Copyright &copy; 2005-2008 PradoSoft
8
 * @license http://www.pradosoft.com/license/
9
 * @version $Id: TPagedList.php 2541 2008-10-21 15:05:13Z qiang.xue $
10
 * @package System.Collections
11
 */
12
 
13
/**
14
 * TPagedList class
15
 *
16
 * TPagedList implements a list with paging functionality.
17
 *
18
 * TPagedList works in one of two modes, managed paging or customized paging,
19
 * specified by {@link setCustomPaging CustomPaging}.
20
 * - Managed paging ({@link setCustomPaging CustomPaging}=false) :
21
 *   the list is assumed to contain all data and it will manage which page
22
 *   of data are available to user.
23
 * - Customized paging ({@link setCustomPaging CustomPaging}=true) :
24
 *   the list is assumed to contain only one page of data. An  {@link onFetchData OnFetchData}
25
 *   event will be raised if the list changes to a different page.
26
 *   Developers can attach a handler to the event and supply the needed data.
27
 *   The event handler can be written as follows,
28
 * <code>
29
 *  public function fetchData($sender,$param)
30
 *  {
31
 *    $offset=$param->Offset; // beginning index of the data needed
32
 *    $limit=$param->Limit;   // maximum number of data items needed
33
 *    // get data according to the above two parameters
34
 *    $param->Data=$data;
35
 *  }
36
 * </code>
37
 *
38
 * Data in TPagedList can be accessed like an integer-indexed array and can
39
 * be traversed using foreach. For example,
40
 * <code>
41
 * $count=$list->Count;
42
 * for($index=0;$index<$count;++$index)
43
 *     echo $list[$index];
44
 * foreach($list as $index=>$item) // traverse each item in the list
45
 * </code>
46
 *
47
 * The {@link setPageSize PageSize} property specifies the number of items in each page.
48
 * To access different page of data in the list, set {@link setCurrentPageIndex CurrentPageIndex}
49
 * or call {@link nextPage()}, {@link previousPage()}, or {@link gotoPage()}.
50
 * The total number of pages can be obtained by {@link getPageCount() PageCount}.
51
 *
52
 *
53
 * @author Qiang Xue <qiang.xue@gmail.com>
54
 * @version $Id: TPagedList.php 2541 2008-10-21 15:05:13Z qiang.xue $
55
 * @package System.Collections
56
 * @since 3.0
57
 */
58
class TPagedList extends TList
59
{
60
	/**
61
	 * @var boolean whether to allow custom paging
62
	 */
63
	private $_customPaging=false;
64
	/**
65
	 * @var integer number of items in each page
66
	 */
67
	private $_pageSize=10;
68
	/**
69
	 * @var integer current page index
70
	 */
71
	private $_currentPageIndex=-1;
72
	/**
73
	 * @var integer user-assigned number of items in data source
74
	 */
75
	private $_virtualCount=-1;
76
 
77
	/**
78
	 * Constructor.
79
	 * @param array|Iterator the initial data. Default is null, meaning no initialization.
80
	 * @param boolean whether the list is read-only. Always true for paged list.
81
	 */
82
	public function __construct($data=null,$readOnly=false)
83
	{
84
		parent::__construct($data,true);
85
	}
86
 
87
	/**
88
	 * @return boolean whether to use custom paging. Defaults to false.
89
	 */
90
	public function getCustomPaging()
91
	{
92
		return $this->_customPaging;
93
	}
94
 
95
	/**
96
	 * @param boolean whether to allow custom paging
97
	 */
98
	public function setCustomPaging($value)
99
	{
100
		$this->_customPaging=TPropertyValue::ensureBoolean($value);
101
	}
102
 
103
	/**
104
	 * @return integer number of items in each page. Defaults to 10.
105
	 */
106
	public function getPageSize()
107
	{
108
		return $this->_pageSize;
109
	}
110
 
111
	/**
112
	 * @param integer number of items in each page
113
	 */
114
	public function setPageSize($value)
115
	{
116
		if(($value=TPropertyValue::ensureInteger($value))>0)
117
			$this->_pageSize=$value;
118
		else
119
			throw new TInvalidDataValueException('pagedlist_pagesize_invalid');
120
	}
121
 
122
	/**
123
	 * @return integer current page index. Defaults to 0.
124
	 */
125
	public function getCurrentPageIndex()
126
	{
127
		return $this->_currentPageIndex;
128
	}
129
 
130
	/**
131
	 * @param integer current page index
132
	 * @throws TInvalidDataValueException if the page index is out of range
133
	 */
134
	public function setCurrentPageIndex($value)
135
	{
136
		if($this->gotoPage($value=TPropertyValue::ensureInteger($value))===false)
137
			throw new TInvalidDataValueException('pagedlist_currentpageindex_invalid');
138
	}
139
 
140
	/**
141
	 * Raises <b>OnPageIndexChanged</b> event.
142
	 * This event is raised each time when the list changes to a different page.
143
	 * @param TPagedListPageChangedEventParameter event parameter
144
	 */
145
	public function onPageIndexChanged($param)
146
	{
147
		$this->raiseEvent('OnPageIndexChanged',$this,$param);
148
	}
149
 
150
	/**
151
	 * Raises <b>OnFetchData</b> event.
152
	 * This event is raised each time when the list changes to a different page
153
	 * and needs the new page of data. This event can only be raised when
154
	 * {@link setCustomPaging CustomPaging} is true.
155
	 * @param TPagedListFetchDataEventParameter event parameter
156
	 */
157
	public function onFetchData($param)
158
	{
159
		$this->raiseEvent('OnFetchData',$this,$param);
160
	}
161
 
162
	/**
163
	 * Changes to a page with the specified page index.
164
	 * @param integer page index
165
	 * @return integer|boolean the new page index, false if page index is out of range.
166
	 */
167
	public function gotoPage($pageIndex)
168
	{
169
		if($pageIndex===$this->_currentPageIndex)
170
			return $pageIndex;
171
		if($this->_customPaging)
172
		{
173
			if($pageIndex>=0 && ($this->_virtualCount<0 || $pageIndex<$this->getPageCount()))
174
			{
175
				$param=new TPagedListFetchDataEventParameter($pageIndex,$this->_pageSize*$pageIndex,$this->_pageSize);
176
				$this->onFetchData($param);
177
				if(($data=$param->getData())!==null)
178
				{
179
					$this->setReadOnly(false);
180
					$this->copyFrom($data);
181
					$this->setReadOnly(true);
182
					$oldPage=$this->_currentPageIndex;
183
					$this->_currentPageIndex=$pageIndex;
184
					$this->onPageIndexChanged(new TPagedListPageChangedEventParameter($oldPage));
185
					return $pageIndex;
186
				}
187
				else
188
					return false;
189
			}
190
			else
191
				return false;
192
		}
193
		else
194
		{
195
			if($pageIndex>=0 && $pageIndex<$this->getPageCount())
196
			{
197
				$this->_currentPageIndex=$pageIndex;
198
				$this->onPageIndexChanged(null);
199
				return $pageIndex;
200
			}
201
			else
202
				return false;
203
		}
204
	}
205
 
206
	/**
207
	 * Switches to the next page.
208
	 * @return integer|boolean the new page index, false if next page is not available.
209
	 */
210
	public function nextPage()
211
	{
212
		return $this->gotoPage($this->_currentPageIndex+1);
213
	}
214
 
215
	/**
216
	 * Switches to the previous page.
217
	 * @return integer|boolean the new page index, false if previous page is not available.
218
	 */
219
	public function previousPage()
220
	{
221
		return $this->gotoPage($this->_currentPageIndex-1);
222
	}
223
 
224
	/**
225
	 * @return integer user-assigned number of items in data source. Defaults to 0.
226
	 */
227
	public function getVirtualCount()
228
	{
229
		return $this->_virtualCount;
230
	}
231
 
232
	/**
233
	 * @param integer user-assigned number of items in data source
234
	 */
235
	public function setVirtualCount($value)
236
	{
237
		if(($value=TPropertyValue::ensureInteger($value))<0)
238
			$value=-1;
239
		$this->_virtualCount=$value;
240
	}
241
 
242
	/**
243
	 * @return integer number of pages, -1 if under custom paging mode and {@link setVirtualCount VirtualCount} is not set.
244
	 */
245
	public function getPageCount()
246
	{
247
		if($this->_customPaging)
248
		{
249
			if($this->_virtualCount>=0)
250
				return (int)(($this->_virtualCount+$this->_pageSize-1)/$this->_pageSize);
251
			else
252
				return -1;
253
		}
254
		else
255
			return (int)((parent::getCount()+$this->_pageSize-1)/$this->_pageSize);
256
	}
257
 
258
	/**
259
	 * @return boolean whether the current page is the first page
260
	 */
261
	public function getIsFirstPage()
262
	{
263
		return $this->_currentPageIndex===0;
264
	}
265
 
266
	/**
267
	 * @return boolean whether the current page is the last page
268
	 */
269
	public function getIsLastPage()
270
	{
271
		return $this->_currentPageIndex===$this->getPageCount()-1;
272
	}
273
 
274
	/**
275
	 * @return integer the number of items in current page
276
	 */
277
	public function getCount()
278
	{
279
		if($this->_customPaging)
280
			return parent::getCount();
281
		else
282
		{
283
			if($this->_currentPageIndex===$this->getPageCount()-1)
284
				return parent::getCount()-$this->_pageSize*$this->_currentPageIndex;
285
			else
286
				return $this->_pageSize;
287
		}
288
	}
289
 
290
	/**
291
	 * @return Iterator iterator
292
	 */
293
	public function getIterator()
294
	{
295
		if($this->_customPaging)
296
			return parent::getIterator();
297
		else
298
		{
299
			$data=$this->toArray();
300
			return new TListIterator($data);
301
		}
302
	}
303
 
304
	/**
305
	 * Returns the item at the specified offset.
306
	 * This method is exactly the same as {@link offsetGet}.
307
	 * @param integer the index of the item
308
	 * @return mixed the item at the index
309
	 * @throws TInvalidDataValueException if the index is out of the range
310
	 */
311
	public function itemAt($index)
312
	{
313
		if($this->_customPaging)
314
			return parent::itemAt($index);
315
		else
316
			return parent::itemAt($this->_pageSize*$this->_currentPageIndex+$index);
317
	}
318
 
319
	/**
320
	 * @param mixed the item
321
	 * @return integer the index of the item in the list (0 based), -1 if not found.
322
	 */
323
	public function indexOf($item)
324
	{
325
		$c=$this->getCount();
326
		for($i=0;$i<$c;++$i)
327
			if($this->itemAt($i)===$item)
328
				return $i;
329
		return -1;
330
	}
331
 
332
	/**
333
	 * Returns whether there is an item at the specified offset.
334
	 * This method is required by the interface ArrayAccess.
335
	 * @param integer the offset to check on
336
	 * @return boolean
337
	 */
338
	public function offsetExists($offset)
339
	{
340
		return ($offset>=0 && $offset<$this->getCount());
341
	}
342
 
343
	/**
344
	 * Returns the item at the specified offset.
345
	 * This method is required by the interface ArrayAccess.
346
	 * @param integer the offset to retrieve item.
347
	 * @return mixed the item at the offset
348
	 * @throws TInvalidDataValueException if the offset is invalid
349
	 */
350
	public function offsetGet($offset)
351
	{
352
		return $this->itemAt($offset);
353
	}
354
 
355
	/**
356
	 * @return array the list of items in array
357
	 */
358
	public function toArray()
359
	{
360
		$c=$this->getCount();
361
		$array=array();
362
		for($i=0;$i<$c;++$i)
363
			$array[$i]=$this->itemAt($i);
364
		return $array;
365
	}
366
}
367
 
368
/**
369
 * TPagedListPageChangedEventParameter class.
370
 * TPagedListPageChangedEventParameter is used as the parameter for
371
 * {@link TPagedList::onPageChanged OnPageChanged} event.
372
 * To obtain the page index before it was changed, use {@link getOldPageIndex OldPageIndex}.
373
 *
374
 * @author Qiang Xue <qiang.xue@gmail.com>
375
 * @version $Id: TPagedList.php 2541 2008-10-21 15:05:13Z qiang.xue $
376
 * @package System.Collections
377
 * @since 3.0
378
 */
379
class TPagedListPageChangedEventParameter extends TEventParameter
380
{
381
	private $_oldPage;
382
 
383
	/**
384
	 * Constructor.
385
	 * @param integer old page index
386
	 */
387
	public function __construct($oldPage)
388
	{
389
		$this->_oldPage=$oldPage;
390
	}
391
 
392
	/**
393
	 * @return integer the index of the page before the list changed to the new page
394
	 */
395
	public function getOldPageIndex()
396
	{
397
		return $this->_oldPage;
398
	}
399
}
400
 
401
/**
402
 * TPagedListFetchDataEventParameter class.
403
 *
404
 * TPagedListFetchDataEventParameter is used as the parameter for
405
 * {@link TPagedList::onFetchData OnFetchData} event.
406
 * To obtain the new page index, use {@link getNewPageIndex NewPageIndex}.
407
 * The {@link getOffset Offset} property refers to the index
408
 * of the first item in the new page, while {@link getLimit Limit}
409
 * specifies how many items are requested for the page.
410
 * Newly fetched data should be saved in {@link setData Data} property.
411
 *
412
 * @author Qiang Xue <qiang.xue@gmail.com>
413
 * @version $Id: TPagedList.php 2541 2008-10-21 15:05:13Z qiang.xue $
414
 * @package System.Collections
415
 * @since 3.0
416
 */
417
class TPagedListFetchDataEventParameter extends TEventParameter
418
{
419
	private $_pageIndex;
420
	private $_offset;
421
	private $_limit;
422
	private $_data=null;
423
 
424
	/**
425
	 * Constructor.
426
	 * @param integer new page index
427
	 * @param integer offset of the first item in the new page
428
	 * @param integer number of items in the new page desired
429
	 */
430
	public function __construct($pageIndex,$offset,$limit)
431
	{
432
		$this->_pageIndex=$pageIndex;
433
		$this->_offset=$offset;
434
		$this->_limit=$limit;
435
	}
436
 
437
	/**
438
	 * @return integer the zero-based index of the new page
439
	 */
440
	public function getNewPageIndex()
441
	{
442
		return $this->_pageIndex;
443
	}
444
 
445
	/**
446
	 * @return integer offset of the first item in the new page
447
	 */
448
	public function getOffset()
449
	{
450
		return $this->_offset;
451
	}
452
 
453
	/**
454
	 * @return integer number of items in the new page
455
	 */
456
	public function getLimit()
457
	{
458
		return $this->_limit;
459
	}
460
 
461
	/**
462
	 * @return mixed new page data
463
	 */
464
	public function getData()
465
	{
466
		return $this->_data;
467
	}
468
 
469
	/**
470
	 * @param mixed new page data
471
	 */
472
	public function setData($value)
473
	{
474
		$this->_data=$value;
475
	}
476
}
477