PageRenderTime 56ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 1ms

/titania/includes/tools/sort.php

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