Completed
Pull Request — master (#16)
by Jakub
08:47
created

admin_controller::ad_enable()   B

Complexity

Conditions 6
Paths 4

Size

Total Lines 28
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 9.1595

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 0
loc 28
ccs 10
cts 18
cp 0.5556
rs 8.439
cc 6
eloc 13
nc 4
nop 1
crap 9.1595
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 \phpbb\config\db_text */
40
	protected $config_text;
41
42
	/** @var \phpbb\cache\driver\driver_interface */
43
	protected $cache;
44
45
	/** @var string php_ext */
46
	protected $php_ext;
47
48
	/** @var string ext_path */
49
	protected $ext_path;
50
51
	/** @var string Custom form action */
52
	protected $u_action;
53
54
	/** @var array Form validation errors */
55
	protected $errors = array();
56
57
	/**
58
	* Constructor
59
	*
60
	* @param \phpbb\template\template				$template			Template object
61
	* @param \phpbb\user							$user				User object
62
	* @param \phpbb\request\request					$request			Request object
63
	* @param \phpbb\admanagement\ad\manager			$manager			Advertisement manager object
64
	* @param \phpbb\admanagement\location\manager	$location_manager	Template location manager object
65
	* @param \phpbb\log\log							$log				The phpBB log system
66
	* @param \phpbb\config\db_text					$config_text		Config text object
67
	* @param \phpbb\cache\driver\driver_interface	$cache				Cache object
68
	* @param string									$php_ext			PHP extension
69
	* @param string									$ext_path			Path to this extension
70
	*/
71 34
	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, \phpbb\config\db_text $config_text, \phpbb\cache\driver\driver_interface $cache, $php_ext, $ext_path)
72
	{
73 34
		$this->template = $template;
74 34
		$this->user = $user;
75 34
		$this->request = $request;
76 34
		$this->manager = $manager;
77 34
		$this->location_manager = $location_manager;
78 34
		$this->log = $log;
79 34
		$this->config_text = $config_text;
80 34
		$this->cache = $cache;
81 34
		$this->php_ext = $php_ext;
82 34
		$this->ext_path = $ext_path;
83 34
	}
84
85
	/**
86
	* Process user request for manage mode
87
	*
88
	* @return void
89
	*/
90 6
	public function mode_manage()
91
	{
92 6
		$this->setup();
93
94
		// Trigger specific action
95 6
		$action = $this->request->variable('action', '');
96 6
		if (in_array($action, array('add', 'edit', 'enable', 'disable', 'delete')))
97 6
		{
98 5
			$this->{'action_' . $action}();
99 5
		}
100
101
		// Otherwise default to this
102 6
		$this->list_ads();
103 6
	}
104
105
	/**
106
	* Process user request for settings mode
107
	*
108
	* @return void
109
	*/
110 3
	public function mode_settings()
111
	{
112 3
		$this->setup();
113
114 3
		add_form_key('phpbb/admanagement/settings');
115 3
		if ($this->request->is_set_post('submit'))
116 3
		{
117
			// Validate form key
118 2
			if (!check_form_key('phpbb/admanagement/settings'))
119 2
			{
120 1
				$this->errors[] = $this->user->lang('FORM_INVALID');
121 1
			}
122
123 2
			if (empty($this->errors))
124 2
			{
125 1
				$this->config_text->set('phpbb_admanagement_hide_groups', json_encode($this->request->variable('hide_groups', array(0))));
126 1
				$this->cache->destroy('sql', USER_GROUP_TABLE);
127
128 1
				$this->success('ACP_AD_SETTINGS_SAVED');
129
			}
130
131 1
			$this->template->assign_vars(array(
132 1
				'S_ERROR'		=> (bool) count($this->errors),
133 1
				'ERROR_MSG'		=> count($this->errors) ? implode('<br />', $this->errors) : '',
134 1
			));
135 1
		}
136
137 2
		$hide_groups = json_decode($this->config_text->get('phpbb_admanagement_hide_groups'), true);
138 2
		$groups = $this->manager->load_groups();
139 2
		foreach ($groups as $group)
140
		{
141 2
			$group_name = ($group['group_type'] == GROUP_SPECIAL) ? $this->user->lang('G_' . $group['group_name']) : $group['group_name'];
142
143 2
			$this->template->assign_block_vars('groups', array(
144 2
				'ID'			=> $group['group_id'],
145 2
				'NAME'			=> $group_name,
146 2
				'S_SELECTED'	=> in_array($group['group_id'], $hide_groups),
147 2
			));
148 2
		}
149 2
	}
