Completed
Pull Request — master (#4)
by Jakub
06:07
created

admin_controller   B

Complexity

Total Complexity 46

Size/Duplication

Total Lines 420
Duplicated Lines 5.95 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 35.2%

Importance

Changes 20
Bugs 0 Features 1
Metric Value
wmc 46
c 20
b 0
f 1
lcom 1
cbo 2
dl 25
loc 420
ccs 69
cts 196
cp 0.352
rs 8.3999

18 Methods

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