Completed
Push — master ( 7d4e77...353440 )
by Matt
08:22
created

admin_controller   B

Complexity

Total Complexity 47

Size/Duplication

Total Lines 455
Duplicated Lines 6.37 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 91.26%

Importance

Changes 23
Bugs 0 Features 1
Metric Value
wmc 47
c 23
b 0
f 1
lcom 1
cbo 2
dl 29
loc 455
ccs 188
cts 206
cp 0.9126
rs 8.439

19 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 11 1
A main() 0 14 2
A set_page_url() 0 4 1
A get_page_title() 0 4 1
A action_enable() 0 4 1
A action_disable() 0 4 1
B action_delete() 0 40 5
A list_ads() 0 20 3
B ad_enable() 0 28 6
A get_form_data() 0 10 1
A validate() 0 16 4
A assign_form_data() 0 12 2
A assign_locations() 0 12 3
A success() 0 4 1
A error() 0 4 1
B action_add() 13 40 5
B action_edit() 16 56 7
A ad_preview() 0 4 1
A log() 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
 * Advertisement management. An extension for the phpBB Forum Software package.
5
 *
6
 * @copyright (c) 2017 phpBB Limited <https://www.phpbb.com>
7
 * @license GNU General Public License, version 2 (GPL-2.0)
8
 *
9
 */
