Completed
Pull Request — master (#5)
by Jakub
31:35 queued 28:50
created

admin_controller   B

Complexity

Total Complexity 50

Size/Duplication

Total Lines 465
Duplicated Lines 6.24 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 90.23%

Importance

Changes 24
Bugs 0 Features 1
Metric Value
wmc 50
c 24
b 0
f 1
lcom 1
cbo 2
dl 29
loc 465
ccs 194
cts 215
cp 0.9023
rs 8.6206

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
B action_add() 13 41 5
B action_edit() 16 57 7
A action_enable() 0 4 1
A action_disable() 0 4 1
B action_delete() 0 40 5
A success() 0 4 1
A list_ads() 0 21 3
B ad_enable() 0 28 6
A get_form_data() 0 11 1
B validate() 0 20 6
A assign_form_data() 0 13 3
A assign_locations() 0 12 3
A ad_preview() 0 4 1
A error() 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
	const DATE_FORMAT = 'Y-m-d';
20
21
	/** @var \phpbb\template\template */
22
	protected $template;
23
24
	/** @var \phpbb\user */
25
	protected $user;
26
27
	/** @var \phpbb\request\request */
28
	protected $request;
29
30
	/** @var \phpbb\admanagement\ad\manager */
31
	protected $manager;
32
33
	/** @var \phpbb\admanagement\location\manager */
34
	protected $location_manager;
35
36
	/** @var \phpbb\log\log */
37
	protected $log;
38
39
	/** @var string php_ext */
40
	protected $php_ext;
41
42
	/** @var string ext_path */
43
	protected $ext_path;
44
45
	/** @var string Custom form action */
46
	protected $u_action;
47
48
	/** @var array Form validation errors */
49
	protected $errors = array();
50
51
	/**
52
	* Constructor
53
	*
54
	* @param \phpbb\template\template				$template			Template object
55
	* @param \phpbb\user							$user				User object
56
	* @param \phpbb\request\request					$request			Request object
57
	* @param \phpbb\admanagement\ad\manager			$manager			Advertisement manager object
58
	* @param \phpbb\admanagement\location\manager	$location_manager	Template location manager object
59
	* @param \phpbb\log\log							$log				The phpBB log system
60
	* @param string									$php_ext			PHP extension
61
	* @param string									$ext_path			Path to this extension
62
	*/
63 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)
64
	{
65 29
		$this->template = $template;
66 29
		$this->user = $user;
67 29
		$this->request = $request;
68 29
		$this->manager = $manager;
69 29
		$this->location_manager = $location_manager;
70 29
		$this->log = $log;
71 29
		$this->php_ext = $php_ext;
72 29
		$this->ext_path = $ext_path;
73 29
	}
74
75
	/**
76
	* Process user request
77
	*
78
	* @return void
79
	*/
80 6
	public function main()
81
	{
82 6
		$this->user->add_lang_ext('phpbb/admanagement', 'acp');
83
84
		// Trigger specific action
85 6
		$action = $this->request->variable('action', '');
86 6
		if (in_array($action, array('add', 'edit', 'enable', 'disable', 'delete')))
87 6
		{
88 5
			$this->{'action_' . $action}();
89 5
		}
90
91
		// Otherwise default to this
92 6
		$this->list_ads();
93 6
	}
94
95
	/**
96
	* Set page url
97
	*
98
	* @param string $u_action Custom form action
99
	* @return void
100
	*/
101 23
	public function set_page_url($u_action)
102
	{
103 23
		$this->u_action = $u_action;
104 23
	}
105
106
	/**
107
	* Get ACP page title for Ads module
108
	*
109
	* @return string	Language string for Ads ACP module
110
	*/
111 1
	public function get_page_title()
112
	{
113 1
		return $this->user->lang('ACP_ADMANAGEMENT_TITLE');
114
	}
115
116
	/**
117
	* Add an advertisement
118
	*
119
	* @return void
120
	*/
121 6
	public function action_add()
