1: <?php
2: /**
3: * CPagination class file.
4: *
5: * @author Qiang Xue <qiang.xue@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: * CPagination represents information relevant to pagination.
13: *
14: * When data needs to be rendered in multiple pages, we can use CPagination to
15: * represent information such as {@link getItemCount total item count},
16: * {@link getPageSize page size}, {@link getCurrentPage current page}, etc.
17: * These information can be passed to {@link CBasePager pagers} to render
18: * pagination buttons or links.
19: *
20: * Example:
21: *
22: * Controller action:
23: * <pre>
24: * function actionIndex(){
25: * $criteria=new CDbCriteria();
26: * $count=Article::model()->count($criteria);
27: * $pages=new CPagination($count);
28: *
29: * // results per page
30: * $pages->pageSize=10;
31: * $pages->applyLimit($criteria);
32: * $models=Article::model()->findAll($criteria);
33: *
34: * $this->render('index', array(
35: * 'models' => $models,
36: * 'pages' => $pages
37: * ));
38: * }
39: * </pre>
40: *
41: * View:
42: * <pre>
43: * <?php foreach($models as $model): ?>
44: * // display a model
45: * <?php endforeach; ?>
46: *
47: * // display pagination
48: * <?php $this->widget('CLinkPager', array(
49: * 'pages' => $pages,
50: * )) ?>
51: * </pre>
52: *
53: * @property integer $pageSize Number of items in each page. Defaults to 10.
54: * @property integer $itemCount Total number of items. Defaults to 0.
55: * @property integer $pageCount Number of pages.
56: * @property integer $currentPage The zero-based index of the current page. Defaults to 0.
57: * @property integer $offset The offset of the data. This may be used to set the
58: * OFFSET value for a SQL statement for fetching the current page of data.
59: * @property integer $limit The limit of the data. This may be used to set the
60: * LIMIT value for a SQL statement for fetching the current page of data.
61: * This returns the same value as {@link pageSize}.
62: *
63: * @author Qiang Xue <qiang.xue@gmail.com>
64: * @package system.web
65: * @since 1.0
66: */
67: class CPagination extends CComponent
68: {
69: /**
70: * The default page size.
71: */
72: const DEFAULT_PAGE_SIZE=10;
73: /**
74: * @var string name of the GET variable storing the current page index. Defaults to 'page'.
75: */
76: public $pageVar='page';
77: /**
78: * @var string the route (controller ID and action ID) for displaying the paged contents.
79: * Defaults to empty string, meaning using the current route.
80: */
81: public $route='';
82: /**
83: * @var array of parameters (name=>value) that should be used instead of GET when generating pagination URLs.
84: * Defaults to null, meaning using the currently available GET parameters.
85: */
86: public $params;
87: /**
88: * @var boolean whether to ensure {@link currentPage} is returning a valid page number.
89: * When this property is true, the value returned by {@link currentPage} will always be between
90: * 0 and ({@link pageCount}-1). Because {@link pageCount} relies on the correct value of {@link itemCount},
91: * it means you must have knowledge about the total number of data items when you want to access {@link currentPage}.
92: * This is fine for SQL-based queries, but may not be feasible for other kinds of queries (e.g. MongoDB).
93: * In those cases, you may set this property to be false to skip the validation (you may need to validate yourself then).
94: * Defaults to true.
95: * @since 1.1.4
96: */
97: public $validateCurrentPage=true;
98:
99: private $_pageSize=self::DEFAULT_PAGE_SIZE;
100: private $_itemCount=0;
101: private $_currentPage;
102:
103: /**
104: * Constructor.
105: * @param integer $itemCount total number of items.
106: */
107: public function __construct($itemCount=0)
108: {
109: $this->setItemCount($itemCount);
110: }
111:
112: /**
113: * @return integer number of items in each page. Defaults to 10.
114: */
115: public function getPageSize()
116: {
117: return $this->_pageSize;
118: }
119:
120: /**
121: * @param integer $value number of items in each page
122: */
123: public function setPageSize($value)
124: {
125: if(($this->_pageSize=$value)<=0)
126: $this->_pageSize=self::DEFAULT_PAGE_SIZE;
127: }
128:
129: /**
130: * @return integer total number of items. Defaults to 0.
131: */
132: public function getItemCount()
133: {
134: return $this->_itemCount;
135: }
136:
137: /**
138: * @param integer $value total number of items.
139: */
140: public function setItemCount($value)
141: {
142: if(($this->_itemCount=$value)<0)
143: $this->_itemCount=0;
144: }
145:
146: /**
147: * @return integer number of pages
148: */
149: public function getPageCount()
150: {
151: return (int)(($this->_itemCount+$this->_pageSize-1)/$this->_pageSize);
152: }
153:
154: /**
155: * @param boolean $recalculate whether to recalculate the current page based on the page size and item count.
156: * @return integer the zero-based index of the current page. Defaults to 0.
157: */
158: public function getCurrentPage($recalculate=true)
159: {
160: if($this->_currentPage===null || $recalculate)
161: {
162: if(isset($_GET[$this->pageVar]))
163: {
164: $this->_currentPage=(int)$_GET[$this->pageVar]-1;
165: if($this->validateCurrentPage)
166: {
167: $pageCount=$this->getPageCount();
168: if($this->_currentPage>=$pageCount)
169: $this->_currentPage=$pageCount-1;
170: }
171: if($this->_currentPage<0)
172: $this->_currentPage=0;
173: }
174: else
175: $this->_currentPage=0;
176: }
177: return $this->_currentPage;
178: }
179:
180: /**
181: * @param integer $value the zero-based index of the current page.
182: */
183: public function setCurrentPage($value)
184: {
185: $this->_currentPage=$value;
186: $_GET[$this->pageVar]=$value+1;
187: }
188:
189: /**
190: * Creates the URL suitable for pagination.
191: * This method is mainly called by pagers when creating URLs used to
192: * perform pagination. The default implementation is to call
193: * the controller's createUrl method with the page information.
194: * You may override this method if your URL scheme is not the same as
195: * the one supported by the controller's createUrl method.
196: * @param CController $controller the controller that will create the actual URL
197: * @param integer $page the page that the URL should point to. This is a zero-based index.
198: * @return string the created URL
199: */
200: public function createPageUrl($controller,$page)
201: {
202: $params=$this->params===null ? $_GET : $this->params;
203: if($page>0) // page 0 is the default
204: $params[$this->pageVar]=$page+1;
205: else
206: unset($params[$this->pageVar]);
207: return $controller->createUrl($this->route,$params);
208: }
209:
210: /**
211: * Applies LIMIT and OFFSET to the specified query criteria.
212: * @param CDbCriteria $criteria the query criteria that should be applied with the limit
213: */
214: public function applyLimit($criteria)
215: {
216: $criteria->limit=$this->getLimit();
217: $criteria->offset=$this->getOffset();
218: }
219:
220: /**
221: * @return integer the offset of the data. This may be used to set the
222: * OFFSET value for a SQL statement for fetching the current page of data.
223: * @since 1.1.0
224: */
225: public function getOffset()
226: {
227: return $this->getCurrentPage()*$this->getPageSize();
228: }
229:
230: /**
231: * @return integer the limit of the data. This may be used to set the
232: * LIMIT value for a SQL statement for fetching the current page of data.
233: * This returns the same value as {@link pageSize}.
234: * @since 1.1.0
235: */
236: public function getLimit()
237: {
238: return $this->getPageSize();
239: }
240: }