10
11
namespace phpbb\admanagement\controller;
12
13
/**
14
* Admin controller
15
*/
16
class admin_controller
17
{
18
	const MAX_NAME_LENGTH = 255;
19
20
	/** @var \phpbb\template\template */
21
	protected $template;
22
23
	/** @var \phpbb\user */
24
	protected $user;
25
26
	/** @var \phpbb\request\request */
27
	protected $request;
28
29
	/** @var \phpbb\admanagement\ad\manager */
30
	protected $manager;
31
32
	/** @var \phpbb\admanagement\location\manager */
33
	protected $location_manager;
34
35
	/** @var \phpbb\log\log */
36
	protected $log;
37
38
	/** @var string php_ext */
39
	protected $php_ext;
40
41
	/** @var string ext_path */
42
	protected $ext_path;
43
44
	/** @var string Custom form action */
45
	protected $u_action;
46
47
	/** @var array Form validation errors */
48
	protected $errors = array();
49
50
	/**
51
	* Constructor
52
	*
53
	* @param \phpbb\template\template				$template			Template object
54
	* @param \phpbb\user							$user				User object
55
	* @param \phpbb\request\request					$request			Request object
56
	* @param \phpbb\admanagement\ad\manager			$manager			Advertisement manager object
57
	* @param \phpbb\admanagement\location\manager	$location_manager	Template location manager object
58
	* @param \phpbb\log\log							$log				The phpBB log system
59
	* @param string									$php_ext			PHP extension
60
	* @param string									$ext_path			Path to this extension
61
	*/
62 29
	public function __construct(\phpbb\template\template $template, \phpbb\user $user, \phpbb\request\request $request, \phpbb\admanagement\ad\manager $manager, \phpbb\admanagement\location\manager $location_manager, \phpbb\log\log $log, $php_ext, $ext_path)
63
	{
64 29
		$this->template = $template;
65 29
		$this->user = $user;
66 29
		$this->request = $request;
67 29
		$this->manager = $manager;
68 29
		$this->location_manager = $location_manager;
69 29
		$this->log = $log;
70 29
		$this->php_ext = $php_ext;
71 29
		$this->ext_path = $ext_path;
72 29
	}
73
74
	/**
75
	* Process user request
76
	*
77
	* @return void
78
	*/
79 6
	public function main()
80
	{
81 6
		$this->user->add_lang_ext('phpbb/admanagement', 'acp');
82
83
		// Trigger specific action
84 6
		$action = $this->request->variable('action', '');
85 6
		if (in_array($action, array('add', 'edit', 'enable', 'disable', 'delete')))
86 6
		{
87 5
			$this->{'action_' . $action}();
88 5
		}
89
90
		// Otherwise default to this
91 6
		$this->list_ads();
92 6
	}
93
94
	/**
95
	* Set page url
96
	*
97
	* @param string $u_action Custom form action
98
	* @return void
99
	*/
100 23
	public function set_page_url($u_action)
101
	{
102 23
		$this->u_action = $u_action;
103 23
	}
104
105
	/**
106
	* Get ACP page title for Ads module
107
	*
108
	* @return string	Language string for Ads ACP module
109
	*/
110 1
	public function get_page_title()
111
	{
112 1
		return $this->user->lang('ACP_ADMANAGEMENT_TITLE');
113
	}
114
115
	/**
116
	* Add an advertisement
117
	*
118
	* @return void
119
	*/
120 6
	public function action_add()
121
	{
122 6
		$preview = $this->request->is_set_post('preview');
123 6
		$submit = $this->request->is_set_post('submit');
124
125 6
		add_form_key('phpbb/admanagement/add');
126 6
		if ($preview || $submit)
127 6
		{
128 5
			$data = $this->get_form_data();
129
130 5
			$this->validate($data, 'phpbb/admanagement/add');
131
132 View Code Duplication
			if ($preview)
1 ignored issue
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
133 5
			{
134 1
				$this->ad_preview($data['ad_code']);
135 1
			}
136
			else if (empty($this->errors))
137 4
			{
138 1
				$ad_id = $this->manager->insert_ad($data);
139 1
				$this->manager->insert_ad_locations($ad_id, $data['ad_locations']);
140
141 1
				$this->log('ADD', $data['ad_name']);
142
143 1
				$this->success('ACP_AD_ADD_SUCCESS');
144
			}
145
146 4
			$this->assign_locations($data);
147 4
			$this->assign_form_data($data);
148 4
		}
149
		else
150
		{
151 1
			$this->assign_locations();
152
		}
153
154
		// Set output vars for display in the template
155 5
		$this->template->assign_vars(array(
156 5
			'S_ADD_AD'	=> true,
157 5
			'U_BACK'	=> $this->u_action,
158 5
		));
159 5
	}
160
161
	/**
162
	* Edit an advertisement
163
	*
164
	* @return void
165
	*/
166 10
	public function action_edit()
167
	{
168 8
		$ad_id = $this->request->variable('id', 0);
169 8
		$preview = $this->request->is_set_post('preview');
170 8
		$submit = $this->request->is_set_post('submit');
171
172 8
		add_form_key('phpbb/admanagement/edit/' . $ad_id);
173 8
		if ($preview || $submit)
174 8
		{
175 6
			$data = $this->get_form_data();
176
177 6
			$this->validate($data, 'phpbb/admanagement/edit/' . $ad_id);
178
179
			if ($preview)
180 6
			{
181 1
				$this->ad_preview($data['ad_code']);
182 1
			}
183 View Code Duplication
			else if (empty($this->errors))
1 ignored issue
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
184 5
			{
185 2
				$success = $this->manager->update_ad($ad_id, $data);
186
187
				if ($success)
188 2
				{
189
					// Only insert new ad locations to DB when ad exists
190 1
					$this->manager->delete_ad_locations($ad_id);
191 1
					$this->manager->insert_ad_locations($ad_id, $data['ad_locations']);
192
193 1
					$this->log('EDIT', $data['ad_name']);
194
195 1
					$this->success('ACP_AD_EDIT_SUCCESS');
196 10
				}
197 1
				$this->error('ACP_AD_DOES_NOT_EXIST');
198
			}
199 4
		}
200
		else
201
		{
202
			// Load ad data
203 2
			$data = $this->manager->get_ad($ad_id);
204 2
			if (empty($data))
205 2
			{
206 1
				$this->error('ACP_AD_DOES_NOT_EXIST');
207
			}
208
209
			// Load ad template locations
210 1
			$data['ad_locations'] = $this->manager->get_ad_locations($ad_id);
211
		}
212
213
		// Set output vars for display in the template
214 5
		$this->template->assign_vars(array(
215 5
			'S_EDIT_AD'	=> true,
216 5
			'EDIT_ID'	=> $ad_id,
217 5
			'U_BACK'	=> $this->u_action,
218 5
		));
219 5
		$this->assign_locations($data);
220 5
		$this->assign_form_data($data);
221 5
	}
222
223
	/**
224
	* Enable an advertisement
225
	*
226
	* @return void
227
	*/
228 3
	public function action_enable()
229
	{
230 3
		$this->ad_enable(true);
231 1
	}
232
233
	/**
234
	* Disable an advertisement
235
	*
236
	* @return void
237
	*/
238 3
	public function action_disable()
239
	{
240 3
		$this->ad_enable(false);
241 1
	}
242
243
	/**
244
	* Delete an advertisement
245
	*
246
	* @return void
247
	*/
248 3
	public function action_delete()
249
	{
250 3
		$ad_id = $this->request->variable('id', 0);
251
		if ($ad_id)
252 3
		{
253 3
			if (confirm_box(true))
254 3
			{
255
				// Get ad data so that we can log ad name
256 2
				$ad_data = $this->manager->get_ad($ad_id);
257
258
				// Delete ad and it's template locations
259 2
				$this->manager->delete_ad_locations($ad_id);
260 2
				$success = $this->manager->delete_ad($ad_id);
261
262
				// Only notify user on error or if not ajax
263 2
				if (!$success)
264 2
				{
265 1
					$this->error('ACP_AD_DELETE_ERRORED');
266
				}
267
				else
268
				{
269 1
					$this->log('DELETE', $ad_data['ad_name']);
270
271 1
					if (!$this->request->is_ajax())
272 1
					{
273 1
						$this->success('ACP_AD_DELETE_SUCCESS');
274
					}
275
				}
276
			}
277
			else
278
			{
279 1
				confirm_box(false, $this->user->lang('CONFIRM_OPERATION'), build_hidden_fields(array(
280 1
					'id'		=> $ad_id,
281 1
					'i'			=> $this->request->variable('i', ''),
282 1
					'mode'		=> $this->request->variable('mode', ''),
283
					'action'	=> 'delete'
284 1
				)));
285
			}
286 1
		}
287 1
	}
288
289
	/**
290
	* Display the ads
291
	*
292
	* @return void
293
	*/
294 1
	public function list_ads()
295
	{
296 1
		foreach ($this->manager->get_all_ads() as $row)
297
		{
298 1
			$ad_enabled = (int) $row['ad_enabled'];
299
300 1
			$this->template->assign_block_vars('ads', array(
301 1
				'NAME'		=> $row['ad_name'],
302 1
				'S_ENABLED'	=> $ad_enabled,
303 1
				'U_ENABLE'	=> $this->u_action . '&amp;action=' . ($ad_enabled ? 'disable' : 'enable') . '&amp;id=' . $row['ad_id'],
304 1
				'U_EDIT'	=> $this->u_action . '&amp;action=edit&amp;id=' . $row['ad_id'],
305 1
				'U_DELETE'	=> $this->u_action . '&amp;action=delete&amp;id=' . $row['ad_id'],
306 1
			));
307 1
		}
308
309
		// Set output vars for display in the template
310 1
		$this->template->assign_vars(array(
311 1
			'U_ACTION_ADD'	=> $this->u_action . '&amp;action=add',
312 1
		));
313 1
	}
314
315
	/**
316
	* Enable/disable an advertisement
317
	*
318
	* @param	bool	$enable	Enable or disable the advertisement?
319
	* @return void
320
	*/
321 4
	protected function ad_enable($enable)
322
	{
323 4
		$ad_id = $this->request->variable('id', 0);
324
325 4
		$success = $this->manager->update_ad($ad_id, array(
326 4
			'ad_enabled'	=> (int) $enable,
327 4
		));
328
329
		// If AJAX was used, show user a result message
330 4
		if ($this->request->is_ajax())
331 4
		{
332
			$json_response = new \phpbb\json_response;
333
			$json_response->send(array(
334
				'text'	=> $this->user->lang($enable ? 'ENABLED' : 'DISABLED'),
335
				'title'	=> $this->user->lang('AD_ENABLE_TITLE', (int) $enable),
336
			));
337
		}
338
339
		// Otherwise, show traditional infobox
340
		if ($success)
341 4
		{
342 2
			$this->success($enable ? 'ACP_AD_ENABLE_SUCCESS' : 'ACP_AD_DISABLE_SUCCESS');
343
		}
344
		else
345
		{
346 2
			$this->error($enable ? 'ACP_AD_ENABLE_ERRORED' : 'ACP_AD_DISABLE_ERRORED');
347
		}
348
	}
349
350
	/**
351
	* Get admin form data.
352
	*
353
	* @return	array	Form data
354
	*/
355 11
	protected function get_form_data()
356
	{
357
		return array(
358 11
			'ad_name'		=> $this->request->variable('ad_name', '', true),
359 11
			'ad_note'		=> $this->request->variable('ad_note', '', true),
360 11
			'ad_code'		=> $this->request->variable('ad_code', '', true),
361 11
			'ad_enabled'	=> $this->request->variable('ad_enabled', 0),
362 11
			'ad_locations'	=> $this->request->variable('ad_locations', array('')),
363 11
		);
364
	}
365
366
	/**
367
	* Validate form data.
368
	*
369
	* @param	array	$data		The form data.
370
	* @param	string	$form_name	The form name.
371
	* @return void
372
	*/
373 11
	protected function validate($data, $form_name)
374
	{
375 11
		if (!check_form_key($form_name))
376 11
		{
377 2
			$this->errors[] = $this->user->lang('FORM_INVALID');
378 2
		}
379
380 11
		if ($data['ad_name'] === '')
381 11
		{
382 2
			$this->errors[] = $this->user->lang('AD_NAME_REQUIRED');
383 2
		}
384 11
		if (truncate_string($data['ad_name'], self::MAX_NAME_LENGTH) !== $data['ad_name'])
385 11
		{
386 2
			$this->errors[] = $this->user->lang('AD_NAME_TOO_LONG', self::MAX_NAME_LENGTH);
387 2
		}
388 11
	}
389
390
	/**
391
	* Assign form data to the template.
392
	*
393
	* @param	array	$data	The form data.
394
	* @return void
395
	*/
396 9
	protected function assign_form_data($data)
397
	{
398 9
		$this->template->assign_vars(array(
399 9
			'S_ERROR'		=> (bool) count($this->errors),
400 9
			'ERROR_MSG'		=> count($this->errors) ? implode('<br />', $this->errors) : '',
401
402 9
			'AD_NAME'		=> $data['ad_name'],
403 9
			'AD_NOTE'		=> $data['ad_note'],
404 9
			'AD_CODE'		=> $data['ad_code'],
405 9
			'AD_ENABLED'	=> $data['ad_enabled'],
406 9
		));
407 9
	}
408
409
	/**
410
	* Assign template locations data to the template.
411
	*
412
	* @param	mixed	$data	The form data or nothing.
413
	* @return	void
414
	*/
415 10
	protected function assign_locations($data = false)
416
	{
417 10
		foreach ($this->location_manager->get_all_locations() as $location_id => $location_data)
418
		{
419 10
			$this->template->assign_block_vars('ad_locations', array(
420 10
				'LOCATION_ID'	=> $location_id,
421 10
				'LOCATION_DESC'	=> $location_data['desc'],
422 10
				'LOCATION_NAME'	=> $location_data['name'],
423 10
				'S_SELECTED'	=> $data ? in_array($location_id, $data['ad_locations']) : false,
424 10
			));
425 10
		}
426 10
	}
427
428
	/**
429
	* Prepare advertisement preview
430
	*
431
	* @param	string	$code	Ad code to preview
432
	* @return	void
433
	*/
434 2
	protected function ad_preview($code)
435
	{
436 2
		$this->template->assign_var('PREVIEW', htmlspecialchars_decode($code));
437 2
	}
438
439
	/**
440
	* Print success message.
441
	*
442
	* It takes arguments in the form of a language key, followed by language substitution values.
443
	*/
444 5
	protected function success()
445
	{
446 5
		trigger_error(call_user_func_array(array($this->user, 'lang'), func_get_args()) . adm_back_link($this->u_action));
447
	}
448
449
	/**
450
	* Print error message.
451
	*
452
	* It takes arguments in the form of a language key, followed by language substitution values.
453
	*/
454 5
	protected function error()
455
	{
456 5
		trigger_error(call_user_func_array(array($this->user, 'lang'), func_get_args()) . adm_back_link($this->u_action), E_USER_WARNING);
457
	}
458
459
	/**
460
	* Log action
461
	*
462
	* @param	string	$action		Performed action in uppercase
463
	* @param	string	$ad_name	Advertisement name
464
	* @return	void
465
	*/
466 3
	protected function log($action, $ad_name)
467
	{
468 3
		$this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'ACP_ADMANAGEMENT_' . $action . '_LOG', time(), array($ad_name));
469 3
	}
470
}
471