150
151
	/**
152
	* Set page url
153
	*
154
	* @param string $u_action Custom form action
155
	* @return void
156
	*/
157 28
	public function set_page_url($u_action)
158
	{
159 28
		$this->u_action = $u_action;
160 28
	}
161
162
	/**
163
	* Get ACP page title for Ads module
164
	*
165
	* @return string	Language string for Ads ACP module
166
	*/
167 1
	public function get_page_title()
168
	{
169 1
		return $this->user->lang('ACP_ADMANAGEMENT_TITLE');
170
	}
171
172
	/**
173
	* Add an advertisement
174
	*
175
	* @return void
176
	*/
177 11
	public function action_add()
178
	{
179 7
		$preview = $this->request->is_set_post('preview');
180 7
		$submit = $this->request->is_set_post('submit');
181
182 7
		add_form_key('phpbb/admanagement/add');
183 7
		if ($preview || $submit)
184 7
		{
185 6
			$data = $this->get_form_data('phpbb/admanagement/add');
186
187 View Code Duplication
			if ($preview)
188 6
			{
189 1
				$this->ad_preview($data['ad_code']);
190 1
			}
191
			else if (empty($this->errors))
192 5
			{
193 1
				$ad_id = $this->manager->insert_ad($data);
194 1
				$this->manager->insert_ad_locations($ad_id, $data['ad_locations']);
195
196 11
				$this->log('ADD', $data['ad_name']);
197
198 1
				$this->success('ACP_AD_ADD_SUCCESS');
199
			}
200
201 5
			$this->assign_locations($data);
202 5
			$this->assign_form_data($data);
203 5
		}
204
		else
205
		{
206 1
			$this->assign_locations();
207
		}
208
209
		// Set output vars for display in the template
210 6
		$this->template->assign_vars(array(
211 6
			'S_ADD_AD'				=> true,
212 6
			'U_BACK'				=> $this->u_action,
213 6
			'PICKER_DATE_FORMAT'	=> self::DATE_FORMAT,
214 6
		));
215 6
	}
216
217
	/**
218
	* Edit an advertisement
219
	*
220
	* @return void
221
	*/
222 9
	public function action_edit()
223
	{
224 9
		$ad_id = $this->request->variable('id', 0);
225 9
		$preview = $this->request->is_set_post('preview');
226 9
		$submit = $this->request->is_set_post('submit');
227
228 9
		add_form_key('phpbb/admanagement/edit/' . $ad_id);
229 9
		if ($preview || $submit)
230 9
		{
231 7
			$data = $this->get_form_data('phpbb/admanagement/edit/' . $ad_id);
232
233
			if ($preview)
234 7
			{
235 1
				$this->ad_preview($data['ad_code']);
236 1
			}
237 View Code Duplication
			else if (empty($this->errors))
238 6
			{
239 2
				$success = $this->manager->update_ad($ad_id, $data);
240
241
				if ($success)
242 2
				{
243
					// Only insert new ad locations to DB when ad exists
244 1
					$this->manager->delete_ad_locations($ad_id);
245 1
					$this->manager->insert_ad_locations($ad_id, $data['ad_locations']);
246
247 1
					$this->log('EDIT', $data['ad_name']);
248
249 1
					$this->success('ACP_AD_EDIT_SUCCESS');
250
				}
251 1
				$this->error('ACP_AD_DOES_NOT_EXIST');
252
			}
253 5
		}
254
		else
255
		{
256
			// Load ad data
257 2
			$data = $this->manager->get_ad($ad_id);
258 2
			if (empty($data))
259 2
			{
260 1
				$this->error('ACP_AD_DOES_NOT_EXIST');
261
			}
262
263
			// Load ad template locations
264 1
			$data['ad_locations'] = $this->manager->get_ad_locations($ad_id);
265
		}
266
267
		// Set output vars for display in the template
268 6
		$this->template->assign_vars(array(
269 6
			'S_EDIT_AD'				=> true,
270 6
			'EDIT_ID'				=> $ad_id,
271 6
			'U_BACK'				=> $this->u_action,
272 6
			'PICKER_DATE_FORMAT'	=> self::DATE_FORMAT,
273 6
		));
274 6
		$this->assign_locations($data);
275 6
		$this->assign_form_data($data);
276 6
	}
