Completed
Pull Request — master (#5)
by Jakub
33:55
created

admin_controller   B

Complexity

Total Complexity 50

Size/Duplication

Total Lines 464
Duplicated Lines 6.25 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 91.26%

Importance

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