122
	{
123 6
		$preview = $this->request->is_set_post('preview');
124 6
		$submit = $this->request->is_set_post('submit');
125
126 6
		add_form_key('phpbb/admanagement/add');
127 6
		if ($preview || $submit)
128 6
		{
129 5
			$data = $this->get_form_data();
130
131 5
			$this->validate($data, 'phpbb/admanagement/add');
132
133 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...
134 5
			{
135 1
				$this->ad_preview($data['ad_code']);
136 1
			}
137
			else if (empty($this->errors))
138 4
			{
139 1
				$ad_id = $this->manager->insert_ad($data);
140 1
				$this->manager->insert_ad_locations($ad_id, $data['ad_locations']);
141
142 1
				$this->log('ADD', $data['ad_name']);
143
144 1
				$this->success('ACP_AD_ADD_SUCCESS');
145
			}
146
147 4
			$this->assign_locations($data);
148 4
			$this->assign_form_data($data);
149 4
		}
150
		else
151
		{
152 1
			$this->assign_locations();
153
		}
154
155
		// Set output vars for display in the template
156 5
		$this->template->assign_vars(array(
157 5
			'S_ADD_AD'				=> true,
158 5
			'U_BACK'				=> $this->u_action,
159 5
			'PICKER_DATE_FORMAT'	=> self::DATE_FORMAT,
160 5
		));
161 5
	}
162
163
	/**
164
	* Edit an advertisement
165
	*
166
	* @return void
167
	*/
168 8
	public function action_edit()
169
	{
170 8
		$ad_id = $this->request->variable('id', 0);
171 8
		$preview = $this->request->is_set_post('preview');
172 8
		$submit = $this->request->is_set_post('submit');
173
174 8
		add_form_key('phpbb/admanagement/edit/' . $ad_id);
175 8
		if ($preview || $submit)
176 8
		{
177 6
			$data = $this->get_form_data();
178
179 6
			$this->validate($data, 'phpbb/admanagement/edit/' . $ad_id);
180
181
			if ($preview)
182 6
			{
183 1
				$this->ad_preview($data['ad_code']);
184 1
			}
185 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...
186 5
			{
187 2
				$success = $this->manager->update_ad($ad_id, $data);
188
189
				if ($success)
190 2
				{
191
					// Only insert new ad locations to DB when ad exists
192 1
					$this->manager->delete_ad_locations($ad_id);
193 1
					$this->manager->insert_ad_locations($ad_id, $data['ad_locations']);
194
195 1
					$this->log('EDIT', $data['ad_name']);
196
197 1
					$this->success('ACP_AD_EDIT_SUCCESS');
198
				}
199 1
				$this->error('ACP_AD_DOES_NOT_EXIST');
200
			}
201 4
		}
202
		else
203
		{
204
			// Load ad data
205 2
			$data = $this->manager->get_ad($ad_id);
206 2
			if (empty($data))
207 2
			{
208 1
				$this->error('ACP_AD_DOES_NOT_EXIST');
209
			}
210
211
			// Load ad template locations
212 1
			$data['ad_locations'] = $this->manager->get_ad_locations($ad_id);
213
		}
214
215
		// Set output vars for display in the template
216 5
		$this->template->assign_vars(array(
217 5
			'S_EDIT_AD'				=> true,
218 5
			'EDIT_ID'				=> $ad_id,
219 5
			'U_BACK'				=> $this->u_action,
220 5
			'PICKER_DATE_FORMAT'	=> self::DATE_FORMAT,
221 5
		));
222 5
		$this->assign_locations($data);
223 5
		$this->assign_form_data($data);
224 5
	}
225
226
	/**
227
	* Enable an advertisement
228
	*
229
	* @return void
230
	*/
231 3
	public function action_enable()
232
	{
233 3
		$this->ad_enable(true);
234 1
	}
235
236
	/**
237
	* Disable an advertisement
238
	*
239
	* @return void
240
	*/
241 3
	public function action_disable()
242
	{
243 3
		$this->ad_enable(false);
244 1
	}
245
246
	/**
247
	* Delete an advertisement
248
	*
249
	* @return void
250
	*/
251 3
	public function action_delete()