277
278
	/**
279
	* Enable an advertisement
280
	*
281
	* @return void
282
	*/
283 3
	public function action_enable()
284
	{
285 3
		$this->ad_enable(true);
286 1
	}
287
288
	/**
289
	* Disable an advertisement
290
	*
291
	* @return void
292
	*/
293 3
	public function action_disable()
294
	{
295 3
		$this->ad_enable(false);
296 1
	}
297
298
	/**
299
	* Delete an advertisement
300
	*
301
	* @return void
302
	*/
303 3
	public function action_delete()
304
	{
305 3
		$ad_id = $this->request->variable('id', 0);
306
		if ($ad_id)
307 3
		{
308 3
			if (confirm_box(true))
309 3
			{
310
				// Get ad data so that we can log ad name
311 2
				$ad_data = $this->manager->get_ad($ad_id);
312
313
				// Delete ad and it's template locations
314 2
				$this->manager->delete_ad_locations($ad_id);
315 2
				$success = $this->manager->delete_ad($ad_id);
316
317
				// Only notify user on error or if not ajax
318 2
				if (!$success)
319 2
				{
320 1
					$this->error('ACP_AD_DELETE_ERRORED');
321
				}
322
				else
323
				{
324 1
					$this->log('DELETE', $ad_data['ad_name']);
325
326 1
					if (!$this->request->is_ajax())
327 1
					{
328 1
						$this->success('ACP_AD_DELETE_SUCCESS');
329
					}
330
				}
331
			}
332
			else
333
			{
334 1
				confirm_box(false, $this->user->lang('CONFIRM_OPERATION'), build_hidden_fields(array(
335 1
					'id'		=> $ad_id,
336 1
					'i'			=> $this->request->variable('i', ''),
337 1
					'mode'		=> $this->request->variable('mode', ''),
338
					'action'	=> 'delete'
339 1
				)));
340
			}
341 1
		}
342 1
	}
343
344
	/**
345
	* Display the ads
346
	*
347
	* @return void
348
	*/
349 1
	public function list_ads()
350
	{
351 1
		foreach ($this->manager->get_all_ads() as $row)
352
		{
353 1
			$ad_enabled = (int) $row['ad_enabled'];
354 1
			$ad_end_date = (int) $row['ad_end_date'];
355 1
			$ad_expired = $ad_end_date > 0 && $ad_end_date < time();
356 1
			if ($ad_expired && $ad_enabled)
357 1
			{
358 1
				$ad_enabled = 0;
359 1
				$this->manager->update_ad($row['ad_id'], array('ad_enabled' => 0));
360 1
			}
361
362 1
			$this->template->assign_block_vars('ads', array(
363 1
				'NAME'					=> $row['ad_name'],
364 1
				'END_DATE'				=> $ad_end_date ? $this->user->format_date($ad_end_date, self::DATE_FORMAT) : '',
365 1
				'S_END_DATE_EXPIRED'	=> $ad_expired,
366 1
				'S_ENABLED'				=> $ad_enabled,
367 1
				'U_ENABLE'				=> $this->u_action . '&amp;action=' . ($ad_enabled ? 'disable' : 'enable') . '&amp;id=' . $row['ad_id'],
368 1
				'U_EDIT'				=> $this->u_action . '&amp;action=edit&amp;id=' . $row['ad_id'],
369 1
				'U_DELETE'				=> $this->u_action . '&amp;action=delete&amp;id=' . $row['ad_id'],
370 1
			));
371 1
		}
372
373
		// Set output vars for display in the template
374 1
		$this->template->assign_var('U_ACTION_ADD', $this->u_action . '&amp;action=add');
375 1
	}
