ManageUltimateMenu::EditButton()   A
last analyzed

Complexity

Conditions 3
Paths 4

Size

Total Lines 26
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 20
c 2
b 0
f 0
dl 0
loc 26
ccs 0
cts 20
cp 0
rs 9.6
cc 3
nc 4
nop 0
crap 12
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * @package   Ultimate Menu mod
7
 * @version   2.0.2
8
 * @author    John Rayes <[email protected]>
9
 * @copyright Copyright (c) 2014, John Rayes
10
 * @license   http://opensource.org/licenses/MIT MIT
11
 */
12
class ManageUltimateMenu
13
{
14
	private UltimateMenu $um;
15
16 1
	public function __construct(string $sa)
17
	{
18
		global $context, $txt;
19
20 1
		isAllowedTo('admin_forum');
21
22 1
		$context['page_title'] = $txt['admin_menu_title'];
23 1
		$context[$context['admin_menu_name']]['tab_data'] = [
24 1
			'title' => $txt['admin_menu'],
25 1
			'description' => $txt['admin_menu_desc'],
26
			'tabs' => [
27
				'manmenu' => [
28 1
					'description' => $txt['admin_manage_menu_desc'],
29
				],
30
				'addbutton' => [
31 1
					'description' => $txt['admin_menu_add_button_desc'],
32
				],
33
			],
34
		];
35 1
		$this->um = new UltimateMenu;
36
37 1
		$subActions = [
38
			'manmenu' => 'ManageMenu',
39
			'addbutton' => 'AddButton',
40
			'editbutton' => 'EditButton',
41
			'savebutton' => 'SaveButton',
42
		];
43 1
		call_user_func([$this, $subActions[$sa] ?? current($subActions)]);
44
	}
45
46
	public function ManageMenu(): void
47
	{
48
		// Get rid of all of em!
49
		if (isset($_POST['removeAll']))
50
		{
51
			checkSession();
52
			$this->um->deleteallButtons();
53
			$this->um->rebuildMenu();
54
			redirectexit('action=admin;area=umen');
55
		}
56
		// User pressed the 'remove selection button'.
57
		elseif (isset($_POST['removeButtons'], $_POST['remove']) && is_array($_POST['remove']))
58
		{
59
			checkSession();
60
			$this->um->deleteButton(array_filter($_POST['remove'], 'ctype_digit'));
61
			$this->um->rebuildMenu();
62
			redirectexit('action=admin;area=umen');
63
		}
64
		// Changing the status?
65
		elseif (isset($_POST['save']))
66
		{
67
			checkSession();
68
			$this->um->updateButton($_POST);
69
			$this->um->rebuildMenu();
70
			redirectexit('action=admin;area=umen');
71
		}
72
		// New item?
73
		elseif (isset($_POST['new']))
74
			redirectexit('action=admin;area=umen;sa=addbutton');
75
76
		$this->listButtons();
77
	}
78
79
	private function listButtons(): void
80
	{
81
		global $context, $txt, $scripturl, $sourcedir;
82
83
		$button_names = $this->um->getButtonNames();
84
		$listOptions = [
85
			'id' => 'menu_list',
86
			'items_per_page' => 20,
87
			'base_href' => $scripturl . '?action=admin;area=umen;sa=manmenu',
88
			'default_sort_col' => 'name',
89
			'default_sort_dir' => 'desc',
90
			'get_items' => [
91
				'function' => [$this->um, 'list_getMenu'],
92
			],
93
			'get_count' => [
94
				'function' => [$this->um, 'list_getNumButtons'],
95
			],
96
			'no_items_label' => $txt['um_menu_no_buttons'],
97
			'columns' => [
98
				'name' => [
99
					'header' => [
100
						'value' => $txt['um_menu_button_name'],
101
					],
102
					'data' => [
103
						'db_htmlsafe' => 'name',
104
					],
105
					'sort' => [
106
						'default' => 'name',
107
						'reverse' => 'name DESC',
108
					],
109
				],
110
				'type' => [
111
					'header' => [
112
						'value' => $txt['um_menu_button_type'],
113
					],
114
					'data' => [
115
						'function' => fn($rowData): string => $txt['um_menu_' . $rowData['type'] . '_link'],
116
					],
117
					'sort' => [
118
						'default' => 'type',
119
						'reverse' => 'type DESC',
120
					],
121
				],
122
				'position' => [
123
					'header' => [
124
						'value' => $txt['um_menu_button_position'],
125
					],
126
					'data' => [
127
						'function' => fn(array $rowData): string =>
128
							sprintf(
129
								'%s %s',
130
								$txt['um_menu_' . $rowData['position']],
131
								isset($button_names[$rowData['parent']])
132
									? $button_names[$rowData['parent']][1]
133
									: ucwords($rowData['parent'])
134
							),
135
					],
136
					'sort' => [
137
						'default' => 'position',
138
						'reverse' => 'position DESC',
139
					],
140
				],
141
				'status' => [
142
					'header' => [
143
						'value' => $txt['um_menu_button_active'],
144
						'class' => 'centertext',
145
					],
146
					'data' => [
147
						'function' => fn(array $rowData): string =>
148
							sprintf(
149
								'<input type="checkbox" name="status[%1$s]" id="status_%1$s" value="%1$s"%2$s />',
150
								$rowData['id_button'],
151
								$rowData['status'] == 'inactive' ? '' : ' checked="checked"'
152
							),
153
						'class' => 'centertext',
154
					],
155
					'sort' => [
156
						'default' => 'status',
157
						'reverse' => 'status DESC',
158
					],
159
				],
160
				'actions' => [
161
					'header' => [
162
						'value' => $txt['um_menu_actions'],
163
						'class' => 'centertext',
164
					],
165
					'data' => [
166
						'function' => fn(array $rowData): string =>
167
							sprintf(
168
								'<a href="%s?action=admin;area=umen;sa=editbutton;in=%d">%s</a>',
169
								$scripturl,
170
								$rowData['id_button'],
171
								$txt['modify']
172
							),
173
						'class' => 'centertext',
174
					],
175
				],
176
				'check' => [
177
					'header' => [
178
						'value' => '<input type="checkbox" onclick="invertAll(this, this.form);" class="input_check" />',
179
						'class' => 'centertext',
180
					],
181
					'data' => [
182
						'sprintf' => [
183
							'format' => '<input type="checkbox" name="remove[]" value="%d" class="input_check" />',
184
							'params' => [
185
								'id_button' => false,
186
							],
187
						],
188
						'class' => 'centertext',
189
					],
190
				],
191
			],
192
			'form' => [
193
				'href' => $scripturl . '?action=admin;area=umen;sa=manmenu',
194
			],
195
			'additional_rows' => [
196
				[
197
					'position' => 'below_table_data',
198
					'value' => sprintf(
199
						'
200
						<input type="submit" name="removeButtons" value="%s" onclick="return confirm(\'%s\');" class="button" />
201
						<input type="submit" name="removeAll" value="%s" onclick="return confirm(\'%s\');" class="button" />
202
						<input type="submit" name="new" value="%s" class="button" />
203
						<input type="submit" name="save" value="%s" class="button" />',
204
						$txt['um_menu_remove_selected'],
205
						$txt['um_menu_remove_confirm'],
206
						$txt['um_menu_remove_all'],
207
						$txt['um_menu_remove_all_confirm'],
208
						$txt['um_admin_add_button'],
209
						$txt['save']
210
					),
211
					'class' => 'righttext',
212
				],
213
			],
214
		];
215
		require_once $sourcedir . '/Subs-List.php';
216
		createList($listOptions);
217
		$context['sub_template'] = 'show_list';
218
		$context['default_list'] = 'menu_list';
219
	}
220
221
	private function getInput(): array
222
	{
223
		$member_groups = $this->um->listGroups([-3]);
224
		$button_names = $this->um->getButtonNames();
225
		$args = [
226
			'in' => FILTER_VALIDATE_INT,
227
			'name' => FILTER_UNSAFE_RAW,
228
			'position' => [
229
				'filter' => FILTER_CALLBACK,
230
				'options' => fn($v) => in_array($v, ['before', 'child_of', 'after']) ? $v : false,
231
			],
232
			'parent' => [
233
				'filter' => FILTER_CALLBACK,
234
				'options' => fn($v) => isset($button_names[$v]) ? $v : false,
235
			],
236
			'type' => [
237
				'filter' => FILTER_CALLBACK,
238
				'options' => fn($v) => in_array($v, ['forum', 'external']) ? $v : false,
239
			],
240
			'link' => FILTER_UNSAFE_RAW,
241
			'permissions' => [
242
				'filter' => FILTER_CALLBACK,
243
				'flags' => FILTER_REQUIRE_ARRAY,
244
				'options' => fn($v) => isset($member_groups[$v]) ? $v : false,
245
			],
246
			'status' => [
247
				'filter' => FILTER_CALLBACK,
248
				'options' => fn($v) => in_array($v, ['active', 'inactive']) ? $v : false,
249
			],
250
			'target' => [
251
				'filter' => FILTER_CALLBACK,
252
				'options' => fn($v) => in_array($v, ['_self', '_blank']) ? $v : false,
253
			],
254
		];
255
256
		return filter_input_array(INPUT_POST, $args, FALSE) ?: [];
257
	}
258
259
	private function validateInput(array $menu_entry): array
260
	{
261
		$post_errors = [];
262
		$required_fields = [
263
			'name',
264
			'link',
265
			'parent',
266
		];
267
268
		// If your session timed out, show an error, but do allow to re-submit.
269
		if (checkSession('post', '', false) != '')
270
			$post_errors[] = 'um_menu_session_verify_fail';
271
272
		// These fields are required!
273
		foreach ($required_fields as $required_field)
274
			if (empty($menu_entry[$required_field]))
275
				$post_errors[$required_field] = 'um_menu_empty_' . $required_field;
276
277
		// Stop making numeric names!
278
		if (is_numeric($menu_entry['name']))
279
			$post_errors['name'] = 'um_menu_numeric';
280
281
		// Let's make sure you're not trying to make a name that's already taken.
282
		if (!empty($this->um->checkButton($menu_entry['in'], $menu_entry['name'])))
283
			$post_errors['name'] = 'um_menu_mysql';
284
285
		return $post_errors;
286
	}
287
288
	public function SaveButton(): void
289
	{
290
		global $context, $txt;
291
292
		if (isset($_POST['submit']))
293
		{
294
			$menu_entry = array_replace(
295
				[
296
					'target' => '_self',
297
					'type' => 'forum',
298
					'position' => 'before',
299
					'permissions' => [],
300
					'status' => 'active',
301
					'parent' => '',
302
				],
303
				$this->getInput()
304
			);
305
			$post_errors = $this->validateInput($menu_entry);
306
307
			// I see you made it to the final stage, my young padawan.
308
			if (empty($post_errors))
309
			{
310
				$this->um->saveButton($menu_entry);
311
				$this->um->rebuildMenu();
312
313
				// Before we leave, we must clear the cache. See, SMF
314
				// caches its menu at level 2 or higher.
315
				clean_cache('menu_buttons');
316
317
				redirectexit('action=admin;area=umen');
318
			}
319
			else
320
			{
321
				$context['page_title'] = $txt['um_menu_edit_title'];
322
				$context['button_names'] = $this->um->getButtonNames();
323
				$context['post_error'] = $post_errors;
324
				$context['error_title'] = empty($menu_entry['in'])
325
					? 'um_menu_errors_create'
326
					: 'um_menu_errors_modify';
327
				$context['button_data'] = [
328
					'name' => $menu_entry['name'],
329
					'type' => $menu_entry['type'],
330
					'target' => $menu_entry['target'],
331
					'position' => $menu_entry['position'],
332
					'link' => $menu_entry['link'],
333
					'parent' => $menu_entry['parent'],
334
					'permissions' => $this->um->listGroups(
335
						array_filter($menu_entry['permissions'], 'strlen')
336
					),
337
					'status' => $menu_entry['status'],
338
					'id' => $menu_entry['in'],
339
				];
340
				$context['all_groups_checked'] = empty(array_diff_key(
341
					$context['button_data']['permissions'],
342
					array_flip(array_filter($menu_entry['permissions'], 'strlen'))
343
				));
344
				$context['template_layers'][] = 'form';
345
				$context['template_layers'][] = 'errors';
346
			}
347
		}
348
		else
349
			fatal_lang_error('no_access', false);
350
	}
351
352
	public function EditButton(): void
353
	{
354
		global $context, $txt;
355
356
		$row = isset($_GET['in']) ? $this->um->fetchButton($_GET['in']) : [];
357
		if (empty($row))
358
			fatal_lang_error('no_access', false);
359
360
		$context['button_data'] = [
361
			'id' => $row['id'],
362
			'name' => $row['name'],
363
			'target' => $row['target'],
364
			'type' => $row['type'],
365
			'position' => $row['position'],
366
			'permissions' => $this->um->listGroups($row['permissions']),
367
			'link' => $row['link'],
368
			'status' => $row['status'],
369
			'parent' => $row['parent'],
370
		];
371
		$context['all_groups_checked'] = empty(array_diff_key(
372
			$context['button_data']['permissions'],
373
			array_flip($row['permissions'])
374
		));
375
		$context['page_title'] = $txt['um_menu_edit_title'];
376
		$context['button_names'] = $this->um->getButtonNames();
377
		$context['template_layers'][] = 'form';
378
	}
379
380
	public function AddButton(): void
381
	{
382
		global $context, $txt;
383
384
		$context['button_data'] = [
385
			'name' => '',
386
			'link' => '',
387
			'target' => '_self',
388
			'type' => 'forum',
389
			'position' => 'before',
390
			'status' => 'active',
391
			'permissions' => $this->um->listGroups([-3]),
392
			'parent' => 'home',
393
			'id' => 0,
394
		];
395
		$context['all_groups_checked'] = true;
396
		$context['page_title'] = $txt['um_menu_add_title'];
397
		$context['button_names'] = $this->um->getButtonNames();
398
		$context['template_layers'][] = 'form';
399
	}
400
}
401