Completed
Push — master ( 4b4f40...0df9bd )
by Matt
01:53 queued 11s
created

admin_controller   B

Complexity

Total Complexity 44

Size/Duplication

Total Lines 500
Duplicated Lines 2.2 %

Coupling/Cohesion

Components 1
Dependencies 1

Importance

Changes 0
Metric Value
wmc 44
lcom 1
cbo 1
dl 11
loc 500
rs 8.8798
c 0
b 0
f 0

17 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 14 1
A display_autogroups() 0 34 2
B save_autogroup_rule() 0 48 5
A delete_autogroup_rule() 0 23 2
A resync_autogroup_rule() 0 17 3
A submit_autogroups_options() 0 20 2
A get_autogroup() 0 11 2
A get_all_autogroups() 0 20 1
A set_exempt_groups() 0 13 2
A get_exempt_groups() 4 11 2
A get_excluded_groups() 7 19 4
A build_groups_menu() 0 16 4
A build_conditions_menu() 0 14 2
A query_groups() 0 13 3
B submit_autogroup_rule() 0 56 6
A get_back_link() 0 6 2
A set_page_url() 0 4 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like admin_controller often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use admin_controller, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
*
4
* Auto Groups extension for the phpBB Forum Software package.
5
*
6
* @copyright (c) 2014 phpBB Limited <https://www.phpbb.com>
7
* @license GNU General Public License, version 2 (GPL-2.0)
8
*
9
*/
10
11
namespace phpbb\autogroups\controller;
12
13
/**
14
 * Admin controller
15
 */