252
	{
253 3
		$ad_id = $this->request->variable('id', 0);
254
		if ($ad_id)
255 3
		{
256 3
			if (confirm_box(true))
257 3
			{
258
				// Get ad data so that we can log ad name
259 2
				$ad_data = $this->manager->get_ad($ad_id);
260
261
				// Delete ad and it's template locations
262 2
				$this->manager->delete_ad_locations($ad_id);
263 2
				$success = $this->manager->delete_ad($ad_id);
264
265
				// Only notify user on error or if not ajax
266 2
				if (!$success)
267 2
				{
268 1
					$this->error('ACP_AD_DELETE_ERRORED');
269
				}
270
				else
271
				{
272 1
					$this->log('DELETE', $ad_data['ad_name']);
273
274 1
					if (!$this->request->is_ajax())
275 1
					{
276 1
						$this->success('ACP_AD_DELETE_SUCCESS');
277
					}
278
				}
279
			}
280
			else
281
			{
282 1
				confirm_box(false, $this->user->lang('CONFIRM_OPERATION'), build_hidden_fields(array(
283 1
					'id'		=> $ad_id,
284 1
					'i'			=> $this->request->variable('i', ''),
285 1
					'mode'		=> $this->request->variable('mode', ''),
286
					'action'	=> 'delete'
287 1
				)));
288
			}
289 1
		}
290 1
	}
291
292
	/**
293
	* Display the ads
294
	*
295
	* @return void
296
	*/
297 1
	public function list_ads()
298
	{
299 1
		foreach ($this->manager->get_all_ads() as $row)
300
		{
301 1
			$ad_enabled = (int) $row['ad_enabled'];
302
303 1
			$this->template->assign_block_vars('ads', array(
304 1
				'NAME'		=> $row['ad_name'],
305 1
				'S_ENABLED'	=> $ad_enabled,
306 1
				'U_ENABLE'	=> $this->u_action . '&amp;action=' . ($ad_enabled ? 'disable' : 'enable') . '&amp;id=' . $row['ad_id'],
307 1
				'U_EDIT'	=> $this->u_action . '&amp;action=edit&amp;id=' . $row['ad_id'],
308 1
				'U_DELETE'	=> $this->u_action . '&amp;action=delete&amp;id=' . $row['ad_id'],
309 1
			));
310 1
		}
311
312
		// Set output vars for display in the template
313 1
		$this->template->assign_vars(array(
314 1
			'S_ADS'			=> true,
315 1
			'U_ACTION_ADD'	=> $this->u_action . '&amp;action=add',
316 1
		));
317 1
	}
318
319
	/**
320
	* Enable/disable an advertisement
321
	*
322
	* @param	bool	$enable	Enable or disable the advertisement?
323
	* @return void
324
	*/
325 4
	protected function ad_enable($enable)
326
	{
327 4
		$ad_id = $this->request->variable('id', 0);
328
329 4
		$success = $this->manager->update_ad($ad_id, array(
330 4
			'ad_enabled'	=> (int) $enable,
331 4
		));
332
333
		// If AJAX was used, show user a result message
334 4
		if ($this->request->is_ajax())
335 4
		{
336
			$json_response = new \phpbb\json_response;
337
			$json_response->send(array(
338
				'text'	=> $this->user->lang($enable ? 'ENABLED' : 'DISABLED'),
339
				'title'	=> $this->user->lang('AD_ENABLE_TITLE', (int) $enable),
340
			));
341
		}
342
343
		// Otherwise, show traditional infobox
344
		if ($success)
345 4
		{
346 2
			$this->success($enable ? 'ACP_AD_ENABLE_SUCCESS' : 'ACP_AD_DISABLE_SUCCESS');
347
		}
348
		else
349
		{
350 2
			$this->error($enable ? 'ACP_AD_ENABLE_ERRORED' : 'ACP_AD_DISABLE_ERRORED');
351
		}
352
	}
353
354
	/**
355
	* Get admin form data.
356
	*
357
	* @return	array	Form data
358
	*/
359 11
	protected function get_form_data()
360
	{
361
		return array(
362 11
			'ad_name'		=> $this->request->variable('ad_name', '', true),
363 11
			'ad_note'		=> $this->request->variable('ad_note', '', true),
364 11
			'ad_code'		=> $this->request->variable('ad_code', '', true),
365 11
			'ad_enabled'	=> $this->request->variable('ad_enabled', 0),
366 11
			'ad_locations'	=> $this->request->variable('ad_locations', array('')),
367 11
			'ad_end_date'	=> (int) $this->user->get_timestamp_from_format(self::DATE_FORMAT, $this->request->variable('ad_end_date', '')),
368 11
		);
369
	}
