PageRenderTime 51ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/fuel/core/classes/pagination.php

https://bitbucket.org/codeyash/bootstrap
PHP | 515 lines | 321 code | 66 blank | 128 comment | 34 complexity | 4e5e8037259f49382b57b29a52e225f3 MD5 | raw file
Possible License(s): MIT, Apache-2.0
  1. <?php
  2. /**
  3. * Part of the Fuel framework.
  4. *
  5. * @package Fuel
  6. * @version 1.5
  7. * @author Fuel Development Team
  8. * @license MIT License
  9. * @copyright 2010 - 2013 Fuel Development Team
  10. * @link http://fuelphp.com
  11. */
  12. namespace Fuel\Core;
  13. class Pagination
  14. {
  15. /**
  16. * @var array Pagination instances
  17. */
  18. protected static $_instances = array();
  19. /**
  20. * @var array Pagination default instance
  21. */
  22. protected static $_instance = null;
  23. /**
  24. * Init
  25. *
  26. * Loads in the config and sets the variables
  27. *
  28. * @return void
  29. */
  30. public static function _init()
  31. {
  32. \Config::load('pagination', true);
  33. \Lang::load('pagination', true);
  34. }
  35. /**
  36. * Static access to the default instance
  37. *
  38. * @return mixed
  39. * @throws BadMethodCallException if the request method does not exist
  40. */
  41. public static function __callStatic($name, $arguments)
  42. {
  43. // old pre-1.4 mapping to new instance methods
  44. static $mapping = array(
  45. 'get' => '__get',
  46. 'set' => '__set',
  47. 'set_config' => '__set',
  48. 'create_links' => 'render',
  49. 'page_links' => 'pages_render',
  50. 'prev_link' => 'previous',
  51. 'next_link' => 'next',
  52. );
  53. array_key_exists($name, $mapping) and $name = $mapping[$name];
  54. // call the method on the default instance
  55. if ($instance = static::instance() and method_exists($instance, $name))
  56. {
  57. return call_user_func_array(array($instance, $name), $arguments);
  58. }
  59. throw new \BadMethodCallException('The pagination class doesn\'t have a method called "'.$name.'"');
  60. }
  61. /**
  62. * forge a new pagination instance
  63. *
  64. * @return \Pagination a new pagination instance
  65. */
  66. public static function forge($name = 'default', $config = array())
  67. {
  68. if ($exists = static::instance($name))
  69. {
  70. \Error::notice('Pagination with this name exists already, cannot be overwritten.');
  71. return $exists;
  72. }
  73. static::$_instances[$name] = new static($config);
  74. if ($name == 'default')
  75. {
  76. static::$_instance = static::$_instances[$name];
  77. }
  78. return static::$_instances[$name];
  79. }
  80. /**
  81. * retrieve an existing pagination instance
  82. *
  83. * @return \Pagination a existing pagination instance
  84. */
  85. public static function instance($name = null)
  86. {
  87. if ($name !== null)
  88. {
  89. if ( ! array_key_exists($name, static::$_instances))
  90. {
  91. return false;
  92. }
  93. return static::$_instances[$name];
  94. }
  95. if (static::$_instance === null)
  96. {
  97. static::$_instance = static::forge();
  98. }
  99. return static::$_instance;
  100. }
  101. // --------------------------------------------------------------------
  102. /**
  103. * instance configuration values
  104. */
  105. protected $config = array(
  106. 'current_page' => null,
  107. 'offset' => 0,
  108. 'per_page' => 10,
  109. 'total_pages' => 0,
  110. 'total_items' => 0,
  111. 'num_links' => 5,
  112. 'uri_segment' => 3,
  113. 'show_first' => false,
  114. 'show_last' => false,
  115. 'pagination_url' => null,
  116. );
  117. /**
  118. * instance template values
  119. */
  120. protected $template = array(
  121. 'wrapper' => "<div class=\"pagination\">\n\t{pagination}\n</div>\n",
  122. 'first' => "<span class=\"first\">\n\t{link}\n</span>\n",
  123. 'first-link' => "\t\t<a href=\"{uri}\">{page}</a>\n",
  124. 'previous' => "<span class=\"previous\">\n\t{link}\n</span>\n",
  125. 'previous-link' => "\t\t<a href=\"{uri}\">{page}</a>\n",
  126. 'previous-inactive' => "<span class=\"previous-inactive\">\n\t{link}\n</span>\n",
  127. 'previous-inactive-link' => "\t\t<a href=\"{uri}\">{page}</a>\n",
  128. 'regular' => "<span>\n\t{link}\n</span>\n",
  129. 'regular-link' => "\t\t<a href=\"{uri}\">{page}</a>\n",
  130. 'active' => "<span class=\"active\">\n\t{link}\n</span>\n",
  131. 'active-link' => "\t\t<a href=\"{uri}\">{page}</a>\n",
  132. 'next' => "<span class=\"next\">\n\t{link}\n</span>\n",
  133. 'next-link' => "\t\t<a href=\"{uri}\">{page}</a>\n",
  134. 'next-inactive' => "<span class=\"next-inactive\">\n\t{link}\n</span>\n",
  135. 'next-inactive-link' => "\t\t<a href=\"{uri}\">{page}</a>\n",
  136. 'last' => "<span class=\"next\">\n\t{link}\n</span>\n",
  137. 'last-link' => "\t\t<a href=\"{uri}\">{page}</a>\n",
  138. );
  139. /**
  140. *
  141. */
  142. public function __construct($config = array())
  143. {
  144. // make sure config is an array
  145. is_array($config) or $config = array('name' => $config);
  146. // and we have a template name
  147. array_key_exists('name', $config) or $config['name'] = \Config::get('pagination.active', 'default');
  148. // merge the config passed with the defined configuration
  149. $config = array_merge(\Config::get('pagination.'.$config['name'], array()), $config);
  150. // don't need the template name anymore
  151. unset($config['name']);
  152. // update the instance default config with the data passed
  153. foreach ($config as $key => $value)
  154. {
  155. $this->__set($key, $value);
  156. }
  157. }
  158. /**
  159. * configuration value getter
  160. */
  161. public function __get($name)
  162. {
  163. if (array_key_exists($name, $this->config))
  164. {
  165. return $this->config[$name];
  166. }
  167. elseif (array_key_exists($name, $this->template))
  168. {
  169. return $this->template[$name];
  170. }
  171. else
  172. {
  173. return null;
  174. }
  175. }
  176. /**
  177. * configuration value setter
  178. */
  179. public function __set($name, $value = null)
  180. {
  181. if (is_array($name))
  182. {
  183. foreach($name as $key => $value)
  184. {
  185. $this->__set($key, $value);
  186. }
  187. }
  188. else
  189. {
  190. if (array_key_exists($name, $this->config))
  191. {
  192. $this->config[$name] = $value;
  193. }
  194. elseif (array_key_exists($name, $this->template))
  195. {
  196. $this->template[$name] = $value;
  197. }
  198. }
  199. // update the page counters
  200. $this->_recalculate();
  201. }
  202. /**
  203. * Creates the pagination markup
  204. *
  205. * @return string Markup for the pagination block
  206. */
  207. public function render()
  208. {
  209. // no links if we only have one page
  210. if ($this->config['total_pages'] == 1)
  211. {
  212. return '';
  213. }
  214. $html = str_replace(
  215. '{pagination}',
  216. $this->first().$this->previous().$this->pages_render().$this->next().$this->last(),
  217. $this->template['wrapper']
  218. );
  219. return $html;
  220. }
  221. /**
  222. * generate the HTML for the page links only
  223. *
  224. * @return string Markup for page number links
  225. */
  226. public function pages_render()
  227. {
  228. // no links if we only have one page
  229. if ($this->config['total_pages'] == 1)
  230. {
  231. return '';
  232. }
  233. $html = '';
  234. // let's get the starting page number, this is determined using num_links
  235. $start = (($this->config['current_page'] - $this->config['num_links']) > 0) ? $this->config['current_page'] - ($this->config['num_links'] - 1) : 1;
  236. // let's get the ending page number
  237. $end = (($this->config['current_page'] + $this->config['num_links']) < $this->config['total_pages']) ? $this->config['current_page'] + $this->config['num_links'] : $this->config['total_pages'];
  238. for($i = $start; $i <= $end; $i++)
  239. {
  240. if ($this->config['current_page'] == $i)
  241. {
  242. $html .= str_replace(
  243. '{link}',
  244. str_replace(array('{uri}', '{page}'), array('#', $i), $this->template['active-link']),
  245. $this->template['active']
  246. );
  247. }
  248. else
  249. {
  250. $html .= str_replace(
  251. '{link}',
  252. str_replace(array('{uri}', '{page}'), array($this->_make_link($i), $i), $this->template['regular-link']),
  253. $this->template['regular']
  254. );
  255. }
  256. }
  257. return $html;
  258. }
  259. /**
  260. * Pagination "First" link
  261. *
  262. * @param string $value optional text to display in the link
  263. *
  264. * @return string Markup for the 'first' page number link
  265. */
  266. public function first($marker = '&laquo;&laquo;')
  267. {
  268. $html = '';
  269. if ($this->config['show_first'] and $this->config['total_pages'] > 1 and $this->config['current_page'] > 1)
  270. {
  271. $html = str_replace(
  272. '{link}',
  273. str_replace(array('{uri}', '{page}'), array($this->_make_link(1), $marker), $this->template['first-link']),
  274. $this->template['first']
  275. );
  276. }
  277. return $html;
  278. }
  279. /**
  280. * Pagination "Previous" link
  281. *
  282. * @param string $value optional text to display in the link
  283. *
  284. * @return string Markup for the 'previous' page number link
  285. */
  286. public function previous($marker = '&laquo;')
  287. {
  288. $html = '';
  289. if ($this->config['total_pages'] > 1)
  290. {
  291. if ($this->config['current_page'] == 1)
  292. {
  293. $html = str_replace(
  294. '{link}',
  295. str_replace(array('{uri}', '{page}'), array('#', $marker), $this->template['previous-inactive-link']),
  296. $this->template['previous-inactive']
  297. );
  298. }
  299. else
  300. {
  301. $previous_page = $this->config['current_page'] - 1;
  302. $previous_page = ($previous_page == 1) ? '' : $previous_page;
  303. $html = str_replace(
  304. '{link}',
  305. str_replace(array('{uri}', '{page}'), array($this->_make_link($previous_page), $marker), $this->template['previous-link']),
  306. $this->template['previous']
  307. );
  308. }
  309. }
  310. return $html;
  311. }
  312. /**
  313. * Pagination "Next" link
  314. *
  315. * @param string $value optional text to display in the link
  316. *
  317. * @return string Markup for the 'next' page number link
  318. */
  319. public function next($marker = '&raquo;')
  320. {
  321. $html = '';
  322. if ($this->config['total_pages'] > 1)
  323. {
  324. if ($this->config['current_page'] == $this->config['total_pages'])
  325. {
  326. $html = str_replace(
  327. '{link}',
  328. str_replace(array('{uri}', '{page}'), array('#', $marker), $this->template['next-inactive-link']),
  329. $this->template['next-inactive']
  330. );
  331. }
  332. else
  333. {
  334. $next_page = $this->config['current_page'] + 1;
  335. $html = str_replace(
  336. '{link}',
  337. str_replace(array('{uri}', '{page}'), array($this->_make_link($next_page), $marker), $this->template['next-link']),
  338. $this->template['next']
  339. );
  340. }
  341. }
  342. return $html;
  343. }
  344. /**
  345. * Pagination "Last" link
  346. *
  347. * @param string $value optional text to display in the link
  348. *
  349. * @return string Markup for the 'last' page number link
  350. */
  351. public function last($marker = '&raquo;&raquo;')
  352. {
  353. $html = '';
  354. if ($this->config['show_last'] and $this->config['total_pages'] > 1 and $this->config['current_page'] != $this->config['total_pages'])
  355. {
  356. $html = str_replace(
  357. '{link}',
  358. str_replace(array('{uri}', '{page}'), array($this->_make_link($this->config['total_pages']), $marker), $this->template['last-link']),
  359. $this->template['last']
  360. );
  361. }
  362. return $html;
  363. }
  364. /**
  365. * Prepares vars for creating links
  366. */
  367. protected function _recalculate()
  368. {
  369. // calculate the number of pages
  370. $this->config['total_pages'] = ceil($this->config['total_items'] / $this->config['per_page']) ?: 1;
  371. // get the current page number from the URI or the query string
  372. if (is_string($this->config['uri_segment']))
  373. {
  374. $this->config['current_page'] = ($this->config['total_items'] > 0 and $this->config['current_page'] > 1) ? $this->config['current_page'] : \Input::get($this->config['uri_segment'], 1);
  375. }
  376. else
  377. {
  378. $this->config['current_page'] = ($this->config['total_items'] > 0 and $this->config['current_page'] > 1) ? $this->config['current_page'] : (int) \Request::main()->uri->get_segment($this->config['uri_segment']);
  379. }
  380. // make sure the current page is within bounds
  381. if ($this->config['current_page'] > $this->config['total_pages'])
  382. {
  383. $this->config['current_page'] = $this->config['total_pages'];
  384. }
  385. elseif ($this->config['current_page'] < 1)
  386. {
  387. $this->config['current_page'] = 1;
  388. }
  389. // the current page must be zero based so that the offset for page 1 is 0.
  390. $this->config['offset'] = ($this->config['current_page'] - 1) * $this->config['per_page'];
  391. }
  392. /**
  393. * Generate a pagination link
  394. */
  395. protected function _make_link($page)
  396. {
  397. // make sure we have a valid page number
  398. empty($page) and $page = 1;
  399. // construct a pagination url if we don't have one
  400. if (is_null($this->config['pagination_url']))
  401. {
  402. // start with the main uri
  403. $this->config['pagination_url'] = \Uri::main();
  404. \Input::get() and $this->config['pagination_url'] .= '?'.http_build_query(\Input::get());
  405. }
  406. // was a placeholder defined in the url?
  407. if (strpos($this->config['pagination_url'], '{page}') === false)
  408. {
  409. // break the url in bits so we can insert it
  410. $url = parse_url($this->config['pagination_url']);
  411. // parse the query string
  412. if (isset($url['query']))
  413. {
  414. parse_str($url['query'], $url['query']);
  415. }
  416. else
  417. {
  418. $url['query'] = array();
  419. }
  420. // is the page number a URI segment?
  421. if (is_numeric($this->config['uri_segment']))
  422. {
  423. // get the URL segments
  424. $segs = isset($url['path']) ? explode('/', trim($url['path'], '/')) : array();
  425. // do we have enough segments to insert? we can't fill in any blanks...
  426. if (count($segs) < $this->config['uri_segment'] - 1)
  427. {
  428. throw new \RuntimeException("Not enough segments in the URI, impossible to insert the page number");
  429. }
  430. // replace the selected segment with the page placeholder
  431. $segs[$this->config['uri_segment'] - 1] = '{page}';
  432. $url['path'] = '/'.implode('/', $segs);
  433. }
  434. else
  435. {
  436. // add our placeholder
  437. $url['query'][$this->config['uri_segment']] = '{page}';
  438. }
  439. // re-assemble the url
  440. $query = empty($url['query']) ? '' : '?'.preg_replace('/%7Bpage%7D/', '{page}', http_build_query($url['query']));
  441. unset($url['query']);
  442. empty($url['scheme']) or $url['scheme'] .= '://';
  443. empty($url['port']) or $url['host'] .= ':';
  444. $this->config['pagination_url'] = implode($url).$query;
  445. }
  446. // return the page link
  447. return str_replace('{page}', $page, $this->config['pagination_url']);
  448. }
  449. }