16
class admin_controller implements admin_interface
17
{
18
	/** @var \phpbb\cache\driver\driver_interface */
19
	protected $cache;
20
21
	/** @var \phpbb\db\driver\driver_interface */
22
	protected $db;
23
24
	/** @var \phpbb\group\helper */
25
	protected $group_helper;
26
27
	/** @var \phpbb\language\language */
28
	protected $language;
29
30
	/** @var \phpbb\log\log */
31
	protected $log;
32
33
	/** @var \phpbb\autogroups\conditions\manager */
34
	protected $manager;
35
36
	/** @var \phpbb\request\request */
37
	protected $request;
38
39
	/** @var \phpbb\template\template */
40
	protected $template;
41
42
	/** @var \phpbb\user */
43
	protected $user;
44
45
	/** @var string The database table the auto group rules are stored in */
46
	protected $autogroups_rules_table;
47
48
	/** @var string The database table the auto group types are stored in */
49
	protected $autogroups_types_table;
50
51
	/** @var string Custom form action */
52
	protected $u_action;
53
54
	/**
55
	 * Constructor
56
	 *
57
	 * @param \phpbb\cache\driver\driver_interface $cache                    Cache driver interface
58
	 * @param \phpbb\db\driver\driver_interface    $db                       Database object
59
	 * @param \phpbb\group\helper                  $group_helper             Group helper object
60
	 * @param \phpbb\language\language             $language                 Language object
61
	 * @param \phpbb\log\log                       $log                      The phpBB log system
62
	 * @param \phpbb\autogroups\conditions\manager $manager                  Auto groups condition manager object
63
	 * @param \phpbb\request\request               $request                  Request object
64
	 * @param \phpbb\template\template             $template                 Template object
65
	 * @param \phpbb\user                          $user                     User object
66
	 * @param string                               $autogroups_rules_table   Name of the table used to store auto group rules data
67
	 * @param string                               $autogroups_types_table   Name of the table used to store auto group types data
68
	 * @access public
69
	 */
70
	public function __construct(\phpbb\cache\driver\driver_interface $cache, \phpbb\db\driver\driver_interface $db, \phpbb\group\helper $group_helper, \phpbb\language\language $language, \phpbb\log\log $log, \phpbb\autogroups\conditions\manager $manager, \phpbb\request\request $request, \phpbb\template\template $template, \phpbb\user $user, $autogroups_rules_table, $autogroups_types_table)
71
	{
72
		$this->cache = $cache;
73
		$this->db = $db;
74
		$this->group_helper = $group_helper;
75
		$this->language = $language;
76
		$this->log = $log;
77
		$this->manager = $manager;
78
		$this->request = $request;
79
		$this->template = $template;
80
		$this->user = $user;
81
		$this->autogroups_rules_table = $autogroups_rules_table;
82
		$this->autogroups_types_table = $autogroups_types_table;
83
	}
84
85
	/**
86
	 * {@inheritdoc}
87
	 */
88
	public function display_autogroups()
89
	{
90
		// Get all auto groups data from the database
91
		$autogroup_rows = $this->get_all_autogroups();
92
93
		// Process all auto groups data for display in the template
94
		foreach ($autogroup_rows as $row)
95
		{
96
			$this->template->assign_block_vars('autogroups', array(
97
				'GROUP_NAME'		=> $row['group_name'],
98
				'CONDITION_NAME'	=> $this->manager->get_condition_lang($row['autogroups_type_name']),
99
				'MIN_VALUE'			=> $row['autogroups_min_value'],
100
				'MAX_VALUE'			=> $row['autogroups_max_value'],
101
102
				'S_DEFAULT'	=> $row['autogroups_default'],
103
				'S_NOTIFY'	=> $row['autogroups_notify'],
104
105
				'EXCLUDED_GROUPS'	=> implode('<br>', $this->get_excluded_groups($row['autogroups_excluded_groups'])),
106
107
				'U_EDIT'	=> "{$this->u_action}&amp;action=edit&amp;autogroups_id=" . $row['autogroups_id'],
108
				'U_DELETE'	=> "{$this->u_action}&amp;action=delete&amp;autogroups_id=" . $row['autogroups_id'],
109
				'U_SYNC'	=> "{$this->u_action}&amp;action=sync&amp;autogroups_id=" . $row['autogroups_id'] . '&amp;hash=' . generate_link_hash('sync' . $row['autogroups_id']),
110
			));
111
		}
112
113
		$this->template->assign_vars(array(
114
			'U_ACTION'				=> $this->u_action,
115
			'U_ADD_AUTOGROUP_RULE'	=> "{$this->u_action}&amp;action=add",
116
		));
117
118
		// Display the group exemption select box
119
		$exempt_groups = $this->get_exempt_groups();
120
		$this->build_groups_menu(array_keys($exempt_groups));
121
	}
122
123
	/**
124
	 * {@inheritdoc}
125
	 */
126
	public function save_autogroup_rule($autogroups_id = 0)
127
	{
128
		// Process auto group form data if form was submitted
129
		if ($this->request->is_set_post('submit'))
130
		{
131
			$this->submit_autogroup_rule($autogroups_id);
132
		}
133
134
		// Get data for the auto group so we can display it
135
		$autogroups_data = $this->get_autogroup($autogroups_id);
136
137
		// If we have no auto group data yet, zero out all default values
138
		if (empty($autogroups_data))
139
		{
140
			$autogroups_data = array_fill_keys([
141
				'autogroups_group_id',
142
				'autogroups_type_id',
143
				'autogroups_min_value',
144
				'autogroups_max_value',
145
				'autogroups_default',
146
				'autogroups_notify',
147
			], 0);
148
		}
149
150
		// Format autogroups_excluded_groups specifically to be an array type
151
		$autogroups_data['autogroups_excluded_groups'] = !empty($autogroups_data['autogroups_excluded_groups']) ? json_decode($autogroups_data['autogroups_excluded_groups'], true) : array();
152
153
		// Process the auto group data for display in the template
154
		$this->build_groups_menu($autogroups_data['autogroups_excluded_groups'], false, 'excluded_groups');
155
		$this->build_groups_menu(array($autogroups_data['autogroups_group_id']), true);
156
		$this->build_conditions_menu($autogroups_data['autogroups_type_id']);
157
		$this->template->assign_vars(array(
158
			'S_ADD'			=> (bool) !$autogroups_id,
159
			'S_EDIT'		=> (bool) $autogroups_id,
160
161
			'MIN_VALUE'		=> (int) $autogroups_data['autogroups_min_value'],
162
			'MAX_VALUE'		=> (int) $autogroups_data['autogroups_max_value'],
163
164
			'S_DEFAULT'		=> (bool) $autogroups_data['autogroups_default'],
165
			'S_NOTIFY'		=> (bool) $autogroups_data['autogroups_notify'],
166
167
			'EXEMPT_GROUPS'	=> implode(', ', $this->get_exempt_groups()),
168
169
			'U_FORM_ACTION'	=> $this->u_action . '&amp;action=' . ($autogroups_id ? 'edit' : 'add') . '&amp;autogroups_id=' . $autogroups_id,
170
			'U_ACTION'		=> $this->u_action,
171
			'U_BACK'		=> $this->u_action,
172
		));
173
	}
174
175
	/**
176
	 * {@inheritdoc}
177
	 */
178
	public function delete_autogroup_rule($autogroups_id)
179
	{
180
		// Delete and auto group rule
181
		$sql = 'DELETE FROM ' . $this->autogroups_rules_table . '
182
			WHERE autogroups_id = ' . (int) $autogroups_id;
183
		$this->db->sql_query($sql);
184
185
		// Log the action
186
		$this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'ACP_AUTOGROUPS_DELETE_LOG', time());
187
188
		// If AJAX was used, show user a result message
189
		if ($this->request->is_ajax())
190
		{
191
			$json_response = new \phpbb\json_response;
192
			$json_response->send(array(
193
				'MESSAGE_TITLE'	=> $this->language->lang('INFORMATION'),
194
				'MESSAGE_TEXT'	=> $this->language->lang('ACP_AUTOGROUPS_DELETE_SUCCESS'),
195
				'REFRESH_DATA'	=> array(
196
					'time'	=> 3
197
				)
198
			));
199
		}
200
	}
