Passed
Push — release-2.1 ( 0c2197...207d2d )
by Jeremy
05:47
created

Subs-List.php ➔ createList()   F

Complexity

Conditions 78
Paths > 20000

Size

Total Lines 234

Duplication

Lines 10
Ratio 4.27 %

Importance

Changes 0
Metric Value
cc 78
nc 429496.7295
nop 1
dl 10
loc 234
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

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:

1
<?php
2
3
/**
4
 * This file contains a standard way of displaying lists for SMF.
5
 * Simple Machines Forum (SMF)
6
 *
7
 * @package SMF
8
 * @author Simple Machines http://www.simplemachines.org
9
 * @copyright 2018 Simple Machines and individual contributors
10
 * @license http://www.simplemachines.org/about/smf/license.php BSD
11
 *
12
 * @version 2.1 Beta 4
13
 */
14
15
if (!defined('SMF'))
16
	die('No direct access...');
17
18
/**
19
 * Create a new list
20
 * @param array $listOptions An array of options for the list - 'id', 'columns', 'items_per_page', 'get_count', etc.
21
 */
22
function createList($listOptions)
23
{
24
	global $context, $smcFunc;
25
26
	assert(isset($listOptions['id']));
27
	assert(isset($listOptions['columns']));
28
	assert(is_array($listOptions['columns']));
29
	assert((empty($listOptions['items_per_page']) || (isset($listOptions['get_count']['function'], $listOptions['base_href']) && is_numeric($listOptions['items_per_page']))));
30
	assert((empty($listOptions['default_sort_col']) || isset($listOptions['columns'][$listOptions['default_sort_col']])));
31
	assert((!isset($listOptions['form']) || isset($listOptions['form']['href'])));
32
33
	call_integration_hook('integrate_' . $listOptions['id'], array(&$listOptions));
34
35
	// All the context data will be easily accessible by using a reference.
36
	$context[$listOptions['id']] = array();
37
	$list_context = &$context[$listOptions['id']];
38
39
	// Figure out the sort.
40
	if (empty($listOptions['default_sort_col']))
41
	{
42
		$list_context['sort'] = array();
43
		$sort = '1=1';
44
	}
45
	else
46
	{
47
		$request_var_sort = isset($listOptions['request_vars']['sort']) ? $listOptions['request_vars']['sort'] : 'sort';
48
		$request_var_desc = isset($listOptions['request_vars']['desc']) ? $listOptions['request_vars']['desc'] : 'desc';
49
		if (isset($_REQUEST[$request_var_sort], $listOptions['columns'][$_REQUEST[$request_var_sort]], $listOptions['columns'][$_REQUEST[$request_var_sort]]['sort']))
50
			$list_context['sort'] = array(
51
				'id' => $_REQUEST[$request_var_sort],
52
				'desc' => isset($_REQUEST[$request_var_desc]) && isset($listOptions['columns'][$_REQUEST[$request_var_sort]]['sort']['reverse']),
53
			);
54
		else
55
			$list_context['sort'] = array(
56
				'id' => $listOptions['default_sort_col'],
57
				'desc' => (!empty($listOptions['default_sort_dir']) && $listOptions['default_sort_dir'] == 'desc') || (!empty($listOptions['columns'][$listOptions['default_sort_col']]['sort']['default']) && substr($listOptions['columns'][$listOptions['default_sort_col']]['sort']['default'], -4, 4) == 'desc') ? true : false,
58
			);
59
60
		// Set the database column sort.
61
		$sort = $listOptions['columns'][$list_context['sort']['id']]['sort'][$list_context['sort']['desc'] ? 'reverse' : 'default'];
62
	}
63
64
	$list_context['start_var_name'] = isset($listOptions['start_var_name']) ? $listOptions['start_var_name'] : 'start';
65
	// In some cases the full list must be shown, regardless of the amount of items.
66
	if (empty($listOptions['items_per_page']))
67
	{
68
		$list_context['start'] = 0;
69
		$list_context['items_per_page'] = 0;
70
	}
71
	// With items per page set, calculate total number of items and page index.
72
	else
73
	{
74
		// First get an impression of how many items to expect.
75
		if (isset($listOptions['get_count']['file']))
76
			require_once($listOptions['get_count']['file']);
77
78
		$call = call_helper($listOptions['get_count']['function'], true);
79
		$list_context['total_num_items'] = call_user_func_array($call, empty($listOptions['get_count']['params']) ? array() : $listOptions['get_count']['params']);
0 ignored issues
show
Bug introduced by
It seems like $call can also be of type boolean; however, parameter $function of call_user_func_array() does only seem to accept callable, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

79
		$list_context['total_num_items'] = call_user_func_array(/** @scrutinizer ignore-type */ $call, empty($listOptions['get_count']['params']) ? array() : $listOptions['get_count']['params']);
Loading history...
80
81
		// Default the start to the beginning...sounds logical.
82
		$list_context['start'] = isset($_REQUEST[$list_context['start_var_name']]) ? (int) $_REQUEST[$list_context['start_var_name']] : 0;
83
		$list_context['items_per_page'] = $listOptions['items_per_page'];
84
85
		// Then create a page index.
86
		if ($list_context['total_num_items'] > $list_context['items_per_page'])
87
			$list_context['page_index'] = constructPageIndex($listOptions['base_href'] . (empty($list_context['sort']) ? '' : ';' . $request_var_sort . '=' . $list_context['sort']['id'] . ($list_context['sort']['desc'] ? ';' . $request_var_desc : '')) . ($list_context['start_var_name'] != 'start' ? ';' . $list_context['start_var_name'] . '=%1$d' : ''), $list_context['start'], $list_context['total_num_items'], $list_context['items_per_page'], $list_context['start_var_name'] != 'start');
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $request_var_desc does not seem to be defined for all execution paths leading up to this point.
Loading history...
Comprehensibility Best Practice introduced by
The variable $request_var_sort does not seem to be defined for all execution paths leading up to this point.
Loading history...
88
	}
89
90
	// Prepare the headers of the table.
91
	$list_context['headers'] = array();
92
	foreach ($listOptions['columns'] as $column_id => $column)
93
		$list_context['headers'][] = array(
94
			'id' => $column_id,
95
			'label' => isset($column['header']['eval']) ? eval($column['header']['eval']) : (isset($column['header']['value']) ? $column['header']['value'] : ''),
0 ignored issues
show
introduced by
The use of eval() is discouraged.
Loading history...
96
			'href' => empty($listOptions['default_sort_col']) || empty($column['sort']) ? '' : $listOptions['base_href'] . ';' . $request_var_sort . '=' . $column_id . ($column_id === $list_context['sort']['id'] && !$list_context['sort']['desc'] && isset($column['sort']['reverse']) ? ';' . $request_var_desc : '') . (empty($list_context['start']) ? '' : ';' . $list_context['start_var_name'] . '=' . $list_context['start']),
97
			'sort_image' => empty($listOptions['default_sort_col']) || empty($column['sort']) || $column_id !== $list_context['sort']['id'] ? null : ($list_context['sort']['desc'] ? 'down' : 'up'),
98
			'class' => isset($column['header']['class']) ? $column['header']['class'] : '',
99
			'style' => isset($column['header']['style']) ? $column['header']['style'] : '',
100
			'colspan' => isset($column['header']['colspan']) ? $column['header']['colspan'] : '',
101
		);
102
103
	// We know the amount of columns, might be useful for the template.
104
	$list_context['num_columns'] = count($listOptions['columns']);
105
	$list_context['width'] = isset($listOptions['width']) ? $listOptions['width'] : '0';
106
107
	// Get the file with the function for the item list.
108
	if (isset($listOptions['get_items']['file']))
109
		require_once($listOptions['get_items']['file']);
110
111
	// Call the function and include which items we want and in what order.
112
	$call = call_helper($listOptions['get_items']['function'], true);
113
	$list_items = call_user_func_array($call, array_merge(array($list_context['start'], $list_context['items_per_page'], $sort), empty($listOptions['get_items']['params']) ? array() : $listOptions['get_items']['params']));
114
	$list_items = empty($list_items) ? array() : $list_items;
115
116
	// Loop through the list items to be shown and construct the data values.
117
	$list_context['rows'] = array();
118
	foreach ($list_items as $item_id => $list_item)
119
	{
120
		$cur_row = array();
121
		foreach ($listOptions['columns'] as $column_id => $column)
122
		{
123
			$cur_data = array();
124
125
			// A value straight from the database?
126
			if (isset($column['data']['db']))
127
				$cur_data['value'] = $list_item[$column['data']['db']];
128
129
			// Take the value from the database and make it HTML safe.
130
			elseif (isset($column['data']['db_htmlsafe']))
131
				$cur_data['value'] = $smcFunc['htmlspecialchars']($list_item[$column['data']['db_htmlsafe']]);
132
133
			// Using sprintf is probably the most readable way of injecting data.
134
			elseif (isset($column['data']['sprintf']))
135
			{
136
				$params = array();
137
				foreach ($column['data']['sprintf']['params'] as $sprintf_param => $htmlsafe)
138
					$params[] = $htmlsafe ? $smcFunc['htmlspecialchars']($list_item[$sprintf_param]) : $list_item[$sprintf_param];
139
				$cur_data['value'] = vsprintf($column['data']['sprintf']['format'], $params);
140
			}
141
142
			// The most flexible way probably is applying a custom function.
143
			elseif (isset($column['data']['function']))
144
				$cur_data['value'] = call_user_func_array($column['data']['function'], array($list_item));
145
146
			// A modified value (inject the database values).
147
			elseif (isset($column['data']['eval']))
148
				$cur_data['value'] = eval(preg_replace('~%([a-zA-Z0-9\-_]+)%~', '$list_item[\'$1\']', $column['data']['eval']));
0 ignored issues
show
introduced by
The use of eval() is discouraged.
Loading history...
149
150
			// A literal value.
151
			elseif (isset($column['data']['value']))
152
				$cur_data['value'] = $column['data']['value'];
153
154
			// Empty value.
155
			else
156
				$cur_data['value'] = '';
157
158
			// Allow for basic formatting.
159
			if (!empty($column['data']['comma_format']))
160
				$cur_data['value'] = comma_format($cur_data['value']);
161
			elseif (!empty($column['data']['timeformat']))
162
				$cur_data['value'] = timeformat($cur_data['value']);
163
164
			// Set a style class for this column?
165
			if (isset($column['data']['class']))
166
				$cur_data['class'] = $column['data']['class'];
167
168
			// Fully customized styling for the cells in this column only.
169
			if (isset($column['data']['style']))
170
				$cur_data['style'] = $column['data']['style'];
171
172
			// Add the data cell properties to the current row.
173
			$cur_row[$column_id] = $cur_data;
174
		}
175
176
		// Maybe we wat set a custom class for the row based on the data in the row itself
177
		if (isset($listOptions['data_check']))
178
		{
179
			if (isset($listOptions['data_check']['class']))
180
				$list_context['rows'][$item_id]['class'] = $listOptions['data_check']['class']($list_item);
181
			if (isset($listOptions['data_check']['style']))
182
				$list_context['rows'][$item_id]['style'] = $listOptions['data_check']['style']($list_item);
183
		}
184
185
		// Insert the row into the list.
186
		$list_context['rows'][$item_id]['data'] = $cur_row;
187
	}
188
189
	// The title is currently optional.
190
	if (isset($listOptions['title']))
191
		$list_context['title'] = $listOptions['title'];
192
193
	// In case there's a form, share it with the template context.
194
	if (isset($listOptions['form']))
195
	{
196
		$list_context['form'] = $listOptions['form'];
197
198
		if (!isset($list_context['form']['hidden_fields']))
199
			$list_context['form']['hidden_fields'] = array();
200
201
		// Always add a session check field.
202
		$list_context['form']['hidden_fields'][$context['session_var']] = $context['session_id'];
203
204
		// Will this do a token check?
205
		if (isset($listOptions['form']['token']))
206
			$list_context['form']['hidden_fields'][$context[$listOptions['form']['token'] . '_token_var']] = $context[$listOptions['form']['token'] . '_token'];
207
208
		// Include the starting page as hidden field?
209
		if (!empty($list_context['form']['include_start']) && !empty($list_context['start']))
210
			$list_context['form']['hidden_fields'][$list_context['start_var_name']] = $list_context['start'];
211
212
		// If sorting needs to be the same after submitting, add the parameter.
213
		if (!empty($list_context['form']['include_sort']) && !empty($list_context['sort']))
214
		{
215
			$list_context['form']['hidden_fields']['sort'] = $list_context['sort']['id'];
216
			if ($list_context['sort']['desc'])
217
				$list_context['form']['hidden_fields']['desc'] = 1;
218
		}
219
	}
220
221
	// Wanna say something nice in case there are no items?
222
	if (isset($listOptions['no_items_label']))
223
	{
224
		$list_context['no_items_label'] = $listOptions['no_items_label'];
225
		$list_context['no_items_align'] = isset($listOptions['no_items_align']) ? $listOptions['no_items_align'] : '';
226
	}
227
228
	// A list can sometimes need a few extra rows above and below.
229
	if (isset($listOptions['additional_rows']))
230
	{
231
		$list_context['additional_rows'] = array();
232
		foreach ($listOptions['additional_rows'] as $row)
233
		{
234
			if (empty($row))
235
				continue;
236
237
			// Supported row positions: top_of_list, after_title,
238
			// above_column_headers, below_table_data, bottom_of_list.
239
			if (!isset($list_context['additional_rows'][$row['position']]))
240
				$list_context['additional_rows'][$row['position']] = array();
241
			$list_context['additional_rows'][$row['position']][] = $row;
242
		}
243
	}
244
245
	// Add an option for inline JavaScript.
246
	if (isset($listOptions['javascript']))
247
		$list_context['javascript'] = $listOptions['javascript'];
248
249
	// We want a menu.
250
	if (isset($listOptions['list_menu']))
251
		$list_context['list_menu'] = $listOptions['list_menu'];
252
253
	// Make sure the template is loaded.
254
	loadTemplate('GenericList');
255
}
256
257
?>