376
377
	/**
378
	* Perform general tasks
379
	*
380
	* @return void
381
	*/
382 9
	protected function setup()
383
	{
384 9
		$this->user->add_lang_ext('phpbb/admanagement', 'acp');
385
386 9
		$this->template->assign_var('S_PHPBB_ADMANAGEMENT', true);
387 9
	}
388
389
	/**
390
	* Enable/disable an advertisement
391
	*
392
	* @param	bool	$enable	Enable or disable the advertisement?
393
	* @return void
394
	*/
395 4
	protected function ad_enable($enable)
396
	{
397 4
		$ad_id = $this->request->variable('id', 0);
398
399 4
		$success = $this->manager->update_ad($ad_id, array(
400 4
			'ad_enabled'	=> (int) $enable,
401 4
		));
402
403
		// If AJAX was used, show user a result message
404 4
		if ($this->request->is_ajax())
405 4
		{
406
			$json_response = new \phpbb\json_response;
407
			$json_response->send(array(
408
				'text'	=> $this->user->lang($enable ? 'ENABLED' : 'DISABLED'),
409
				'title'	=> $this->user->lang('AD_ENABLE_TITLE', (int) $enable),
410
			));
411
		}
412
413
		// Otherwise, show traditional infobox
414
		if ($success)
415 4
		{
416 2
			$this->success($enable ? 'ACP_AD_ENABLE_SUCCESS' : 'ACP_AD_DISABLE_SUCCESS');
417
		}
418
		else
419
		{
420 2
			$this->error($enable ? 'ACP_AD_ENABLE_ERRORED' : 'ACP_AD_DISABLE_ERRORED');
421
		}
422
	}
423
424
	/**
425
	* Get admin form data.
426
	*
427
	* @param	string	$form_name	The form name.
428
	* @return	array	Form data
429
	*/
430 13
	protected function get_form_data($form_name)
431
	{
432
		$data = array(
433 13
			'ad_name'		=> $this->request->variable('ad_name', '', true),
434 13
			'ad_note'		=> $this->request->variable('ad_note', '', true),
435 13
			'ad_code'		=> $this->request->variable('ad_code', '', true),
436 13
			'ad_enabled'	=> $this->request->variable('ad_enabled', 0),
437 13
			'ad_locations'	=> $this->request->variable('ad_locations', array('')),
438 13
			'ad_end_date'	=> $this->request->variable('ad_end_date', ''),
439 13
		);
440
441
		// Validate form key
442 13
		if (!check_form_key($form_name))
443 13
		{
444 2
			$this->errors[] = $this->user->lang('FORM_INVALID');
445 2
		}
446
447
		// Validate ad name
448 13
		if ($data['ad_name'] === '')
449 13
		{
450 2
			$this->errors[] = $this->user->lang('AD_NAME_REQUIRED');
451 2
		}
452 13
		if (truncate_string($data['ad_name'], self::MAX_NAME_LENGTH) !== $data['ad_name'])
453 13
		{
454 2
			$this->errors[] = $this->user->lang('AD_NAME_TOO_LONG', self::MAX_NAME_LENGTH);
455 2
		}
456
457
		// Validate ad end date
458 13
		if (preg_match('#^\d{4}\-\d{2}\-\d{2}$#', $data['ad_end_date']))
459 13
		{
460 4
			$data['ad_end_date'] = (int) $this->user->get_timestamp_from_format(self::DATE_FORMAT, $data['ad_end_date']);
461
462 4
			if ($data['ad_end_date'] < time())
463 4
			{
464 2
				$this->errors[] = $this->user->lang('AD_END_DATE_INVALID');
465 2
			}
466 4
		}
467 9
		else if ($data['ad_end_date'] !== '')
468 9
		{
469
			$this->errors[] = $this->user->lang('AD_END_DATE_INVALID');
470
		}
471
		else
472
		{
473 9
			$data['ad_end_date'] = 0;
474
		}
475
476 13
		return $data;
477
	}