201
202
	/**
203
	 * {@inheritdoc}
204
	 */
205
	public function resync_autogroup_rule($autogroups_id)
206
	{
207
		// If the link hash is invalid, stop and show an error message to the user
208
		if (!check_link_hash($this->request->variable('hash', ''), 'sync' . $autogroups_id))
209
		{
210
			trigger_error($this->language->lang('FORM_INVALID') . $this->get_back_link(), E_USER_WARNING);
211
		}
212
213
		try
214
		{
215
			$this->manager->sync_autogroups($autogroups_id);
216
		}
217
		catch (\Exception $e)
218
		{
219
			trigger_error($e->getMessage() . $this->get_back_link(), E_USER_WARNING);
220
		}
221
	}
222
223
	/**
224
	 * {@inheritdoc}
225
	 */
226
	public function submit_autogroups_options()
227
	{
228
		// Get data from the form
229
		$group_ids = $this->request->variable('group_ids', array(0));
230
231
		// Use a confirmation box routine before setting the data
232
		if (confirm_box(true))
233
		{
234
			// Set selected groups to true, unselected to false
235
			$this->set_exempt_groups($group_ids);
236
			$this->cache->destroy('sql', GROUPS_TABLE);
237
		}
238
		else
239
		{
240
			confirm_box(false, $this->language->lang('CONFIRM_OPERATION'), build_hidden_fields(array(
241
				'generalsubmit' => true,
242
				'group_ids' => $group_ids,
243
			)));
244
		}
245
	}
246
247
	/**
248
	 * Submit auto group rule form data
249
	 *
250
	 * @param int $autogroups_id An auto group identifier
251
	 *                           A value of 0 is new, otherwise we're updating
252
	 * @return void
253
	 * @access protected
254
	 */
255
	protected function submit_autogroup_rule($autogroups_id = 0)
256
	{
257
		$data = array(
258
			'autogroups_type_id'	=> $this->request->variable('autogroups_type_id', 0),
259
			'autogroups_min_value'	=> $this->request->variable('autogroups_min_value', 0),
260
			'autogroups_max_value'	=> $this->request->variable('autogroups_max_value', 0),
261
			'autogroups_group_id'	=> $this->request->variable('autogroups_group_id', 0),
262
			'autogroups_default'	=> $this->request->variable('autogroups_default', false),
263
			'autogroups_notify'		=> $this->request->variable('autogroups_notify', false),
264
			'autogroups_excluded_groups' => $this->request->variable('autogroups_excluded_groups', array(0)),
265
		);
266
267
		// Prevent form submit when no user groups are available or selected
268
		if (!$data['autogroups_group_id'])
269
		{
270
			trigger_error($this->language->lang('ACP_AUTOGROUPS_INVALID_GROUPS') . $this->get_back_link($autogroups_id), E_USER_WARNING);
271
		}
272
273
		// Prevent form submit when min and max values are identical
274
		if ($data['autogroups_min_value'] == $data['autogroups_max_value'])
275
		{
276
			trigger_error($this->language->lang('ACP_AUTOGROUPS_INVALID_RANGE') . $this->get_back_link($autogroups_id), E_USER_WARNING);
277
		}
278
279
		// Prevent form submit when the target group is also in the excluded groups array
280
		if (in_array($data['autogroups_group_id'], $data['autogroups_excluded_groups']))
281
		{
282
			trigger_error($this->language->lang('ACP_AUTOGROUPS_INVALID_EXCLUDE_GROUPS') . $this->get_back_link($autogroups_id), E_USER_WARNING);
283
		}
284
285
		// Format autogroups_excluded_groups for storage in the db
286
		$data['autogroups_excluded_groups'] = !empty($data['autogroups_excluded_groups']) ? json_encode($data['autogroups_excluded_groups']) : '';
287
288
		if ($autogroups_id != 0) // Update existing auto group data
289
		{
290
			$sql = 'UPDATE ' . $this->autogroups_rules_table . '
291
				SET ' . $this->db->sql_build_array('UPDATE', $data) . '
292
				WHERE autogroups_id = ' . (int) $autogroups_id;
293
			$this->db->sql_query($sql);
294
		}
295
		else // Insert new auto group data
296
		{
297
			$sql = 'INSERT INTO ' . $this->autogroups_rules_table . ' ' . $this->db->sql_build_array('INSERT', $data);
298
			$this->db->sql_query($sql);
299
			$autogroups_id = (int) $this->db->sql_nextid();
300
		}
301
302
		// Apply the auto group to all users
303
		$this->manager->sync_autogroups($autogroups_id);
304
305
		// Log the action
306
		$this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'ACP_AUTOGROUPS_SAVED_LOG', time());
