pagination::generate_template_pagination()   F
last analyzed

Complexity

Conditions 23
Paths 4672

Duplication

Lines 0
Ratio 0 %

Size

Total Lines 142
Code Lines 64

Importance

Changes 0
Metric Value
dl 0
loc 142
rs 2
c 0
b 0
f 0
cc 23
eloc 64
nc 4672
nop 8

How to fix   Long Method    Complexity    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
/**
3
* This file is part of the VinaBB.vn package.
4
*
5
* @copyright (c) VinaBB <vinabb.vn>
6
* @license GNU General Public License, version 2 (GPL-2.0)
7
*/
8
9
namespace vinabb\web\controllers;
10
11
use vinabb\web\includes\constants;
12
13
class pagination
14
{
15
	/** @var \phpbb\language\language */
16
	protected $language;
17
18
	/** @var \phpbb\template\template */
19
	protected $template;
20
21
	/** @var \phpbb\user */
22
	protected $user;
23
24
	/** @var \phpbb\controller\helper */
25
	protected $helper;
26
27
	/**
28
	* Constructor
29
	*
30
	* @param \phpbb\language\language $language
31
	* @param \phpbb\template\template $template
32
	* @param \phpbb\user $user
33
	* @param \phpbb\controller\helper $helper
34
	*/
35
	public function __construct(
36
		\phpbb\language\language $language,
37
		\phpbb\template\template $template,
38
		\phpbb\user $user,
39
		\phpbb\controller\helper $helper
40
	)
41
	{
42
		$this->language = $language;
43
		$this->template = $template;
44
		$this->user = $user;
45
		$this->helper = $helper;
46
	}
47
48
	/**
49
	* Generate a pagination link based on the url and the page information
50
	*
51
	* @param       $route_name
52
	* @param array $route_params
53
	* @param       $on_page
54
	*
55
	* @return string
56
	*/
57
	protected function generate_page_link($route_name, $route_params, $on_page)
58
	{
59
		if ($on_page > 1)
60
		{
61
			$route_params['page'] = constants::REWRITE_URL_PAGE . $on_page;
62
		}
63
64
		return $this->helper->route($route_name, $route_params);
65
	}
66
67
	/**
68
	* Generate template rendered pagination
69
	* Allows full control of rendering of pagination with the template
70
	*
71
	* @param		$route_name
72
	* @param array	$route_params
73
	* @param string $block_var_name is the name assigned to the pagination data block within the template (example: <!-- BEGIN pagination -->)
74
	* @param int $num_items the total number of items, posts, etc., used to determine the number of pages to produce
75
	* @param int $per_page the number of items, posts, etc. to display per page, used to determine the number of pages to produce
76
	* @param int $start the item which should be considered currently active, used to determine the page we're on
77
	* @param bool $reverse_count determines whether we weight display of the list towards the start (false) or end (true) of the list
78
	* @param bool $ignore_on_page decides whether we enable an active (unlinked) item, used primarily for embedded lists
79
	* @return null
80
	*/
81
	public function generate_template_pagination($route_name, $route_params, $block_var_name, $num_items, $per_page, $start = 1, $reverse_count = false, $ignore_on_page = false)
82
	{
83
		$total_pages = ceil($num_items / $per_page);
84
		$on_page = $this->get_on_page($per_page, $start);
85
		$u_previous_page = $u_next_page = '';
86
87
		if ($total_pages > 1)
88
		{
89
			if ($reverse_count)
90
			{
91
				$start_page = ($total_pages > 5) ? $total_pages - 4 : 1;
92
				$end_page = $total_pages;
93
			}
94
			else
95
			{
96
				// What we're doing here is calculating what the "start" and "end" pages should be. We
97
				// do this by assuming pagination is "centered" around the currently active page with
98
				// the three previous and three next page links displayed. Anything more than that and
99
				// we display the ellipsis, likewise anything less.
100
				//
101
				// $start_page is the page at which we start creating the list. When we have five or less
102
				// pages we start at page 1 since there will be no ellipsis displayed. Anymore than that
103
				// and we calculate the start based on the active page. This is the min/max calculation.
104
				// First (max) would we end up starting on a page less than 1? Next (min) would we end
105
				// up starting so close to the end that we'd not display our minimum number of pages.
106
				//
107
				// $end_page is the last page in the list to display. Like $start_page we use a min/max to
108
				// determine this number. Again at most five pages? Then just display them all. More than
109
				// five and we first (min) determine whether we'd end up listing more pages than exist.
110
				// We then (max) ensure we're displaying the minimum number of pages.
111
				$start_page = ($total_pages > 5) ? min(max(1, $on_page - 2), $total_pages - 4) : 1;
112
				$end_page = ($total_pages > 5) ? max(min($total_pages, $on_page + 2), 5) : $total_pages;
113
			}
114
115
			if ($on_page != 1)
116
			{
117
				$u_previous_page = $this->generate_page_link($route_name, $route_params, $on_page - 1);
118
119
				$this->template->assign_block_vars($block_var_name, array(
120
					'PAGE_NUMBER'	=> '',
121
					'PAGE_URL'		=> $u_previous_page,
122
					'S_IS_CURRENT'	=> false,
123
					'S_IS_PREV'		=> true,
124
					'S_IS_NEXT'		=> false,
125
					'S_IS_ELLIPSIS'	=> false,
126
				));
127
			}
128
129
			// This do...while exists purely to negate the need for start and end assign_block_vars, i.e.
130
			// to display the first and last page in the list plus any ellipsis. We use this loop to jump
131
			// around a little within the list depending on where we're starting (and ending).
132
			$at_page = 1;
133
134
			do
135
			{
136
				// We decide whether to display the ellipsis during the loop. The ellipsis is always
137
				// displayed as either the second or penultimate item in the list. So are we at either
138
				// of those points and of course do we even need to display it, i.e. is the list starting
139
				// on at least page 3 and ending three pages before the final item.
140
				$this->template->assign_block_vars($block_var_name, array(
141
					'PAGE_NUMBER'	=> $at_page,
142
					'PAGE_URL'		=> $this->generate_page_link($route_name, $route_params, $at_page),
143
					'S_IS_CURRENT'	=> (!$ignore_on_page && $at_page == $on_page),
144
					'S_IS_NEXT'		=> false,
145
					'S_IS_PREV'		=> false,
146
					'S_IS_ELLIPSIS'	=> ($at_page == 2 && $start_page > 2) || ($at_page == $total_pages - 1 && $end_page < $total_pages - 1),
147
				));
148
149
				// We may need to jump around in the list depending on whether we have or need to display
150
				// the ellipsis. Are we on page 2 and are we more than one page away from the start
151
				// of the list? Yes? Then we jump to the start of the list. Likewise are we at the end of
152
				// the list and are there more than two pages left in total? Yes? Then jump to the penultimate
153
				// page (so we can display the ellipsis next pass). Else, increment the counter and keep
154
				// going
155
				if ($at_page == 2 && $at_page < $start_page - 1)
156
				{
157
					$at_page = $start_page;
158
				}
159
				else if ($at_page == $end_page && $end_page < $total_pages - 1)
160
				{
161
					$at_page = $total_pages - 1;
162
				}
163
				else
164
				{
165
					$at_page++;
166
				}
167
			}
168
			while ($at_page <= $total_pages);
169
170
			if ($on_page != $total_pages)
171
			{
172
				$u_next_page = $this->generate_page_link($route_name, $route_params, $on_page + 1);
173
174
				$this->template->assign_block_vars($block_var_name, array(
175
					'PAGE_NUMBER'	=> '',
176
					'PAGE_URL'		=> $u_next_page,
177
					'S_IS_CURRENT'	=> false,
178
					'S_IS_PREV'		=> false,
179
					'S_IS_NEXT'		=> true,
180
					'S_IS_ELLIPSIS'	=> false,
181
				));
182
			}
183
		}
184
185
		// If the block_var_name is a nested block, we will use the last (most
186
		// inner) block as a prefix for the template variables. If the last block
187
		// name is pagination, the prefix is empty. If the rest of the
188
		// block_var_name is not empty, we will modify the last row of that block
189
		// and add our pagination items.
190
		$tpl_block_name = $tpl_prefix = '';
191
192
		if (strrpos($block_var_name, '.') !== false)
193
		{
194
			$tpl_block_name = substr($block_var_name, 0, strrpos($block_var_name, '.'));
195
			$tpl_prefix = strtoupper(substr($block_var_name, strrpos($block_var_name, '.') + 1));
196
		}
197
		else
198
		{
199
			$tpl_prefix = strtoupper($block_var_name);
200
		}
201
202
		$tpl_prefix = ($tpl_prefix == 'PAGINATION') ? '' : $tpl_prefix . '_';
203
204
		$template_array = array(
205
			$tpl_prefix . 'BASE_URL'				=> (empty($route_name)) ? '' : $this->helper->route($route_name, $route_params),
206
			$tpl_prefix . 'PER_PAGE'				=> $per_page,
207
			'U_' . $tpl_prefix . 'PREVIOUS_PAGE'	=> ($on_page != 1) ? $u_previous_page : '',
208
			'U_' . $tpl_prefix . 'NEXT_PAGE'		=> ($on_page != $total_pages) ? $u_next_page : '',
209
			$tpl_prefix . 'TOTAL_PAGES'				=> $total_pages,
210
			$tpl_prefix . 'CURRENT_PAGE'			=> $on_page,
211
			$tpl_prefix . 'PAGE_NUMBER'				=> $this->on_page($num_items, $per_page, $start),
212
		);
213
214
		if ($tpl_block_name)
215
		{
216
			$this->template->alter_block_array($tpl_block_name, $template_array, true, 'change');
217
		}
218
		else
219
		{
220
			$this->template->assign_vars($template_array);
221
		}
222
	}
223
224
	/**
225
	* Get current page number
226
	*
227
	* @param int $per_page the number of items, posts, etc. per page
228
	* @param int $start the item which should be considered currently active, used to determine the page we're on
229
	* @return int	Current page number
230
	*/
231
	public function get_on_page($per_page, $start)
232
	{
233
		return floor($start / $per_page) + 1;
234
	}
235
236
	/**
237
	* Return current page
238
	*
239
	* @param int $num_items the total number of items, posts, topics, etc.
240
	* @param int $per_page the number of items, posts, etc. per page
241
	* @param int $start the item which should be considered currently active, used to determine the page we're on
242
	* @return string Descriptive pagination string (e.g. "page 1 of 10")
243
	*/
244
	public function on_page($num_items, $per_page, $start)
245
	{
246
		$on_page = $this->get_on_page($per_page, $start);
247
248
		return $this->language->lang('PAGE_OF', $on_page, max(ceil($num_items / $per_page), 1));
249
	}
250
251
	/**
252
	* Get current page number
253
	*
254
	* @param int $start the item which should be considered currently active, used to determine the page we're on
255
	* @param int $per_page the number of items, posts, etc. per page
256
	* @param int $num_items the total number of items, posts, topics, etc.
257
	* @return int	Current page number
258
	*/
259
	public function validate_start($start, $per_page, $num_items)
260
	{
261
		if ($start < 0 || $start >= $num_items)
262
		{
263
			return ($start < 0 || $num_items <= 0) ? 0 : floor(($num_items - 1) / $per_page) * $per_page;
264
		}
265
266
		return $start;
267
	}
268
269
	/**
270
	* Get new start when searching from the end
271
	*
272
	* If the user is trying to reach late pages, start searching from the end.
273
	*
274
	* @param int $start the item which should be considered currently active, used to determine the page we're on
275
	* @param int $limit the number of items, posts, etc. to display
276
	* @param int $num_items the total number of items, posts, topics, etc.
277
	* @return int	Current page number
278
	*/
279
	public function reverse_start($start, $limit, $num_items)
280
	{
281
		return max(0, $num_items - $limit - $start);
282
	}
283
284
	/**
285
	* Get new item limit when searching from the end
286
	*
287
	* If the user is trying to reach late pages, start searching from the end.
288
	* In this case the items to display might be lower then the actual per_page setting.
289
	*
290
	* @param int $start the item which should be considered currently active, used to determine the page we're on
291
	* @param int $per_page the number of items, posts, etc. per page
292
	* @param int $num_items the total number of items, posts, topics, etc.
293
	* @return int	Current page number
294
	*/
295
	public function reverse_limit($start, $per_page, $num_items)
296
	{
297
		if ($start + $per_page > $num_items)
298
		{
299
			return min($per_page, max(1, $num_items - $start));
300
		}
301
302
		return $per_page;
303
	}
304
}
305