478
479
	/**
480
	* Assign form data to the template.
481
	*
482
	* @param	array	$data	The form data.
483
	* @return void
484
	*/
485 11
	protected function assign_form_data($data)
486
	{
487 11
		$this->template->assign_vars(array(
488 11
			'S_ERROR'		=> (bool) count($this->errors),
489 11
			'ERROR_MSG'		=> count($this->errors) ? implode('<br />', $this->errors) : '',
490
491 11
			'AD_NAME'		=> $data['ad_name'],
492 11
			'AD_NOTE'		=> $data['ad_note'],
493 11
			'AD_CODE'		=> $data['ad_code'],
494 11
			'AD_ENABLED'	=> $data['ad_enabled'],
495 11
			'AD_END_DATE'	=> $this->prepare_end_date($data['ad_end_date']),
496 11
		));
497 11
	}
498
	/**
499
	* Prepare end date for display
500
	*
501
	* @param	mixed	$end_date	End date.
502
	* @return	string	End date prepared for display.
503
	*/
504 11
	protected function prepare_end_date($end_date)
505
	{
506 11
		if (empty($end_date))
507 11
		{
508 8
			return '';
509
		}
510 3
		else if (is_numeric($end_date))
511 3
		{
512 3
			return $this->user->format_date($end_date, self::DATE_FORMAT);
513
		}
514
515
		return $end_date;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $end_date; (object|string|null|array|boolean) is incompatible with the return type documented by phpbb\admanagement\contr...oller::prepare_end_date of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
516
	}
517
518
	/**
519
	* Assign template locations data to the template.
520
	*
521
	* @param	mixed	$data	The form data or nothing.
522
	* @return	void
523
	*/
524 12
	protected function assign_locations($data = false)
525
	{
526 12
		foreach ($this->location_manager->get_all_locations() as $location_id => $location_data)
527
		{
528 12
			$this->template->assign_block_vars('ad_locations', array(
529 12
				'LOCATION_ID'	=> $location_id,
530 12
				'LOCATION_DESC'	=> $location_data['desc'],
531 12
				'LOCATION_NAME'	=> $location_data['name'],
532 12
				'S_SELECTED'	=> $data ? in_array($location_id, $data['ad_locations']) : false,
533 12
			));
534 12
		}
535 12
	}
536
537
	/**
538
	* Prepare advertisement preview
539
	*
540
	* @param	string	$code	Ad code to preview
541
	* @return	void
542
	*/
543 2
	protected function ad_preview($code)
544
	{
545 2
		$this->template->assign_var('PREVIEW', htmlspecialchars_decode($code));
546 2
	}
547
548
	/**
549
	* Print success message.
550
	*
551
	* It takes arguments in the form of a language key, followed by language substitution values.
552
	*/
553 6
	protected function success()
554
	{
555 6
		trigger_error(call_user_func_array(array($this->user, 'lang'), func_get_args()) . adm_back_link($this->u_action));
556
	}
557
558
	/**
559
	* Print error message.
560
	*
561
	* It takes arguments in the form of a language key, followed by language substitution values.
562
	*/
563 5
	protected function error()
564
	{
565 5
		trigger_error(call_user_func_array(array($this->user, 'lang'), func_get_args()) . adm_back_link($this->u_action), E_USER_WARNING);
566
	}
567
568
	/**
569
	* Log action
570
	*
571
	* @param	string	$action		Performed action in uppercase
572
	* @param	string	$ad_name	Advertisement name
573
	* @return	void
574
	*/
575 3
	protected function log($action, $ad_name)
576
	{
577 3
		$this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'ACP_ADMANAGEMENT_' . $action . '_LOG', time(), array($ad_name));
578 3
	}
579
}
580