Pager.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630
  1. <?php
  2. /*
  3. * This file is part of the symfony package.
  4. * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
  5. *
  6. * For the full copyright and license information, please view the LICENSE
  7. * file that was distributed with this source code.
  8. */
  9. namespace Sonata\AdminBundle\Datagrid;
  10. use Sonata\AdminBundle\Model\ModelManagerInterface;
  11. /**
  12. * Pager class.
  13. * @author Fabien Potencier <fabien.potencier@symfony-project.com>
  14. * @author Thomas Rabaix <thomas.rabaix@sonata-project.org>
  15. */
  16. abstract class Pager implements \Iterator, \Countable, \Serializable, PagerInterface
  17. {
  18. protected $page = 1;
  19. protected $maxPerPage = 0;
  20. protected $lastPage = 1;
  21. protected $nbResults = 0;
  22. protected $cursor = 1;
  23. protected $parameters = array();
  24. protected $currentMaxLink = 1;
  25. protected $maxRecordLimit = false;
  26. protected $maxPageLinks = 0;
  27. // used by iterator interface
  28. protected $results = null;
  29. protected $resultsCounter = 0;
  30. protected $query = null;
  31. protected $countColumn = array('id');
  32. /**
  33. * Constructor.
  34. *
  35. * @param integer $maxPerPage Number of records to display per page
  36. */
  37. public function __construct($maxPerPage = 10)
  38. {
  39. $this->setMaxPerPage($maxPerPage);
  40. }
  41. /**
  42. * Returns an array of results on the given page.
  43. *
  44. * @return array
  45. */
  46. abstract public function getResults();
  47. /**
  48. * Returns the current pager's max link.
  49. *
  50. * @return integer
  51. */
  52. public function getCurrentMaxLink()
  53. {
  54. return $this->currentMaxLink;
  55. }
  56. /**
  57. * Returns the current pager's max record limit.
  58. *
  59. * @return integer
  60. */
  61. public function getMaxRecordLimit()
  62. {
  63. return $this->maxRecordLimit;
  64. }
  65. /**
  66. * Sets the current pager's max record limit.
  67. *
  68. * @param integer $limit
  69. */
  70. public function setMaxRecordLimit($limit)
  71. {
  72. $this->maxRecordLimit = $limit;
  73. }
  74. /**
  75. * Returns an array of page numbers to use in pagination links.
  76. *
  77. * @param integer $nb_links The maximum number of page numbers to return
  78. *
  79. * @return array
  80. */
  81. public function getLinks($nb_links = null)
  82. {
  83. if ($nb_links == null) {
  84. $nb_links = $this->getMaxPageLinks();
  85. }
  86. $links = array();
  87. $tmp = $this->page - floor($nb_links / 2);
  88. $check = $this->lastPage - $nb_links + 1;
  89. $limit = $check > 0 ? $check : 1;
  90. $begin = $tmp > 0 ? ($tmp > $limit ? $limit : $tmp) : 1;
  91. $i = (int)$begin;
  92. while ($i < $begin + $nb_links && $i <= $this->lastPage) {
  93. $links[] = $i++;
  94. }
  95. $this->currentMaxLink = count($links) ? $links[count($links) - 1] : 1;
  96. return $links;
  97. }
  98. /**
  99. * Returns true if the current query requires pagination.
  100. *
  101. * @return boolean
  102. */
  103. public function haveToPaginate()
  104. {
  105. return $this->getMaxPerPage() && $this->getNbResults() > $this->getMaxPerPage();
  106. }
  107. /**
  108. * Returns the current cursor.
  109. *
  110. * @return integer
  111. */
  112. public function getCursor()
  113. {
  114. return $this->cursor;
  115. }
  116. /**
  117. * Sets the current cursor.
  118. *
  119. * @param integer $pos
  120. */
  121. public function setCursor($pos)
  122. {
  123. if ($pos < 1) {
  124. $this->cursor = 1;
  125. } else {
  126. if ($pos > $this->nbResults) {
  127. $this->cursor = $this->nbResults;
  128. } else {
  129. $this->cursor = $pos;
  130. }
  131. }
  132. }
  133. /**
  134. * Returns an object by cursor position.
  135. *
  136. * @param integer $pos
  137. *
  138. * @return mixed
  139. */
  140. public function getObjectByCursor($pos)
  141. {
  142. $this->setCursor($pos);
  143. return $this->getCurrent();
  144. }
  145. /**
  146. * Returns the current object.
  147. *
  148. * @return mixed
  149. */
  150. public function getCurrent()
  151. {
  152. return $this->retrieveObject($this->cursor);
  153. }
  154. /**
  155. * Returns the next object.
  156. *
  157. * @return mixed|null
  158. */
  159. public function getNext()
  160. {
  161. if ($this->cursor + 1 > $this->nbResults) {
  162. return null;
  163. } else {
  164. return $this->retrieveObject($this->cursor + 1);
  165. }
  166. }
  167. /**
  168. * Returns the previous object.
  169. *
  170. * @return mixed|null
  171. */
  172. public function getPrevious()
  173. {
  174. if ($this->cursor - 1 < 1) {
  175. return null;
  176. } else {
  177. return $this->retrieveObject($this->cursor - 1);
  178. }
  179. }
  180. /**
  181. * Returns the first index on the current page.
  182. *
  183. * @return integer
  184. */
  185. public function getFirstIndice()
  186. {
  187. if ($this->page == 0) {
  188. return 1;
  189. } else {
  190. return ($this->page - 1) * $this->maxPerPage + 1;
  191. }
  192. }
  193. /**
  194. * Returns the last index on the current page.
  195. *
  196. * @return integer
  197. */
  198. public function getLastIndice()
  199. {
  200. if ($this->page == 0) {
  201. return $this->nbResults;
  202. } else {
  203. if ($this->page * $this->maxPerPage >= $this->nbResults) {
  204. return $this->nbResults;
  205. } else {
  206. return $this->page * $this->maxPerPage;
  207. }
  208. }
  209. }
  210. /**
  211. * Returns the number of results.
  212. *
  213. * @return integer
  214. */
  215. public function getNbResults()
  216. {
  217. return $this->nbResults;
  218. }
  219. /**
  220. * Sets the number of results.
  221. *
  222. * @param integer $nb
  223. */
  224. protected function setNbResults($nb)
  225. {
  226. $this->nbResults = $nb;
  227. }
  228. /**
  229. * Returns the first page number.
  230. *
  231. * @return integer
  232. */
  233. public function getFirstPage()
  234. {
  235. return 1;
  236. }
  237. /**
  238. * Returns the last page number.
  239. *
  240. * @return integer
  241. */
  242. public function getLastPage()
  243. {
  244. return $this->lastPage;
  245. }
  246. /**
  247. * Sets the last page number.
  248. *
  249. * @param integer $page
  250. */
  251. protected function setLastPage($page)
  252. {
  253. $this->lastPage = $page;
  254. if ($this->getPage() > $page) {
  255. $this->setPage($page);
  256. }
  257. }
  258. /**
  259. * Returns the current page.
  260. *
  261. * @return integer
  262. */
  263. public function getPage()
  264. {
  265. return $this->page;
  266. }
  267. /**
  268. * Returns the next page.
  269. *
  270. * @return integer
  271. */
  272. public function getNextPage()
  273. {
  274. return min($this->getPage() + 1, $this->getLastPage());
  275. }
  276. /**
  277. * Returns the previous page.
  278. *
  279. * @return integer
  280. */
  281. public function getPreviousPage()
  282. {
  283. return max($this->getPage() - 1, $this->getFirstPage());
  284. }
  285. /**
  286. * Sets the current page.
  287. *
  288. * @param integer $page
  289. */
  290. public function setPage($page)
  291. {
  292. $this->page = intval($page);
  293. if ($this->page <= 0) {
  294. // set first page, which depends on a maximum set
  295. $this->page = $this->getMaxPerPage() ? 1 : 0;
  296. }
  297. }
  298. /**
  299. * Returns the maximum number of results per page.
  300. *
  301. * @return integer
  302. */
  303. public function getMaxPerPage()
  304. {
  305. return $this->maxPerPage;
  306. }
  307. /**
  308. * Sets the maximum number of results per page.
  309. *
  310. * @param integer $max
  311. */
  312. public function setMaxPerPage($max)
  313. {
  314. if ($max > 0) {
  315. $this->maxPerPage = $max;
  316. if ($this->page == 0) {
  317. $this->page = 1;
  318. }
  319. } else {
  320. if ($max == 0) {
  321. $this->maxPerPage = 0;
  322. $this->page = 0;
  323. } else {
  324. $this->maxPerPage = 1;
  325. if ($this->page == 0) {
  326. $this->page = 1;
  327. }
  328. }
  329. }
  330. }
  331. /**
  332. * Returns the maximum number of page numbers.
  333. *
  334. * @return integer
  335. */
  336. public function getMaxPageLinks()
  337. {
  338. return $this->maxPageLinks;
  339. }
  340. /**
  341. * Sets the maximum number of page numbers.
  342. *
  343. * @param integer $maxPageLinks
  344. */
  345. public function setMaxPageLinks($maxPageLinks)
  346. {
  347. $this->maxPageLinks = $maxPageLinks;
  348. }
  349. /**
  350. * Returns true if on the first page.
  351. *
  352. * @return boolean
  353. */
  354. public function isFirstPage()
  355. {
  356. return 1 == $this->page;
  357. }
  358. /**
  359. * Returns true if on the last page.
  360. *
  361. * @return boolean
  362. */
  363. public function isLastPage()
  364. {
  365. return $this->page == $this->lastPage;
  366. }
  367. /**
  368. * Returns the current pager's parameter holder.
  369. *
  370. * @return array
  371. */
  372. public function getParameters()
  373. {
  374. return $this->parameters;
  375. }
  376. /**
  377. * Returns a parameter.
  378. *
  379. * @param string $name
  380. * @param mixed $default
  381. *
  382. * @return mixed
  383. */
  384. public function getParameter($name, $default = null)
  385. {
  386. return isset($this->parameters[$name]) ? $this->parameters[$name] : $default;
  387. }
  388. /**
  389. * Checks whether a parameter has been set.
  390. *
  391. * @param string $name
  392. *
  393. * @return boolean
  394. */
  395. public function hasParameter($name)
  396. {
  397. return isset($this->parameters[$name]);
  398. }
  399. /**
  400. * Sets a parameter.
  401. *
  402. * @param string $name
  403. * @param mixed $value
  404. */
  405. public function setParameter($name, $value)
  406. {
  407. $this->parameters[$name] = $value;
  408. }
  409. /**
  410. * Returns true if the properties used for iteration have been initialized.
  411. *
  412. * @return boolean
  413. */
  414. protected function isIteratorInitialized()
  415. {
  416. return null !== $this->results;
  417. }
  418. /**
  419. * Loads data into properties used for iteration.
  420. */
  421. protected function initializeIterator()
  422. {
  423. $this->results = $this->getResults();
  424. $this->resultsCounter = count($this->results);
  425. }
  426. /**
  427. * Empties properties used for iteration.
  428. */
  429. protected function resetIterator()
  430. {
  431. $this->results = null;
  432. $this->resultsCounter = 0;
  433. }
  434. /**
  435. * {@inheritdoc}
  436. */
  437. public function current()
  438. {
  439. if (!$this->isIteratorInitialized()) {
  440. $this->initializeIterator();
  441. }
  442. return current($this->results);
  443. }
  444. /**
  445. * {@inheritdoc}
  446. */
  447. public function key()
  448. {
  449. if (!$this->isIteratorInitialized()) {
  450. $this->initializeIterator();
  451. }
  452. return key($this->results);
  453. }
  454. /**
  455. * {@inheritdoc}
  456. */
  457. public function next()
  458. {
  459. if (!$this->isIteratorInitialized()) {
  460. $this->initializeIterator();
  461. }
  462. --$this->resultsCounter;
  463. return next($this->results);
  464. }
  465. /**
  466. * {@inheritdoc}
  467. */
  468. public function rewind()
  469. {
  470. if (!$this->isIteratorInitialized()) {
  471. $this->initializeIterator();
  472. }
  473. $this->resultsCounter = count($this->results);
  474. return reset($this->results);
  475. }
  476. /**
  477. * {@inheritdoc}
  478. */
  479. public function valid()
  480. {
  481. if (!$this->isIteratorInitialized()) {
  482. $this->initializeIterator();
  483. }
  484. return $this->resultsCounter > 0;
  485. }
  486. /**
  487. * {@inheritdoc}
  488. */
  489. public function count()
  490. {
  491. return $this->getNbResults();
  492. }
  493. /**
  494. * {@inheritdoc}
  495. */
  496. public function serialize()
  497. {
  498. $vars = get_object_vars($this);
  499. unset($vars['query']);
  500. return serialize($vars);
  501. }
  502. /**
  503. * {@inheritdoc}
  504. */
  505. public function unserialize($serialized)
  506. {
  507. $array = unserialize($serialized);
  508. foreach ($array as $name => $values) {
  509. $this->$name = $values;
  510. }
  511. }
  512. /**
  513. * @return array
  514. */
  515. public function getCountColumn()
  516. {
  517. return $this->countColumn;
  518. }
  519. /**
  520. * @param array $countColumn
  521. *
  522. * @return array
  523. */
  524. public function setCountColumn(array $countColumn)
  525. {
  526. return $this->countColumn = $countColumn;
  527. }
  528. /**
  529. * Retrieve the object for a certain offset
  530. *
  531. * @param integer $offset
  532. *
  533. * @return object
  534. */
  535. protected function retrieveObject($offset)
  536. {
  537. $queryForRetrieve = clone $this->getQuery();
  538. $queryForRetrieve
  539. ->setFirstResult($offset - 1)
  540. ->setMaxResults(1);
  541. $results = $queryForRetrieve->execute();
  542. return $results[0];
  543. }
  544. /**
  545. * @param mixed $query
  546. */
  547. public function setQuery($query)
  548. {
  549. $this->query = $query;
  550. }
  551. /**
  552. * @return null
  553. */
  554. public function getQuery()
  555. {
  556. return $this->query;
  557. }
  558. }