307
308
		// Output message to user after submitting the form
309
		trigger_error($this->language->lang('ACP_AUTOGROUPS_SUBMIT_SUCCESS') . $this->get_back_link());
310
	}
311
312
	/**
313
	 * Get one auto group rule from the database
314
	 *
315
	 * @param int $id An auto group rule identifier
316
	 * @return array An auto group rule and it's associated data
317
	 * @access public
318
	 */
319
	protected function get_autogroup($id)
320
	{
321
		$sql = 'SELECT *
322
			FROM ' . $this->autogroups_rules_table . '
323
			WHERE autogroups_id = ' . (int) $id;
324
		$result = $this->db->sql_query($sql);
325
		$autogroups_data = $this->db->sql_fetchrow($result);
326
		$this->db->sql_freeresult($result);
327
328
		return $autogroups_data ? $autogroups_data : [];
329
	}
330
331
	/**
332
	 * Get all auto group rules from the database
333
	 *
334
	 * @return array Array of auto group rules and their associated data
335
	 * @access public
336
	 */
337
	protected function get_all_autogroups()
338
	{
339
		$sql_array = array(
340
			'SELECT'	=> 'agr.*, agt.autogroups_type_name, g.group_name',
341
			'FROM'	=> array(
342
				$this->autogroups_rules_table => 'agr',
343
				$this->autogroups_types_table => 'agt',
344
				GROUPS_TABLE => 'g',
345
			),
346
			'WHERE'	=> 'agr.autogroups_type_id = agt.autogroups_type_id
347
				AND agr.autogroups_group_id = g.group_id',
348
			'ORDER_BY'	=> 'g.group_name ASC, autogroups_min_value ASC',
349
		);
350
		$sql = $this->db->sql_build_query('SELECT', $sql_array);
351
		$result = $this->db->sql_query($sql);
352
		$rows = $this->db->sql_fetchrowset($result);
353
		$this->db->sql_freeresult($result);
354
355
		return $rows;
356
	}
357
358
	/**
359
	 * Set the user groups marked as exempt from default switching.
360
	 * Sets the 'autogroup_default_exempt' field for all groups in
361
	 * $group_ids to true, while all other groups are set to false.
362
	 *
363
	 * @param array $group_ids An array of group ids
364
	 * @param bool  $flag      True or false
365
	 */
366
	protected function set_exempt_groups($group_ids, $flag = true)
367
	{
368
		$sql = 'UPDATE ' . GROUPS_TABLE . '
369
			SET autogroup_default_exempt = ' . (int) $flag . '
370
			WHERE ' . $this->db->sql_in_set('group_id', $group_ids, !$flag, true);
371
		$this->db->sql_query($sql);
372
373
		// Recursively recall this function with false, to set all other groups to false
374
		if ($flag !== false)
375
		{
376
			$this->set_exempt_groups($group_ids, false);
377
		}
378
	}
379
380
	/**
381
	 * Get an array of user groups marked as exempt from default switching
382
	 *
383
	 * @return array An array of exempted groups: array('group_id' => 'group_name')
384
	 * @access protected
385
	 */
386
	protected function get_exempt_groups()
387
	{
388
		$groups = array();
389
390 View Code Duplication
		foreach ($this->query_groups('autogroup_default_exempt = 1') as $row)
391
		{
392
			$groups[$row['group_id']] = $this->group_helper->get_name_string('full', $row['group_id'], $row['group_name'], $row['group_colour']);
393
		}
394
395
		return $groups;
396
	}
