Pagination.php 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. <?php
  2. /**
  3. * @link http://www.yiiframework.com/
  4. * @copyright Copyright (c) 2008 Yii Software LLC
  5. * @license http://www.yiiframework.com/license/
  6. */
  7. namespace yii\data;
  8. use Yii;
  9. use yii\base\Object;
  10. use yii\web\Request;
  11. /**
  12. * Pagination represents information relevant to pagination of data items.
  13. *
  14. * When data needs to be rendered in multiple pages, Pagination can be used to
  15. * represent information such as [[totalCount|total item count]], [[pageSize|page size]],
  16. * [[page|current page]], etc. These information can be passed to [[yii\widgets\Pager|pagers]]
  17. * to render pagination buttons or links.
  18. *
  19. * The following example shows how to create a pagination object and feed it
  20. * to a pager.
  21. *
  22. * Controller action:
  23. *
  24. * ~~~
  25. * function actionIndex()
  26. * {
  27. * $query = Article::find()->where(['status' => 1]);
  28. * $countQuery = clone $query;
  29. * $pages = new Pagination(['totalCount' => $countQuery->count()]);
  30. * $models = $query->offset($pages->offset)
  31. * ->limit($pages->limit)
  32. * ->all();
  33. *
  34. * return $this->render('index', [
  35. * 'models' => $models,
  36. * 'pages' => $pages,
  37. * ]);
  38. * }
  39. * ~~~
  40. *
  41. * View:
  42. *
  43. * ~~~
  44. * foreach ($models as $model) {
  45. * // display $model here
  46. * }
  47. *
  48. * // display pagination
  49. * echo LinkPager::widget([
  50. * 'pagination' => $pages,
  51. * ]);
  52. * ~~~
  53. *
  54. * @property integer $limit The limit of the data. This may be used to set the LIMIT value for a SQL statement
  55. * for fetching the current page of data. Note that if the page size is infinite, a value -1 will be returned.
  56. * This property is read-only.
  57. * @property integer $offset The offset of the data. This may be used to set the OFFSET value for a SQL
  58. * statement for fetching the current page of data. This property is read-only.
  59. * @property integer $page The zero-based current page number.
  60. * @property integer $pageCount Number of pages. This property is read-only.
  61. *
  62. * @author Qiang Xue <[email protected]>
  63. * @since 2.0
  64. */
  65. class Pagination extends Object
  66. {
  67. /**
  68. * @var string name of the parameter storing the current page index. Defaults to 'page'.
  69. * @see params
  70. */
  71. public $pageVar = 'page';
  72. /**
  73. * @var boolean whether to always have the page parameter in the URL created by [[createUrl()]].
  74. * If false and [[page]] is 0, the page parameter will not be put in the URL.
  75. */
  76. public $forcePageVar = true;
  77. /**
  78. * @var string the route of the controller action for displaying the paged contents.
  79. * If not set, it means using the currently requested route.
  80. */
  81. public $route;
  82. /**
  83. * @var array parameters (name => value) that should be used to obtain the current page number
  84. * and to create new pagination URLs. If not set, all parameters from $_GET will be used instead.
  85. *
  86. * In order to add hash to all links use `array_merge($_GET, ['#' => 'my-hash'])`.
  87. *
  88. * The array element indexed by [[pageVar]] is considered to be the current page number.
  89. * If the element does not exist, the current page number is considered 0.
  90. */
  91. public $params;
  92. /**
  93. * @var \yii\web\UrlManager the URL manager used for creating pagination URLs. If not set,
  94. * the "urlManager" application component will be used.
  95. */
  96. public $urlManager;
  97. /**
  98. * @var boolean whether to check if [[page]] is within valid range.
  99. * When this property is true, the value of [[page]] will always be between 0 and ([[pageCount]]-1).
  100. * Because [[pageCount]] relies on the correct value of [[totalCount]] which may not be available
  101. * in some cases (e.g. MongoDB), you may want to set this property to be false to disable the page
  102. * number validation. By doing so, [[page]] will return the value indexed by [[pageVar]] in [[params]].
  103. */
  104. public $validatePage = true;
  105. /**
  106. * @var integer number of items on each page. Defaults to 20.
  107. * If it is less than 1, it means the page size is infinite, and thus a single page contains all items.
  108. */
  109. public $pageSize = 20;
  110. /**
  111. * @var integer total number of items.
  112. */
  113. public $totalCount = 0;
  114. /**
  115. * @return integer number of pages
  116. */
  117. public function getPageCount()
  118. {
  119. if ($this->pageSize < 1) {
  120. return $this->totalCount > 0 ? 1 : 0;
  121. } else {
  122. $totalCount = $this->totalCount < 0 ? 0 : (int)$this->totalCount;
  123. return (int)(($totalCount + $this->pageSize - 1) / $this->pageSize);
  124. }
  125. }
  126. private $_page;
  127. /**
  128. * Returns the zero-based current page number.
  129. * @param boolean $recalculate whether to recalculate the current page based on the page size and item count.
  130. * @return integer the zero-based current page number.
  131. */
  132. public function getPage($recalculate = false)
  133. {
  134. if ($this->_page === null || $recalculate) {
  135. if (($params = $this->params) === null) {
  136. $request = Yii::$app->getRequest();
  137. $params = $request instanceof Request ? $request->get() : [];
  138. }
  139. if (isset($params[$this->pageVar]) && is_scalar($params[$this->pageVar])) {
  140. $this->_page = (int)$params[$this->pageVar] - 1;
  141. if ($this->validatePage) {
  142. $pageCount = $this->getPageCount();
  143. if ($this->_page >= $pageCount) {
  144. $this->_page = $pageCount - 1;
  145. }
  146. }
  147. if ($this->_page < 0) {
  148. $this->_page = 0;
  149. }
  150. } else {
  151. $this->_page = 0;
  152. }
  153. }
  154. return $this->_page;
  155. }
  156. /**
  157. * Sets the current page number.
  158. * @param integer $value the zero-based index of the current page.
  159. */
  160. public function setPage($value)
  161. {
  162. $this->_page = $value;
  163. }
  164. /**
  165. * Creates the URL suitable for pagination with the specified page number.
  166. * This method is mainly called by pagers when creating URLs used to perform pagination.
  167. * @param integer $page the zero-based page number that the URL should point to.
  168. * @param boolean $absolute whether to create an absolute URL. Defaults to `false`.
  169. * @return string the created URL
  170. * @see params
  171. * @see forcePageVar
  172. */
  173. public function createUrl($page, $absolute = false)
  174. {
  175. if (($params = $this->params) === null) {
  176. $request = Yii::$app->getRequest();
  177. $params = $request instanceof Request ? $request->get() : [];
  178. }
  179. if ($page > 0 || $page >= 0 && $this->forcePageVar) {
  180. $params[$this->pageVar] = $page + 1;
  181. } else {
  182. unset($params[$this->pageVar]);
  183. }
  184. $route = $this->route === null ? Yii::$app->controller->getRoute() : $this->route;
  185. $urlManager = $this->urlManager === null ? Yii::$app->getUrlManager() : $this->urlManager;
  186. if ($absolute) {
  187. return $urlManager->createAbsoluteUrl($route, $params);
  188. } else {
  189. return $urlManager->createUrl($route, $params);
  190. }
  191. }
  192. /**
  193. * @return integer the offset of the data. This may be used to set the
  194. * OFFSET value for a SQL statement for fetching the current page of data.
  195. */
  196. public function getOffset()
  197. {
  198. return $this->pageSize < 1 ? 0 : $this->getPage() * $this->pageSize;
  199. }
  200. /**
  201. * @return integer the limit of the data. This may be used to set the
  202. * LIMIT value for a SQL statement for fetching the current page of data.
  203. * Note that if the page size is infinite, a value -1 will be returned.
  204. */
  205. public function getLimit()
  206. {
  207. return $this->pageSize < 1 ? -1 : $this->pageSize;
  208. }
  209. }