Completed
Pull Request — master (#2)
by Jakub
06:25
created

admin_controller   B

Complexity

Total Complexity 41

Size/Duplication

Total Lines 416
Duplicated Lines 6.49 %

Coupling/Cohesion

Components 1
Dependencies 0

Test Coverage

Coverage 71.28%

Importance

Changes 13
Bugs 0 Features 1
Metric Value
wmc 41
c 13
b 0
f 1
lcom 1
cbo 0
dl 27
loc 416
ccs 139
cts 195
cp 0.7128
rs 8.2769

16 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 10 1
B main() 0 39 6
A set_page_url() 0 4 1
A get_page_title() 0 4 1
B action_add() 13 32 3
B action_edit() 14 51 4
B ad_enable() 0 28 6
B action_delete() 0 32 5
B list_ads() 0 26 3
A check_form_key() 0 7 2
A get_form_data() 0 9 1
A validate() 0 11 3
A assign_errors() 0 7 2
A assign_form_data() 0 9 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\db\driver\driver_interface */
21
	protected $db;
22
23
	/** @var \phpbb\template\template */
24
	protected $template;
25
26
	/** @var \phpbb\user */
27
	protected $user;
28
29
	/** @var \phpbb\request\request */
30
	protected $request;
31
32
	/** @var string ads_table */
33
	protected $ads_table;
34
35
	/** @var string php_ext */
36
	protected $php_ext;
37
38
	/** @var string phpbb_admin_path */
39
	protected $phpbb_admin_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\db\driver\driver_interface	$db					DB driver interface
51
	* @param \phpbb\template\template			$template			Template object
52
	* @param \phpbb\user						$user				User object
53
	* @param \phpbb\request\request				$request			Request object
54
	* @param string								$ads_table			Ads table
55
	* @param string								$php_ext			PHP extension
56
	* @param string								$phpbb_admin_path	Path to admin
57
	*/
58 16
	public function __construct(\phpbb\db\driver\driver_interface $db, \phpbb\template\template $template, \phpbb\user $user, \phpbb\request\request $request, $ads_table, $php_ext, $phpbb_admin_path)
59
	{
60 16
		$this->db = $db;
61 16
		$this->template = $template;
62 16
		$this->user = $user;
63 16
		$this->request = $request;
64 16
		$this->ads_table = $ads_table;
65 16
		$this->php_ext = $php_ext;
66 16
		$this->phpbb_admin_path = $phpbb_admin_path;
67 16
	}
68
69
	/**
70
	* Process user request
71
	*
72
	* @return void
73
	*/
74 5
	public function main()
75
	{
76 5
		$this->user->add_lang_ext('phpbb/admanagement', 'acp');
77
78 5
		switch ($this->request->variable('action', ''))
79
		{
80 5
			case 'add':
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
81
82 1
				$this->action_add();
83
84 1
			break;
85
86 4
			case 'edit':
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
87
88 1
				$this->action_edit();
89
90 1
			break;
91
92 3
			case 'enable':
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
93
94 1
				$this->ad_enable(true);
95
96 1
			break;
97
98 2
			case 'disable':
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
99
100 1
				$this->ad_enable(false);
101
102 1
			break;
103
104 1
			case 'delete':
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
105
106 1
				$this->action_delete();
107
108 1
			break;
109 5
		}
110
111 5
		$this->list_ads();
112 5
	}
113
114
	/**
115
	* Set page url
116
	*
117
	* @param string $u_action Custom form action
118
	* @return void
119
	*/
120 11
	public function set_page_url($u_action)
121
	{
122 11
		$this->u_action = $u_action;
123 11
	}
124
125
	/**
126
	* Get ACP page title for Ads module
127
	*
128
	* @return string	Language string for Ads ACP module
129
	*/
130 1
	public function get_page_title()
131
	{
132 1
		return $this->user->lang('ACP_ADMANAGEMENT_TITLE');
133
	}
134
135
	/**
136
	* Add an advertisement
137
	*
138
	* @return void
139
	*/
140 4
	public function action_add()
141
	{
142 4
		add_form_key('phpbb/admanagement/add');
143 4
		if ($this->request->is_set_post('submit'))
144 4
		{
145 3
			$this->check_form_key('phpbb/admanagement/add');
146
147 3
			$data = $this->get_form_data();
148
149 3
			$this->validate($data);
150
151 3 View Code Duplication
			if (empty($this->errors))
0 ignored issues
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...
152 3
			{
153
				// Insert the ad data to the database
154 1
				$sql = 'INSERT INTO ' . $this->ads_table . ' ' . $this->db->sql_build_array('INSERT', $data);
155 1
				$this->db->sql_query($sql);
156
157 1
				$this->success('ACP_AD_ADD_SUCCESS');
158
			}
159
			else
160
			{
161 2
				$this->assign_errors();
162 2
				$this->assign_form_data($data);
163
			}
164 2
		}
165
166
		// Set output vars for display in the template
167 3
		$this->template->assign_vars(array(
168 3
			'S_ADD_AD'	=> true,
169 3
			'U_BACK'	=> $this->u_action,
170 3
		));
171 3
	}
172
173
	/**
174
	* Edit an advertisement
175
	*
176
	* @return void
177
	*/
178 6
	public function action_edit()
179
	{
180
		$ad_id = $this->request->variable('id', 0);
181
182
		add_form_key('phpbb/admanagement/edit');
183
		if ($this->request->is_set_post('submit'))
184
		{
185
			$this->check_form_key('phpbb/admanagement/edit');
186
187
			$data = $this->get_form_data();
188
189
			$this->validate($data);
190
191 View Code Duplication
			if (empty($this->errors))
0 ignored issues
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...
192
			{
193
				// Insert the ad data to the database
194
				$sql = 'UPDATE ' . $this->ads_table . '
195
					SET ' . $this->db->sql_build_array('UPDATE', $data) . '
196 6
					WHERE ad_id = ' . (int) $ad_id;
197
				$this->db->sql_query($sql);
198
199
				$this->success('ACP_AD_EDIT_SUCCESS');
200
			}
201
			else
202
			{
203
				$this->assign_errors();
204
			}
205
		}
206
		else
207
		{
208
			$sql = 'SELECT *
209
				FROM ' . $this->ads_table . '
210
				WHERE ad_id = ' . (int) $ad_id;
211
			$result = $this->db->sql_query($sql);
212
			$data = $this->db->sql_fetchrow($result);
213
			$this->db->sql_freeresult($result);
214
215
			if (empty($data))
216
			{
217
				$this->error('ACP_AD_DOES_NOT_EXIST');
218
			}
219
		}
220
221
		// Set output vars for display in the template
222
		$this->template->assign_vars(array(
223
			'S_EDIT_AD'	=> true,
224
			'EDIT_ID'	=> $ad_id,
225
			'U_BACK'	=> $this->u_action,
226
		));
227
		$this->assign_form_data($data);
228
	}
229
230
	/**
231
	* Enable/disable an advertisement
232
	*
233
	* @param	bool	$enable	Enable or disable the advertisement?
234
	* @return void
235
	*/
236 4
	public function ad_enable($enable)
237
	{
238 4
		$sql = 'UPDATE ' . $this->ads_table . '
239 4
			SET ad_enabled = ' . (int) $enable . '
240 4
			WHERE ad_id = ' . (int) $this->request->variable('id', 0);
241 4
		$this->db->sql_query($sql);
242 4
		$success = (bool) $this->db->sql_affectedrows();
243
244
		// If AJAX was used, show user a result message
245 4
		if ($this->request->is_ajax())
246 4
		{
247
			$json_response = new \phpbb\json_response;
248
			$json_response->send(array(
249
				'text'	=> $this->user->lang($enable ? 'ENABLED' : 'DISABLED'),
250
				'title'	=> $this->user->lang('AD_ENABLE_TITLE', (int) $enable),
251
			));
252
		}
253
254
		// Otherwise, show traditional infobox
255
		if ($success)
256 4
		{
257 2
			$this->success($enable ? 'ACP_AD_ENABLE_SUCCESS' : 'ACP_AD_DISABLE_SUCCESS');
258
		}
259
		else
260
		{
261 2
			$this->error($enable ? 'ACP_AD_ENABLE_ERRORED' : 'ACP_AD_DISABLE_ERRORED');
262
		}
263
	}
264
265
	/**
266
	* Delete an advertisement
267
	*
268
	* @return void
269
	*/
270 1
	public function action_delete()
271
	{
272 1
		$ad_id = $this->request->variable('id', 0);
273
		if ($ad_id)
274 1
		{
275 1
			if (confirm_box(true))
276 1
			{
277 1
				$sql = 'DELETE FROM ' . $this->ads_table . '
278 1
					WHERE ad_id = ' . (int) $ad_id;
279 1
				$this->db->sql_query($sql);
280
281
				// Only notify user on error or if not ajax
282 1
				if (!$this->db->sql_affectedrows())
283 1
				{
284
					$this->error('ACP_AD_DELETE_ERRORED');
285
				}
286 1
				else if (!$this->request->is_ajax())
287 1
				{
288 1
					$this->success('ACP_AD_DELETE_SUCCESS');
289
				}
290
			}
291
			else
292
			{
293
				confirm_box(false, $this->user->lang('CONFIRM_OPERATION'), build_hidden_fields(array(
294
					'id'		=> $ad_id,
295
					'i'			=> $this->request->variable('i', ''),
296
					'mode'		=> $this->request->variable('mode', ''),
297
					'action'	=> 'delete'
298
				)));
299
			}
300
		}
301
	}
302
303
304
	/**
305
	* Display the ads
306
	*
307
	* @return void
308
	*/
309 6
	public function list_ads()
310
	{
311
		$sql = 'SELECT ad_id, ad_name, ad_enabled
312 6
			FROM ' . $this->ads_table;
313 6
		$result = $this->db->sql_query($sql);
314 6
		while ($row = $this->db->sql_fetchrow($result))
315
		{
316 6
			$ad_enabled = (int) $row['ad_enabled'];
317
318 6
			$this->template->assign_block_vars('ads', array(
319 6
				'NAME'		=> $row['ad_name'],
320 6
				'S_ENABLED'	=> $ad_enabled,
321 6
				'U_ENABLE'	=> $this->u_action . '&amp;action=' . ($ad_enabled ? 'disable' : 'enable') . '&amp;id=' . $row['ad_id'],
322 6
				'U_PREVIEW'	=> append_sid(generate_board_url() . '/index.' . $this->php_ext, 'ad_preview=' . $row['ad_id']),
323 6
				'U_EDIT'	=> $this->u_action . '&amp;action=edit&amp;id=' . $row['ad_id'],
324 6
				'U_DELETE'	=> $this->u_action . '&amp;action=delete&amp;id=' . $row['ad_id'],
325 6
			));
326 6
		}
327 6
		$this->db->sql_freeresult($result);
328
329
		// Set output vars for display in the template
330 6
		$this->template->assign_vars(array(
331 6
			'U_ACTION_ADD'	=> $this->u_action . '&amp;action=add',
332 6
			'ICON_PREVIEW'	=> '<img src="' . htmlspecialchars($this->phpbb_admin_path) . 'images/file_up_to_date.gif" alt="' . $this->user->lang('AD_PREVIEW') . '" title="' . $this->user->lang('AD_PREVIEW') . '" />',
333 6
		));
334 6
	}
335
336
	/**
337
	* Check the form key.
338
	*
339
	* @param	string	$form_name	The name of the form.
340
	* @return void
341
	*/
342 3
	protected function check_form_key($form_name)
343
	{
344 3
		if (!check_form_key($form_name))
345 3
		{
346
			$this->errors[] = $this->user->lang('FORM_INVALID');
347
		}
348 3
	}
349
350
	/**
351
	* Get admin form data.
352
	*
353
	* @return	array	Form data
354
	*/
355 3
	protected function get_form_data()
356
	{
357
		return array(
358 3
			'ad_name'		=> $this->request->variable('ad_name', '', true),
359 3
			'ad_note'		=> $this->request->variable('ad_note', '', true),
360 3
			'ad_code'		=> $this->request->variable('ad_code', '', true),
361 3
			'ad_enabled'	=> $this->request->variable('ad_enabled', false),
362 3
		);
363
	}
364
365
	/**
366
	* Validate form data.
367
	*
368
	* @param	array	$data	The form data.
369
	* @return void
370
	*/
371 3
	protected function validate($data)
372
	{
373 3
		if ($data['ad_name'] === '')
374 3
		{
375 1
			$this->errors[] = $this->user->lang('AD_NAME_REQUIRED');
376 1
		}
377 3
		if (truncate_string($data['ad_name'], self::MAX_NAME_LENGTH) !== $data['ad_name'])
378 3
		{
379 1
			$this->errors[] = $this->user->lang('AD_NAME_TOO_LONG', self::MAX_NAME_LENGTH);
380 1
		}
381 3
	}
382
383
	/**
384
	* Assign errors to the template.
385
	*
386
	* @return void
387
	*/
388 2
	protected function assign_errors()
389
	{
390 2
		$this->template->assign_vars(array(
391 2
			'S_ERROR'			=> (bool) count($this->errors),
392 2
			'ERROR_MSG'			=> count($this->errors) ? implode('<br />', $this->errors) : '',
393 2
		));
394 2
	}
395
396
	/**
397
	* Assign form data to the template.
398
	*
399
	* @param	array	$data	The form data.
400
	* @return void
401
	*/
402 2
	protected function assign_form_data($data)
403
	{
404 2
		$this->template->assign_vars(array(
405 2
			'AD_NAME'		=> $data['ad_name'],
406 2
			'AD_NOTE'		=> $data['ad_note'],
407 2
			'AD_CODE'		=> $data['ad_code'],
408 2
			'AD_ENABLED'	=> $data['ad_enabled'],
409 2
		));
410 2
	}
411
412
	/**
413
	* Print success message.
414
	*
415
	* It takes arguments in the form of a language key, followed by language substitution values.
416
	*/
417 4
	protected function success()
418
	{
419 4
		trigger_error(call_user_func_array(array($this->user, 'lang'), func_get_args()) . adm_back_link($this->u_action));
420
	}
421
422
	/**
423
	* Print error message.
424
	*
425
	* It takes arguments in the form of a language key, followed by language substitution values.
426
	*/
427 2
	protected function error()
428
	{
429 2
		trigger_error(call_user_func_array(array($this->user, 'lang'), func_get_args()) . adm_back_link($this->u_action), E_USER_WARNING);
430
	}
431
}
432