/app/Foundation/Paginator.php

https://github.com/jitamin/jitamin · PHP · 496 lines · 203 code · 65 blank · 228 comment · 10 complexity · 07201c0ce829b678f071d7cc89cb640e MD5 · raw file

  1. <?php
  2. /*
  3. * This file is part of Jitamin.
  4. *
  5. * Copyright (C) Jitamin Team
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Jitamin\Foundation;
  11. use PicoDb\Table;
  12. use Pimple\Container;
  13. /**
  14. * Paginator helper.
  15. */
  16. class Paginator
  17. {
  18. /**
  19. * Container instance.
  20. *
  21. * @var \Pimple\Container
  22. */
  23. private $container;
  24. /**
  25. * Total number of items.
  26. *
  27. * @var int
  28. */
  29. private $total = 0;
  30. /**
  31. * Page number.
  32. *
  33. * @var int
  34. */
  35. private $page = 1;
  36. /**
  37. * Offset.
  38. *
  39. * @var int
  40. */
  41. private $offset = 0;
  42. /**
  43. * Limit.
  44. *
  45. * @var int
  46. */
  47. private $limit = 0;
  48. /**
  49. * Sort by this column.
  50. *
  51. * @var string
  52. */
  53. private $order = '';
  54. /**
  55. * Sorting direction.
  56. *
  57. * @var string
  58. */
  59. private $direction = 'ASC';
  60. /**
  61. * Slice of items.
  62. *
  63. * @var array
  64. */
  65. private $items = [];
  66. /**
  67. * PicoDb Table instance.
  68. *
  69. * @var \Picodb\Table
  70. */
  71. private $query = null;
  72. /**
  73. * Controller name.
  74. *
  75. * @var string
  76. */
  77. private $controller = '';
  78. /**
  79. * Action name.
  80. *
  81. * @var string
  82. */
  83. private $action = '';
  84. /**
  85. * Url params.
  86. *
  87. * @var array
  88. */
  89. private $params = [];
  90. /**
  91. * Constructor.
  92. *
  93. * @param \Pimple\Container $container
  94. */
  95. public function __construct(Container $container)
  96. {
  97. $this->container = $container;
  98. }
  99. /**
  100. * Set a PicoDb query.
  101. *
  102. * @param \PicoDb\Table $query
  103. *
  104. * @return Paginator
  105. */
  106. public function setQuery(Table $query)
  107. {
  108. $this->query = $query;
  109. $this->total = $this->query->count();
  110. return $this;
  111. }
  112. /**
  113. * Execute a PicoDb query.
  114. *
  115. * @return array
  116. */
  117. public function executeQuery()
  118. {
  119. if ($this->query !== null) {
  120. return $this->query
  121. ->offset($this->offset)
  122. ->limit($this->limit)
  123. ->orderBy($this->order, $this->direction)
  124. ->findAll();
  125. }
  126. return [];
  127. }
  128. /**
  129. * Set url parameters.
  130. *
  131. * @param string $controller
  132. * @param string $action
  133. * @param array $params
  134. *
  135. * @return Paginator
  136. */
  137. public function setUrl($controller, $action, array $params = [])
  138. {
  139. $this->controller = $controller;
  140. $this->action = $action;
  141. $this->params = $params;
  142. return $this;
  143. }
  144. /**
  145. * Add manually items.
  146. *
  147. * @param array $items
  148. *
  149. * @return Paginator
  150. */
  151. public function setCollection(array $items)
  152. {
  153. $this->items = $items;
  154. return $this;
  155. }
  156. /**
  157. * Return the items.
  158. *
  159. * @return array
  160. */
  161. public function getCollection()
  162. {
  163. return $this->items ?: $this->executeQuery();
  164. }
  165. /**
  166. * Set the total number of items.
  167. *
  168. * @param int $total
  169. *
  170. * @return Paginator
  171. */
  172. public function setTotal($total)
  173. {
  174. $this->total = $total;
  175. return $this;
  176. }
  177. /**
  178. * Get the total number of items.
  179. *
  180. * @return int
  181. */
  182. public function getTotal()
  183. {
  184. return $this->total;
  185. }
  186. /**
  187. * Set the default page number.
  188. *
  189. * @param int $page
  190. *
  191. * @return Paginator
  192. */
  193. public function setPage($page)
  194. {
  195. $this->page = $page;
  196. return $this;
  197. }
  198. /**
  199. * Get the number of current page.
  200. *
  201. * @return int
  202. */
  203. public function getPage()
  204. {
  205. return $this->page;
  206. }
  207. /**
  208. * Get the total number of pages.
  209. *
  210. * @return int
  211. */
  212. public function getPageTotal()
  213. {
  214. return ceil($this->getTotal() / $this->getMax());
  215. }
  216. /**
  217. * Set the default column order.
  218. *
  219. * @param string $order
  220. *
  221. * @return Paginator
  222. */
  223. public function setOrder($order)
  224. {
  225. $this->order = $order;
  226. return $this;
  227. }
  228. /**
  229. * Set the default sorting direction.
  230. *
  231. * @param string $direction
  232. *
  233. * @return Paginator
  234. */
  235. public function setDirection($direction)
  236. {
  237. $this->direction = $direction;
  238. return $this;
  239. }
  240. /**
  241. * Set the maximum number of items per page.
  242. *
  243. * @param int $limit
  244. *
  245. * @return Paginator
  246. */
  247. public function setMax($limit)
  248. {
  249. $this->limit = $limit;
  250. return $this;
  251. }
  252. /**
  253. * Get the maximum number of items per page.
  254. *
  255. * @return int
  256. */
  257. public function getMax()
  258. {
  259. return $this->limit;
  260. }
  261. /**
  262. * Return true if the collection is empty.
  263. *
  264. * @return bool
  265. */
  266. public function isEmpty()
  267. {
  268. return $this->total === 0;
  269. }
  270. /**
  271. * Execute the offset calculation only if the $condition is true.
  272. *
  273. * @param bool $condition
  274. *
  275. * @return Paginator
  276. */
  277. public function calculateOnlyIf($condition)
  278. {
  279. if ($condition) {
  280. $this->calculate();
  281. }
  282. return $this;
  283. }
  284. /**
  285. * Calculate the offset value accoring to url params and the page number.
  286. *
  287. * @return Paginator
  288. */
  289. public function calculate()
  290. {
  291. $this->page = $this->container['request']->getIntegerParam('page', 1);
  292. $this->direction = $this->container['request']->getStringParam('direction', $this->direction);
  293. $this->order = $this->container['request']->getStringParam('order', $this->order);
  294. if ($this->page < 1) {
  295. $this->page = 1;
  296. }
  297. $this->offset = (int) (($this->page - 1) * $this->limit);
  298. return $this;
  299. }
  300. /**
  301. * Generation pagination links.
  302. *
  303. * @return string
  304. */
  305. public function toHtml()
  306. {
  307. $html = '';
  308. if (!$this->hasNothingtoShow()) {
  309. $html .= '<div class="pagination">';
  310. $html .= $this->generatPageShowing();
  311. $html .= $this->generatePreviousLink();
  312. $html .= $this->generateNextLink();
  313. $html .= '</div>';
  314. }
  315. return $html;
  316. }
  317. /**
  318. * Magic method to output pagination links.
  319. *
  320. * @return string
  321. */
  322. public function __toString()
  323. {
  324. return $this->toHtml();
  325. }
  326. /**
  327. * Column sorting.
  328. *
  329. * @param string $label Column title
  330. * @param string $column SQL column name
  331. *
  332. * @return string
  333. */
  334. public function order($label, $column)
  335. {
  336. $prefix = '';
  337. $direction = 'ASC';
  338. if ($this->order === $column) {
  339. $prefix = $this->direction === 'DESC' ? '&#9660; ' : '&#9650; ';
  340. $direction = $this->direction === 'DESC' ? 'ASC' : 'DESC';
  341. }
  342. return $prefix.$this->container['helper']->url->link(
  343. $label,
  344. $this->controller,
  345. $this->action,
  346. $this->getUrlParams($this->page, $column, $direction)
  347. );
  348. }
  349. /**
  350. * Get url params for link generation.
  351. *
  352. * @param int $page
  353. * @param string $order
  354. * @param string $direction
  355. *
  356. * @return string
  357. */
  358. protected function getUrlParams($page, $order, $direction)
  359. {
  360. $params = [
  361. 'page' => $page,
  362. 'order' => $order,
  363. 'direction' => $direction,
  364. ];
  365. return array_merge($this->params, $params);
  366. }
  367. /**
  368. * Generate the previous link.
  369. *
  370. * @return string
  371. */
  372. protected function generatePreviousLink()
  373. {
  374. $html = '<span class="pagination-previous">';
  375. if ($this->offset > 0) {
  376. $html .= $this->container['helper']->url->link(
  377. '&laquo; '.t('Previous'),
  378. $this->controller,
  379. $this->action,
  380. $this->getUrlParams($this->page - 1, $this->order, $this->direction),
  381. false,
  382. 'btn btn-info'
  383. );
  384. } else {
  385. $html .= '<span class="btn btn-default">&laquo; '.t('Previous').'</span>';
  386. }
  387. $html .= '</span>';
  388. return $html;
  389. }
  390. /**
  391. * Generate the next link.
  392. *
  393. * @return string
  394. */
  395. protected function generateNextLink()
  396. {
  397. $html = '<span class="pagination-next">';
  398. if (($this->total - $this->offset) > $this->limit) {
  399. $html .= $this->container['helper']->url->link(
  400. t('Next').' &raquo;',
  401. $this->controller,
  402. $this->action,
  403. $this->getUrlParams($this->page + 1, $this->order, $this->direction),
  404. false,
  405. 'btn btn-info'
  406. );
  407. } else {
  408. $html .= '<span class="btn btn-default">'.t('Next').' &raquo;</span>';
  409. }
  410. $html .= '</span>';
  411. return $html;
  412. }
  413. /**
  414. * Generate the page showing.
  415. *
  416. * @return string
  417. */
  418. protected function generatPageShowing()
  419. {
  420. return '<span class="pagination-showing">'.t('Showing %d-%d of %d', (($this->getPage() - 1) * $this->getMax() + 1), min($this->getTotal(), $this->getPage() * $this->getMax()), $this->getTotal()).'</span>';
  421. }
  422. /**
  423. * Return true if there is no pagination to show.
  424. *
  425. * @return bool
  426. */
  427. protected function hasNothingtoShow()
  428. {
  429. return $this->offset === 0 && ($this->total - $this->offset) <= $this->limit;
  430. }
  431. }