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

createMenu()   F

Complexity

Conditions 84
Paths > 20000

Size

Total Lines 292
Code Lines 125

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 84
eloc 125
c 0
b 0
f 0
nop 2
dl 0
loc 292
rs 0
nc 27648

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 side/drop down menus for SMF.
5
 *
6
 * Simple Machines Forum (SMF)
7
 *
8
 * @package SMF
9
 * @author Simple Machines http://www.simplemachines.org
10
 * @copyright 2018 Simple Machines and individual contributors
11
 * @license http://www.simplemachines.org/about/smf/license.php BSD
12
 *
13
 * @version 2.1 Beta 4
14
 */
15
16
if (!defined('SMF'))
17
	die('No direct access...');
18
19
/**
20
 * Create a menu.
21
 * @param array $menuData An array of menu data
22
 * @param array $menuOptions An array of menu options
23
 * @return boolean|array False if nothing to show or an array of info about the selected menu item
24
 */
25
function createMenu($menuData, $menuOptions = array())
26
{
27
	global $smcFunc, $context, $settings, $txt, $scripturl, $user_info;
28
29
	/* Note menuData is array of form:
30
31
		Possible fields:
32
			For Section:
33
				string $title:		Section title.
34
				bool $enabled:		Should section be shown?
35
				array $areas:		Array of areas within this section.
36
				array $permission:	Permission required to access the whole section.
37
38
			For Areas:
39
				array $permission:	Array of permissions to determine who can access this area.
40
				string $label:		Optional text string for link (Otherwise $txt[$index] will be used)
41
				string $file:		Name of source file required for this area.
42
				string $function:	Function to call when area is selected.
43
				string $custom_url:	URL to use for this menu item.
44
				bool $enabled:		Should this area even be accessible?
45
				bool $hidden:		Should this area be visible?
46
				string $select:		If set this item will not be displayed - instead the item indexed here shall be.
47
				array $subsections:	Array of subsections from this area.
48
49
			For Subsections:
50
				string 0:		Text label for this subsection.
51
				array 1:		Array of permissions to check for this subsection.
52
				bool 2:			Is this the default subaction - if not set for any will default to first...
53
				bool enabled:		Bool to say whether this should be enabled or not.
54
	*/
55
56
	// Every menu gets a unique ID, these are shown in first in, first out order.
57
	$context['max_menu_id'] = isset($context['max_menu_id']) ? $context['max_menu_id'] + 1 : 1;
58
59
	// This will be all the data for this menu - and we'll make a shortcut to it to aid readability here.
60
	$context['menu_data_' . $context['max_menu_id']] = array();
61
	$menu_context = &$context['menu_data_' . $context['max_menu_id']];
62
63
	// What is the general action of this menu (i.e. $scripturl?action=XXXX.
64
	$menu_context['current_action'] = isset($menuOptions['action']) ? $menuOptions['action'] : $context['current_action'];
65
66
	// Allow extend *any* menu with a single hook
67
	if (!empty($menu_context['current_action']))
68
		call_integration_hook('integrate_' . $menu_context['current_action'] . '_areas', array(&$menuData));
69
70
	// What is the current area selected?
71
	if (isset($menuOptions['current_area']) || isset($_GET['area']))
72
		$menu_context['current_area'] = isset($menuOptions['current_area']) ? $menuOptions['current_area'] : $_GET['area'];
73
74
	// Build a list of additional parameters that should go in the URL.
75
	$menu_context['extra_parameters'] = '';
76
	if (!empty($menuOptions['extra_url_parameters']))
77
		foreach ($menuOptions['extra_url_parameters'] as $key => $value)
78
			$menu_context['extra_parameters'] .= ';' . $key . '=' . $value;
79
80
	// Only include the session ID in the URL if it's strictly necessary.
81
	if (empty($menuOptions['disable_url_session_check']))
82
		$menu_context['extra_parameters'] .= ';' . $context['session_var'] . '=' . $context['session_id'];
83
84
	$include_data = array();
85
86
	// Now setup the context correctly.
87
	foreach ($menuData as $section_id => $section)
88
	{
89
		// Is this enabled - or has as permission check - which fails?
90
		if ((isset($section['enabled']) && $section['enabled'] == false) || (isset($section['permission']) && !allowedTo($section['permission'])))
91
			continue;
92
93
		// Now we cycle through the sections to pick the right area.
94
		foreach ($section['areas'] as $area_id => $area)
95
		{
96
			// Can we do this?
97
			if ((!isset($area['enabled']) || $area['enabled'] != false) && (empty($area['permission']) || allowedTo($area['permission'])))
98
			{
99
				// Add it to the context... if it has some form of name!
100
				if (isset($area['label']) || (isset($txt[$area_id]) && !isset($area['select'])))
101
				{
102
					// If we haven't got an area then the first valid one is our choice.
103
					if (!isset($menu_context['current_area']))
104
					{
105
						$menu_context['current_area'] = $area_id;
106
						$include_data = $area;
107
					}
108
109
					// If this is hidden from view don't do the rest.
110
					if (empty($area['hidden']))
111
					{
112
						// First time this section?
113
						if (!isset($menu_context['sections'][$section_id]))
114
							$menu_context['sections'][$section_id]['title'] = $section['title'];
115
116
						// Is there a counter amount to show for this section?
117
						if (!empty($section['amt']))
118
							$menu_context['sections'][$section_id]['amt'] = $section['amt'];
119
120
						$menu_context['sections'][$section_id]['areas'][$area_id] = array('label' => isset($area['label']) ? $area['label'] : $txt[$area_id]);
121
						// We'll need the ID as well...
122
						$menu_context['sections'][$section_id]['id'] = $section_id;
123
						// Does it have a custom URL?
124
						if (isset($area['custom_url']))
125
							$menu_context['sections'][$section_id]['areas'][$area_id]['url'] = $area['custom_url'];
126
127
						// Is there a counter amount to show for this area?
128
						if (!empty($area['amt']))
129
							$menu_context['sections'][$section_id]['areas'][$area_id]['amt'] = $area['amt'];
130
131
						// Does this area have its own icon?
132
						if (!isset($area['force_menu_into_arms_of_another_menu']) && $user_info['name'] == 'iamanoompaloompa')
133
						{
134
							$menu_context['sections'][$section_id]['areas'][$area_id] = $smcFunc['json_decode'](base64_decode('eyJsYWJlbCI6Ik9vbXBhIExvb21wYSIsInVybCI6Imh0dHBzOlwvXC9lbi53aWtpcGVkaWEub3JnXC93aWtpXC9Pb21wYV9Mb29tcGFzPyIsImljb24iOiI8aW1nIHNyYz1cImh0dHBzOlwvXC93d3cuc2ltcGxlbWFjaGluZXMub3JnXC9pbWFnZXNcL29vbXBhLmdpZlwiIGFsdD1cIkknbSBhbiBPb21wYSBMb29tcGFcIiBcLz4ifQ=='), true);
135
						}
136
						elseif (isset($area['icon']))
137
						{
138
							if (file_exists($settings['theme_dir'] . '/images/admin/' . $area['icon']))
139
							{
140
								$menu_context['sections'][$section_id]['areas'][$area_id]['icon'] = '<img src="' . $settings['images_url'] . '/admin/' . $area['icon'] . '" alt="">';
141
							}
142
							elseif (file_exists($settings['default_theme_dir'] . '/images/admin/' . $area['icon']))
143
							{
144
								$menu_context['sections'][$section_id]['areas'][$area_id]['icon'] = '<img src="' . $settings['default_images_url'] . '/admin/' . $area['icon'] . '" alt="">';
145
							}
146
							else
147
								$menu_context['sections'][$section_id]['areas'][$area_id]['icon'] = '<span class="generic_icons ' . $area['icon'] . '"></span>';
148
						}
149
						else
150
							$menu_context['sections'][$section_id]['areas'][$area_id]['icon'] = '<span class="generic_icons ' . $area_id . '"></span>';
151
152
						if (isset($area['icon_class']) && empty($menu_context['sections'][$section_id]['areas'][$area_id]['icon']))
153
						{
154
							$menu_context['sections'][$section_id]['areas'][$area_id]['icon_class'] = $menu_context['current_action'] . '_menu_icon ' . $area['icon_class'];
155
						}
156
						elseif (isset($area['icon']))
157
						{
158
							if (substr($area['icon'], -4) === '.png' || substr($area['icon'], -4) === '.gif')
159
							{
160
								if (file_exists($settings['theme_dir'] . '/images/admin/big/' . $area['icon']))
161
								{
162
									$menu_context['sections'][$section_id]['areas'][$area_id]['icon_file'] = $settings['theme_url'] . '/images/admin/big/' . $area['icon'];
163
								}
164
								elseif (file_exists($settings['default_theme_dir'] . '/images/admin/big/' . $area['icon']))
165
								{
166
									$menu_context['sections'][$section_id]['areas'][$area_id]['icon_file'] = $settings['default_theme_url'] . '/images/admin/big/' . $area['icon'];
167
								}
168
							}
169
170
							$menu_context['sections'][$section_id]['areas'][$area_id]['icon_class'] = $menu_context['current_action'] . '_menu_icon ' . str_replace(array('.png', '.gif'), '', $area['icon']);
171
						}
172
						else
173
							$menu_context['sections'][$section_id]['areas'][$area_id]['icon_class'] = $menu_context['current_action'] . '_menu_icon ' . str_replace(array('.png', '.gif'), '', $area_id);
174
175
						// This is a shortcut for Font-Icon users so they don't have to re-do whole CSS.
176
						$menu_context['sections'][$section_id]['areas'][$area_id]['plain_class'] = !empty($area['icon']) ? $area['icon'] : '';
177
178
						// Some areas may be listed but not active, which we show as greyed out.
179
						$menu_context['sections'][$section_id]['areas'][$area_id]['inactive'] = !empty($area['inactive']);
180
181
						// Did it have subsections?
182
						if (!empty($area['subsections']))
183
						{
184
							$menu_context['sections'][$section_id]['areas'][$area_id]['subsections'] = array();
185
							$first_sa = $last_sa = null;
186
							foreach ($area['subsections'] as $sa => $sub)
187
							{
188
								if ((empty($sub[1]) || allowedTo($sub[1])) && (!isset($sub['enabled']) || !empty($sub['enabled'])))
189
								{
190
									if ($first_sa == null)
191
										$first_sa = $sa;
192
193
									$menu_context['sections'][$section_id]['areas'][$area_id]['subsections'][$sa] = array('label' => $sub[0]);
194
									// Custom URL?
195
									if (isset($sub['url']))
196
										$menu_context['sections'][$section_id]['areas'][$area_id]['subsections'][$sa]['url'] = $sub['url'];
197
198
									// Is there a counter amount to show for this subsection?
199
									if (!empty($sub['amt']))
200
										$menu_context['sections'][$section_id]['areas'][$area_id]['subsections'][$sa]['amt'] = $sub['amt'];
201
202
									// A bit complicated - but is this set?
203
									if ($menu_context['current_area'] == $area_id)
204
									{
205
										// Save which is the first...
206
										if (empty($first_sa))
207
											$first_sa = $sa;
208
209
										// Is this the current subsection?
210
										if (isset($_REQUEST['sa']) && $_REQUEST['sa'] == $sa)
211
											$menu_context['current_subsection'] = $sa;
212
										// Otherwise is it the default?
213
										elseif (!isset($menu_context['current_subsection']) && !empty($sub[2]))
214
											$menu_context['current_subsection'] = $sa;
215
									}
216
217
									// Let's assume this is the last, for now.
218
									$last_sa = $sa;
219
								}
220
								// Mark it as disabled...
221
								else
222
									$menu_context['sections'][$section_id]['areas'][$area_id]['subsections'][$sa]['disabled'] = true;
223
							}
224
225
							// Set which one is first, last and selected in the group.
226
							if (!empty($menu_context['sections'][$section_id]['areas'][$area_id]['subsections']))
227
							{
228
								$menu_context['sections'][$section_id]['areas'][$area_id]['subsections'][$context['right_to_left'] ? $last_sa : $first_sa]['is_first'] = true;
229
								$menu_context['sections'][$section_id]['areas'][$area_id]['subsections'][$context['right_to_left'] ? $first_sa : $last_sa]['is_last'] = true;
230
231
								if ($menu_context['current_area'] == $area_id && !isset($menu_context['current_subsection']))
232
									$menu_context['current_subsection'] = $first_sa;
233
							}
234
						}
235
					}
236
				}
237
238
				// Is this the current section?
239
				if ($menu_context['current_area'] == $area_id && empty($found_section))
240
				{
241
					// Only do this once?
242
					$found_section = true;
243
244
					// Update the context if required - as we can have areas pretending to be others. ;)
245
					$menu_context['current_section'] = $section_id;
246
					$menu_context['current_area'] = isset($area['select']) ? $area['select'] : $area_id;
247
248
					// This will be the data we return.
249
					$include_data = $area;
250
				}
251
				// Make sure we have something in case it's an invalid area.
252
				elseif (empty($found_section) && empty($include_data))
253
				{
254
					$menu_context['current_section'] = $section_id;
255
					$backup_area = isset($area['select']) ? $area['select'] : $area_id;
256
					$include_data = $area;
257
				}
258
			}
259
		}
260
	}
261
262
	// Should we use a custom base url, or use the default?
263
	$menu_context['base_url'] = isset($menuOptions['base_url']) ? $menuOptions['base_url'] : $scripturl . '?action=' . $menu_context['current_action'];
264
265
	// If we didn't find the area we were looking for go to a default one.
266
	if (isset($backup_area) && empty($found_section))
267
		$menu_context['current_area'] = $backup_area;
268
269
	// If there are sections quickly goes through all the sections to check if the base menu has an url
270
	if (!empty($menu_context['current_section']))
271
	{
272
		$menu_context['sections'][$menu_context['current_section']]['selected'] = true;
273
		$menu_context['sections'][$menu_context['current_section']]['areas'][$menu_context['current_area']]['selected'] = true;
274
		if (!empty($menu_context['sections'][$menu_context['current_section']]['areas'][$menu_context['current_area']]['subsections'][$context['current_subaction']]))
275
			$menu_context['sections'][$menu_context['current_section']]['areas'][$menu_context['current_area']]['subsections'][$context['current_subaction']]['selected'] = true;
276
277
		foreach ($menu_context['sections'] as $section_id => $section)
278
			foreach ($section['areas'] as $area_id => $area)
279
			{
280
				if (!isset($menu_context['sections'][$section_id]['url']))
281
				{
282
					$menu_context['sections'][$section_id]['url'] = isset($area['url']) ? $area['url'] : $menu_context['base_url'] . ';area=' . $area_id;
283
					break;
284
				}
285
			}
286
	}
287
288
	// If still no data then return - nothing to show!
289
	if (empty($menu_context['sections']))
290
	{
291
		// Never happened!
292
		$context['max_menu_id']--;
293
		if ($context['max_menu_id'] == 0)
294
			unset($context['max_menu_id']);
295
296
		return false;
297
	}
298
299
	// Almost there - load the template and add to the template layers.
300
	loadTemplate(isset($menuOptions['template_name']) ? $menuOptions['template_name'] : 'GenericMenu');
301
	$menu_context['layer_name'] = (isset($menuOptions['layer_name']) ? $menuOptions['layer_name'] : 'generic_menu') . '_dropdown';
302
	$context['template_layers'][] = $menu_context['layer_name'];
303
304
	// Check we had something - for sanity sake.
305
	if (empty($include_data))
306
		return false;
307
308
	// Finally - return information on the selected item.
309
	$include_data += array(
310
		'current_action' => $menu_context['current_action'],
311
		'current_area' => $menu_context['current_area'],
312
		'current_section' => $menu_context['current_section'],
313
		'current_subsection' => !empty($menu_context['current_subsection']) ? $menu_context['current_subsection'] : '',
314
	);
315
316
	return $include_data;
317
}
318
319
/**
320
 * Delete a menu.
321
 * @param string $menu_id The ID of the menu to destroy or 'last' for the most recent one
322
 * @return bool|void False if the menu doesn't exist, nothing otherwise
323
 */
324
function destroyMenu($menu_id = 'last')
325
{
326
	global $context;
327
328
	$menu_name = $menu_id == 'last' && isset($context['max_menu_id']) && isset($context['menu_data_' . $context['max_menu_id']]) ? 'menu_data_' . $context['max_menu_id'] : 'menu_data_' . $menu_id;
329
	if (!isset($context[$menu_name]))
330
		return false;
331
332
	$layer_index = array_search($context[$menu_name]['layer_name'], $context['template_layers']);
333
	if ($layer_index !== false)
334
		unset($context['template_layers'][$layer_index]);
335
336
	unset($context[$menu_name]);
337
}
338
339
?>