370
371
	/**
372
	* Validate form data.
373
	*
374
	* @param	array	$data		The form data.
375
	* @param	string	$form_name	The form name.
376
	* @return void
377
	*/
378 11
	protected function validate($data, $form_name)
379
	{
380 11
		if (!check_form_key($form_name))
381 11
		{
382 2
			$this->errors[] = $this->user->lang('FORM_INVALID');
383 2
		}
384
385 11
		if ($data['ad_name'] === '')
386 11
		{
387 2
			$this->errors[] = $this->user->lang('AD_NAME_REQUIRED');
388 2
		}
389 11
		if (truncate_string($data['ad_name'], self::MAX_NAME_LENGTH) !== $data['ad_name'])
390 11
		{
391 2
			$this->errors[] = $this->user->lang('AD_NAME_TOO_LONG', self::MAX_NAME_LENGTH);
392 2
		}
393 11
		if ($data['ad_end_date'] != 0 && $data['ad_end_date'] < time())
394 11
		{
395
			$this->errors[] = $this->user->lang('AD_END_DATE_INVALID');
396
		}
397 11
	}
398
399
	/**
400
	* Assign form data to the template.
401
	*
402
	* @param	array	$data	The form data.
403
	* @return void
404
	*/
405 9
	protected function assign_form_data($data)
406
	{
407 9
		$this->template->assign_vars(array(
408 9
			'S_ERROR'		=> (bool) count($this->errors),
409 9
			'ERROR_MSG'		=> count($this->errors) ? implode('<br />', $this->errors) : '',
410
411 9
			'AD_NAME'		=> $data['ad_name'],
412 9
			'AD_NOTE'		=> $data['ad_note'],
413 9
			'AD_CODE'		=> $data['ad_code'],
414 9
			'AD_ENABLED'	=> $data['ad_enabled'],
415 9
			'AD_END_DATE'	=> $data['ad_end_date'] ? $this->user->format_date($data['ad_end_date'], self::DATE_FORMAT) : '',
416 9
		));
417 9
	}
418
419
	/**
420
	* Assign template locations data to the template.
421
	*
422
	* @param	mixed	$data	The form data or nothing.
423
	* @return	void
424
	*/
425 10
	protected function assign_locations($data = false)
426
	{
427 10
		foreach ($this->location_manager->get_all_locations() as $location_id => $location_data)
428
		{
429 10
			$this->template->assign_block_vars('ad_locations', array(
430 10
				'LOCATION_ID'	=> $location_id,
431 10
				'LOCATION_DESC'	=> $location_data['desc'],
432 10
				'LOCATION_NAME'	=> $location_data['name'],
433 10
				'S_SELECTED'	=> $data ? in_array($location_id, $data['ad_locations']) : false,
434 10
			));
435 10
		}
436 10
	}
437
438
	/**
439
	* Prepare advertisement preview
440
	*
441
	* @param	string	$code	Ad code to preview
442
	* @return	void
443
	*/
444 2
	protected function ad_preview($code)
445
	{
446 2
		$this->template->assign_var('PREVIEW', htmlspecialchars_decode($code));
447 2
	}
448
449
	/**
450
	* Print success message.
451
	*
452
	* It takes arguments in the form of a language key, followed by language substitution values.
453
	*/
454 5
	protected function success()
455
	{
456 5
		trigger_error(call_user_func_array(array($this->user, 'lang'), func_get_args()) . adm_back_link($this->u_action));
457
	}
458
459
	/**
460
	* Print error message.
461
	*
462
	* It takes arguments in the form of a language key, followed by language substitution values.
463
	*/
464 5
	protected function error()
465
	{
466 5
		trigger_error(call_user_func_array(array($this->user, 'lang'), func_get_args()) . adm_back_link($this->u_action), E_USER_WARNING);
467
	}
468
469
	/**
470
	* Log action
471
	*
472
	* @param	string	$action		Performed action in uppercase
473
	* @param	string	$ad_name	Advertisement name
474
	* @return	void
475
	*/
476 3
	protected function log($action, $ad_name)
477
	{
478 3
		$this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'ACP_ADMANAGEMENT_' . $action . '_LOG', time(), array($ad_name));
479 3
	}
480
}
481