PageRenderTime 48ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/titania/includes/tools/sort.php

http://github.com/phpbb/customisation-db
PHP | 569 lines | 352 code | 78 blank | 139 comment | 68 complexity | 6ed6b743db2f4ff1a3774699acad8f10 MD5 | raw file
Possible License(s): AGPL-1.0
  1. <?php
  2. /**
  3. *
  4. * @package Titania
  5. * @copyright (c) 2008 phpBB Customisation Database Team
  6. * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License, version 2
  7. *
  8. */
  9. /**
  10. * @ignore
  11. */
  12. if (!defined('IN_TITANIA'))
  13. {
  14. exit;
  15. }
  16. /**
  17. * Class to generate pagination
  18. *
  19. * @package Titania
  20. */
  21. class titania_sort extends titania_object
  22. {
  23. /**
  24. * Constants
  25. */
  26. const OFFSET_LIMIT_DEFAULT = 25;
  27. const OFFSET_LIMIT_MAX = 100;
  28. /**
  29. * URL Location/Parameters
  30. * Setting these will over-ride the settings sent in build_pagination
  31. *
  32. * @var mixed
  33. */
  34. public $url_location = false;
  35. public $url_parameters = false;
  36. /**
  37. * Have we requested the sort data already?
  38. *
  39. * @var bool
  40. */
  41. public $request_completed = false;
  42. /**
  43. * Set some default variables, set template_vars default values
  44. */
  45. public function __construct()
  46. {
  47. // Configure object properties
  48. $this->object_config = array_merge($this->object_config, array(
  49. 'start' => array('default' => 0),
  50. 'start_name' => array('default' => 'start'),
  51. 'limit' => array('default' => self::OFFSET_LIMIT_DEFAULT),
  52. 'limit_name' => array('default' => 'limit'),
  53. 'default_limit' => array('default' => self::OFFSET_LIMIT_DEFAULT),
  54. 'max_limit' => array('default' => self::OFFSET_LIMIT_MAX),
  55. 'sort_key_ary' => array('default' => array()),
  56. 'sort_key' => array('default' => ''),
  57. 'default_sort_key' => array('default' => ''),
  58. 'sort_key_name' => array('default' => 'sk'),
  59. 'sort_dir' => array('default' => 'a'),
  60. 'default_sort_dir' => array('default' => 'a'),
  61. 'sort_dir_name' => array('default' => 'sd'),
  62. 'total' => array('default' => 0),
  63. 'result_lang' => array('default' => 'TOTAL_RESULTS'), // sprintf'd into 'TOTAL_RESULTS' output; Should have TOTAL_RESULTS and TOTAL_RESULTS_ONE strings
  64. 'template_vars' => array(
  65. 'default' => array(
  66. 'PAGINATION' => 'PAGINATION',
  67. 'PAGE_NUMBER' => 'PAGE_NUMBER',
  68. 'S_PAGINATION_ACTION' => 'S_PAGINATION_ACTION',
  69. 'S_SORT_ACTION' => 'S_SORT_ACTION',
  70. 'S_NUM_POSTS' => 'S_NUM_POSTS',
  71. 'S_SELECT_SORT_KEY' => 'S_SELECT_SORT_KEY',
  72. 'S_SELECT_SORT_DIR' => 'S_SELECT_SORT_DIR',
  73. 'SORT_KEYS_NAME' => 'SORT_KEYS_NAME',
  74. 'SORT_DIR_NAME' => 'SORT_DIR_NAME',
  75. 'PER_PAGE' => 'PER_PAGE',
  76. 'ON_PAGE' => 'ON_PAGE',
  77. 'PREVIOUS_PAGE' => 'PREVIOUS_PAGE',
  78. 'NEXT_PAGE' => 'NEXT_PAGE',
  79. 'TOTAL_PAGES' => 'TOTAL_PAGES',
  80. 'TOTAL_ITEMS' => 'TOTAL_ITEMS',
  81. 'TOTAL_RESULTS' => 'TOTAL_RESULTS',
  82. ),
  83. ),
  84. ));
  85. }
  86. /**
  87. * Set some defaults
  88. *
  89. * @param int $limit Default limit, false to not change
  90. * @param string $sort_key Default sort key, false to not change
  91. * @param string $sort_dir (a|d) for ascending/descending, false to not change
  92. */
  93. public function set_defaults($limit, $sort_key = false, $sort_dir = false)
  94. {
  95. if ($limit !== false)
  96. {
  97. $this->default_limit = (int) $limit;
  98. }
  99. if ($sort_key !== false)
  100. {
  101. $this->default_sort_key = $sort_key;
  102. }
  103. if ($sort_dir !== false)
  104. {
  105. $this->default_sort_dir = ($sort_dir == 'a') ? 'a' : 'd';
  106. }
  107. }
  108. /**
  109. * Request function to run the start and limit grabbing functions
  110. */
  111. public function request()
  112. {
  113. if ($this->request_completed)
  114. {
  115. return;
  116. }
  117. $this->get_start();
  118. $this->get_limit();
  119. $this->get_sort_key();
  120. $this->get_sort_dir();
  121. $this->request_completed = true;
  122. }
  123. /**
  124. * Set start variable for pagination
  125. *
  126. * @param int $default custom start param
  127. *
  128. * @return int start
  129. */
  130. public function get_start($default = 0)
  131. {
  132. $this->start = request_var($this->start_name, (int) $default);
  133. return $this->start;
  134. }
  135. /**
  136. * Set limit variable for pagination
  137. *
  138. * @param int $default default Offset/Limit -- uses the constant if unset.
  139. *
  140. * @return int $limit
  141. */
  142. public function get_limit($default = false)
  143. {
  144. if ($default !== false)
  145. {
  146. $this->default_limit = $default;
  147. }
  148. $limit = request_var($this->limit_name, (int) $this->default_limit);
  149. // Don't allow limits of 0 which is unlimited results. Instead use the max limit.
  150. $limit = ($limit == 0) ? $this->max_limit : $limit;
  151. // We don't allow the user to specify a limit higher than the maximum.
  152. $this->limit = ($limit > $this->max_limit) ? $this->max_limit : $limit;
  153. return $this->limit;
  154. }
  155. /**
  156. * Set sort key
  157. */
  158. public function get_sort_key()
  159. {
  160. $this->sort_key = request_var($this->sort_key_name, (string) $this->default_sort_key);
  161. if (!isset($this->sort_key_ary[$this->sort_key]))
  162. {
  163. $this->sort_key = $this->default_sort_key;
  164. }
  165. return $this->sort_key;
  166. }
  167. /**
  168. * Set sort direction
  169. */
  170. public function get_sort_dir()
  171. {
  172. $this->sort_dir = (request_var($this->sort_dir_name, (string) $this->default_sort_dir) == $this->default_sort_dir) ? $this->default_sort_dir : (($this->default_sort_dir == 'a') ? 'd' : 'a');
  173. return $this->sort_dir;
  174. }
  175. /**
  176. * Count the number of results
  177. *
  178. * @param mixed $sql_ary
  179. * @param mixed $field
  180. */
  181. public function sql_count($sql_ary, $field)
  182. {
  183. $sql_ary['SELECT'] = "COUNT($field) AS cnt";
  184. unset($sql_ary['ORDER_BY']);
  185. $count_sql = phpbb::$db->sql_build_query('SELECT', $sql_ary);
  186. phpbb::$db->sql_query($count_sql);
  187. $this->total = phpbb::$db->sql_fetchfield('cnt');
  188. phpbb::$db->sql_freeresult();
  189. return $this->total;
  190. }
  191. /**
  192. * Setup the list of possible sort options using an array
  193. *
  194. * Example: Setting the sort keys, text, and default key
  195. * <code>
  196. * $sort->set_sort_keys(array(
  197. * 'a' => array('SORT_LANG_KEY1', 't.some_sql_field'),
  198. * 'b' => array('SORT_LANG_KEY2', 't.another_sql', true), // this is the default
  199. * 'c' => array('ANOTHER_LANG', 'a.sql_field'),
  200. * ));
  201. * </code>
  202. *
  203. * @param array $sort_keys
  204. */
  205. public function set_sort_keys($sort_keys)
  206. {
  207. foreach ($sort_keys as $key => $options)
  208. {
  209. if (!isset($options[0]) || !isset($options[1]))
  210. {
  211. unset($sort_keys[$key]);
  212. continue;
  213. }
  214. // if the third array increment is set to true, this key is set to default
  215. if ((isset($options[2]) && $options[2]))
  216. {
  217. $this->default_sort_key = $key;
  218. }
  219. }
  220. $this->sort_key_ary = $sort_keys;
  221. }
  222. /**
  223. * Set the URL info
  224. *
  225. * @param string $location
  226. * @param array $params
  227. */
  228. public function set_url($location, $params = array())
  229. {
  230. if (titania_url::is_built($location))
  231. {
  232. $this->url_location = titania_url::unbuild_url($location);
  233. }
  234. else
  235. {
  236. $this->url_location = $location;
  237. }
  238. if (is_array($params))
  239. {
  240. $this->url_parameters = $params;
  241. }
  242. }
  243. /**
  244. * Grab the sort key option list for usage within template
  245. *
  246. * @return string
  247. */
  248. public function get_sort_key_list()
  249. {
  250. $s_sort_key = '';
  251. foreach ($this->sort_key_ary as $key => $options)
  252. {
  253. $selected = ($this->sort_key == $key) ? ' selected="selected"' : '';
  254. $value = $options[0];
  255. $s_sort_key .= '<option value="' . $key . '"' . $selected . '>' . ((isset(phpbb::$user->lang[$value])) ? phpbb::$user->lang[$value] : $value) . '</option>';
  256. }
  257. return $s_sort_key;
  258. }
  259. /**
  260. * Grab the sort direction option list for usage within template
  261. *
  262. * @return string
  263. */
  264. public function get_sort_dir_list()
  265. {
  266. $sort_dir = array(
  267. 'a' => 'ASCENDING',
  268. 'd' => 'DESCENDING',
  269. );
  270. $s_sort_dir = '';
  271. foreach ($sort_dir as $key => $value)
  272. {
  273. $selected = ($this->sort_dir == $key) ? ' selected="selected"' : '';
  274. $s_sort_dir .= '<option value="' . $key . '"' . $selected . '>' . ((isset(phpbb::$user->lang[$value])) ? phpbb::$user->lang[$value] : $value) . '</option>';
  275. }
  276. return $s_sort_dir;
  277. }
  278. /**
  279. * Get order string for ORDER BY sql statement
  280. *
  281. * @return string SQL ORDER BY
  282. */
  283. public function get_order_by()
  284. {
  285. // If the sort_request function was not run yet we shall run it
  286. if (!$this->sort_key || !$this->sort_dir)
  287. {
  288. $this->request();
  289. }
  290. return $this->sort_key_ary[$this->sort_key][1] . ' ' . (($this->sort_dir == 'a') ? 'ASC' : 'DESC');
  291. }
  292. /**
  293. * Build a canonical URL
  294. */
  295. public function build_canonical()
  296. {
  297. $params = $this->url_parameters;
  298. if ($this->start)
  299. {
  300. $params[$this->start_name] = $this->start;
  301. }
  302. if ($this->limit != $this->default_limit)
  303. {
  304. $params[$this->limit_name] = $this->limit;
  305. }
  306. if ($this->sort_key != $this->default_sort_key)
  307. {
  308. $params[$this->sort_key_name] = $this->sort_key;
  309. }
  310. if ($this->sort_dir != $this->default_sort_dir)
  311. {
  312. $params[$this->sort_dir_name] = $this->sort_dir;
  313. }
  314. return titania_url::build_url($this->url_location, $params);
  315. }
  316. /**
  317. * Build pagination and send to template
  318. * $this->url_location and $this->url_parameters will over-ride the settings given here for $page, $params.
  319. * The reason is that the place that calls build_pagination is typically in a completely different area, in an area that can't say for certain the correct URL (other than the current page)
  320. *
  321. * @param string $page path/page to be used in pagination url
  322. * @param array $params to be used in pagination url
  323. */
  324. public function build_pagination($page, $params = array())
  325. {
  326. if ($this->url_location)
  327. {
  328. $page = $this->url_location;
  329. }
  330. if ($this->url_parameters)
  331. {
  332. $params = $this->url_parameters;
  333. }
  334. // Spring cleaning
  335. unset($params[$this->start_name], $params[$this->limit_name], $params[$this->sort_key_name], $params[$this->sort_dir_name]);
  336. // Add the limit to the URL if required
  337. if ($this->limit != $this->default_limit)
  338. {
  339. $params[$this->limit_name] = $this->limit;
  340. }
  341. // Don't include the sort key/dir in the sort action url
  342. $sort_url = titania_url::build_url($page, $params);
  343. // Add the sort key to the URL if required
  344. if ($this->sort_key != $this->default_sort_key)
  345. {
  346. $params[$this->sort_key_name] = $this->sort_key;
  347. }
  348. // Add the sort dir to the URL if required
  349. if ($this->sort_dir != $this->default_sort_dir)
  350. {
  351. $params[$this->sort_dir_name] = $this->sort_dir;
  352. }
  353. $pagination_url = titania_url::build_url($page, $params);
  354. phpbb::$template->assign_vars(array(
  355. $this->template_vars['PAGINATION'] => $this->generate_pagination($pagination_url, false, false, false, true),
  356. $this->template_vars['PAGE_NUMBER'] => on_page($this->total, $this->limit, $this->start),
  357. $this->template_vars['S_SORT_ACTION'] => $sort_url,
  358. $this->template_vars['S_PAGINATION_ACTION'] => $pagination_url,
  359. $this->template_vars['S_NUM_POSTS'] => $this->total,
  360. $this->template_vars['S_SELECT_SORT_KEY'] => $this->get_sort_key_list(),
  361. $this->template_vars['S_SELECT_SORT_DIR'] => $this->get_sort_dir_list(),
  362. $this->template_vars['SORT_KEYS_NAME'] => $this->sort_key_name,
  363. $this->template_vars['SORT_DIR_NAME'] => $this->sort_dir_name,
  364. ));
  365. return true;
  366. }
  367. /**
  368. * Generate pagination (similar to phpBB's generate_pagination function, only with some minor tweaks to work in this class better and use proper URLs)
  369. *
  370. * @param <string> $base_url
  371. * @param <int|bool> $num_items Bool false to use $this->total
  372. * @param <int|bool> $per_page Bool false to use $this->limit
  373. * @param <int|bool> $start_item Bool false to use $this->start
  374. * @param <bool> $add_prevnext_text
  375. * @return <string>
  376. */
  377. public function generate_pagination($base_url, $num_items = false, $per_page = false, $start_item = false, $add_prevnext_text = true)
  378. {
  379. $num_items = ($num_items === false) ? $this->total : $num_items;
  380. $per_page = ($per_page === false) ? $this->limit : $per_page;
  381. $start_item = ($start_item === false) ? $this->start : $start_item;
  382. $seperator = '<span class="page-sep">' . phpbb::$user->lang['COMMA_SEPARATOR'] . '</span>';
  383. $total_pages = ceil($num_items / $per_page);
  384. $on_page = floor($start_item / $per_page) + 1;
  385. $page_string = '';
  386. if (!$num_items)
  387. {
  388. return false;
  389. }
  390. if ($total_pages > 1)
  391. {
  392. $page_string = ($on_page == 1) ? '<strong>1</strong>' : '<a href="' . $base_url . '">1</a>';
  393. if ($total_pages > 5)
  394. {
  395. $start_cnt = min(max(1, $on_page - 4), $total_pages - 5);
  396. $end_cnt = max(min($total_pages, $on_page + 4), 6);
  397. $page_string .= ($start_cnt > 1) ? ' ... ' : $seperator;
  398. for ($i = $start_cnt + 1; $i < $end_cnt; $i++)
  399. {
  400. $page_string .= ($i == $on_page) ? '<strong>' . $i . '</strong>' : '<a href="' . titania_url::append_url($base_url, array($this->start_name => (($i - 1) * $per_page))) . '">' . $i . '</a>';
  401. if ($i < $end_cnt - 1)
  402. {
  403. $page_string .= $seperator;
  404. }
  405. }
  406. $page_string .= ($end_cnt < $total_pages) ? ' ... ' : $seperator;
  407. }
  408. else
  409. {
  410. $page_string .= $seperator;
  411. for ($i = 2; $i < $total_pages; $i++)
  412. {
  413. $page_string .= ($i == $on_page) ? '<strong>' . $i . '</strong>' : '<a href="' . titania_url::append_url($base_url, array($this->start_name => (($i - 1) * $per_page))) . '">' . $i . '</a>';
  414. if ($i < $total_pages)
  415. {
  416. $page_string .= $seperator;
  417. }
  418. }
  419. }
  420. $page_string .= ($on_page == $total_pages) ? '<strong>' . $total_pages . '</strong>' : '<a href="' . titania_url::append_url($base_url, array($this->start_name => (($total_pages - 1) * $per_page))) . '">' . $total_pages . '</a>';
  421. if ($add_prevnext_text)
  422. {
  423. if ($on_page == 2)
  424. {
  425. $page_string = '<a href="' . $base_url . '">' . phpbb::$user->lang['PREVIOUS'] . '</a>&nbsp;&nbsp;' . $page_string;
  426. }
  427. else if ($on_page != 1)
  428. {
  429. $page_string = '<a href="' . titania_url::append_url($base_url, array($this->start_name => (($on_page - 2) * $per_page))) . '">' . phpbb::$user->lang['PREVIOUS'] . '</a>&nbsp;&nbsp;' . $page_string;
  430. }
  431. if ($on_page != $total_pages)
  432. {
  433. $page_string .= '&nbsp;&nbsp;<a href="' . titania_url::append_url($base_url, array($this->start_name => ($on_page * $per_page))) . '">' . phpbb::$user->lang['NEXT'] . '</a>';
  434. }
  435. }
  436. }
  437. if ($num_items == 1)
  438. {
  439. $total_results = (isset(phpbb::$user->lang[$this->result_lang . '_ONE'])) ? phpbb::$user->lang[$this->result_lang . '_ONE'] : phpbb::$user->lang['TOTAL_RESULTS_ONE'];
  440. }
  441. else
  442. {
  443. $total_results = (isset(phpbb::$user->lang[$this->result_lang])) ? sprintf(phpbb::$user->lang[$this->result_lang], $num_items) : sprintf(phpbb::$user->lang['TOTAL_RESULTS'], $num_items);
  444. }
  445. phpbb::$template->assign_vars(array(
  446. $this->template_vars['PER_PAGE'] => $per_page,
  447. $this->template_vars['ON_PAGE'] => $on_page,
  448. $this->template_vars['PREVIOUS_PAGE'] => ($on_page == 2) ? $base_url : (($on_page == 1) ? '' : titania_url::append_url($base_url, array($this->start_name => (($on_page - 2) * $per_page)))),
  449. $this->template_vars['NEXT_PAGE'] => ($on_page == $total_pages) ? '' : titania_url::append_url($base_url, array($this->start_name => ($on_page * $per_page))),
  450. $this->template_vars['TOTAL_PAGES'] => $total_pages,
  451. $this->template_vars['TOTAL_ITEMS'] => $num_items,
  452. $this->template_vars['TOTAL_RESULTS'] => $total_results,
  453. ));
  454. return $page_string;
  455. }
  456. /**
  457. * Generate topic pagination
  458. */
  459. public function topic_generate_pagination($replies, $base_url)
  460. {
  461. // Make sure $per_page is a valid value
  462. $per_page = (phpbb::$config['posts_per_page'] <= 0) ? 1 : phpbb::$config['posts_per_page'];
  463. if (($replies + 1) > $per_page)
  464. {
  465. $total_pages = ceil(($replies + 1) / $per_page);
  466. $pagination = '';
  467. $times = 1;
  468. for ($j = 0; $j < $replies + 1; $j += $per_page)
  469. {
  470. $pagination .= '<a href="' . titania_url::append_url($base_url, array($this->start_name => $j)) . '">' . $times . '</a>';
  471. if ($times == 1 && $total_pages > 5)
  472. {
  473. $pagination .= ' ... ';
  474. // Display the last three pages
  475. $times = $total_pages - 3;
  476. $j += ($total_pages - 4) * $per_page;
  477. }
  478. else if ($times < $total_pages)
  479. {
  480. $pagination .= '<span class="page-sep">' . phpbb::$user->lang['COMMA_SEPARATOR'] . '</span>';
  481. }
  482. $times++;
  483. }
  484. }
  485. else
  486. {
  487. $pagination = '';
  488. }
  489. return $pagination;
  490. }
  491. }