397
398
	/**
399
	 * Get an array of user groups marked as excluded from auto grouping
400
	 *
401
	 * @param string $excluded_groups A json encoded string of an array of group ids
402
	 * @return array An array of groups: array('group_id' => 'group_name')
403
	 * @access protected
404
	 */
405
	protected function get_excluded_groups($excluded_groups)
406
	{
407
		$groups = array();
408
409
		if (!empty($excluded_groups))
410
		{
411
			$excluded_groups = json_decode($excluded_groups, true);
412
413 View Code Duplication
			foreach ($this->query_groups() as $row)
414
			{
415
				if (in_array($row['group_id'], $excluded_groups))
416
				{
417
					$groups[$row['group_id']] = $this->group_helper->get_name_string('full', $row['group_id'], $row['group_name'], $row['group_colour']);
418
				}
419
			}
420
		}
421
422
		return $groups;
423
	}
424
425
	/**
426
	 * Build template vars for a select menu of user groups
427
	 *
428
	 * @param array  $selected                  An array of identifiers for selected group(s)
429
	 * @param bool   $exclude_predefined_groups Exclude GROUP_SPECIAL
430
	 * @param string $block                     Name of the template block vars array
431
	 * @return void
432
	 * @access protected
433
	 */
434
	protected function build_groups_menu($selected, $exclude_predefined_groups = false, $block = 'groups')
435
	{
436
		foreach ($this->query_groups() as $group)
437
		{
438
			if ($exclude_predefined_groups && $group['group_type'] == GROUP_SPECIAL)
439
			{
440
				continue;
441
			}
442
			$this->template->assign_block_vars($block, array(
443
				'GROUP_ID'		=> $group['group_id'],
444
				'GROUP_NAME'	=> $this->group_helper->get_name($group['group_name']),
445
446
				'S_SELECTED'	=> in_array($group['group_id'], $selected),
447
			));
448
		}
449
	}
450
451
	/**
452
	 * Build template vars for a select menu of auto group conditions
453
	 *
454
	 * @param int $selected An identifier for the selected group
455
	 * @return void
456
	 * @access protected
457
	 */
458
	protected function build_conditions_menu($selected)
459
	{
460
		$conditions = $this->manager->get_autogroups_type_ids();
461
462
		foreach ($conditions as $condition_name => $condition_id)
463
		{
464
			$this->template->assign_block_vars('conditions', array(
465
				'CONDITION_ID'		=> $condition_id,
466
				'CONDITION_NAME'	=> $this->manager->get_condition_lang($condition_name),
467
468
				'S_SELECTED'		=> $condition_id == $selected,
469
			));
470
		}
471
	}
472
473
	/**
474
	 * Get group data, always excluding BOTS, Guests
475
	 *
476
	 * @param string $where_sql Optional additional SQL where conditions
477
	 * @return array An array of group data rows (group_id, group_name, group_type)
478
	 */
479
	protected function query_groups($where_sql = '')
480
	{
481
		$sql = 'SELECT group_id, group_name, group_type, group_colour
482
			FROM ' . GROUPS_TABLE . '
483
			WHERE ' . $this->db->sql_in_set('group_name', array('BOTS', 'GUESTS'), true, true) .
484
				($where_sql ? ' AND ' . $this->db->sql_escape($where_sql) : '') . '
485
			ORDER BY group_name';
486
		$result = $this->db->sql_query($sql, 3600);
487
		$groups = $this->db->sql_fetchrowset($result);
488
		$this->db->sql_freeresult($result);
489
490
		return $groups ?: array();
491
	}
492
493
	/**
494
	 * Return the ACP action back link. For editing an auto group it will take you
495
	 * back to that auto group's edit page. Otherwise it will take you back to main
496
	 * auto groups ACP page.
497
	 *
498
	 * @param int $autogroups_id
499
	 * @return string
500
	 */
501
	protected function get_back_link($autogroups_id = 0)
502
	{
503
		$back_link = $autogroups_id ? '&amp;action=edit&amp;autogroups_id=' . $autogroups_id : '';
504
505
		return adm_back_link($this->u_action . $back_link);
506
	}
507
508
	/**
509
	 * {@inheritdoc}
510
	 */
511
	public function set_page_url($u_action)
512
	{
513
		$this->u_action = $u_action;
514
	}
515
}
516