Completed
Pull Request — master (#16)
by Jakub
07:46
created

admin_controller::ad_preview()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
ccs 3
cts 3
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 1
crap 1
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 3
		$this->user->add_lang('common');
114
115 3
		add_form_key('phpbb/admanagement/settings');
116 3
		if ($this->request->is_set_post('submit'))
117 3
		{
118
			// Validate form key
119 2
			if (!check_form_key('phpbb/admanagement/settings'))
120 2
			{
121 1
				$this->errors[] = $this->user->lang('FORM_INVALID');
122 1
			}
123
124 2
			if (empty($this->errors))
125 2
			{
126 1
				$this->config_text->set('phpbb_admanagement_hide_groups', json_encode($this->request->variable('hide_groups', array(0))));
127 1
				$this->cache->destroy('sql', USER_GROUP_TABLE);
128
129 1
				$this->success('ACP_AD_SETTINGS_SAVED');
130
			}
131
			else
132
			{
133 1
				$this->template->assign_vars(array(
134 1
					'S_ERROR'		=> (bool) count($this->errors),
135 1
					'ERROR_MSG'		=> count($this->errors) ? implode('<br />', $this->errors) : '',
136 1
				));
137
			}
138 1
		}
139
140 2
		$hide_groups = json_decode($this->config_text->get('phpbb_admanagement_hide_groups'), true);
141 2
		$groups = $this->manager->load_groups();
142 2
		foreach ($groups as $group)
143
		{
144 2
			$group_name = (!empty($this->user->lang['G_' . $group['group_name']])) ? $this->user->lang('G_' . $group['group_name']) : $group['group_name'];
145
146 2
			$this->template->assign_block_vars('groups', array(
147 2
				'ID'			=> $group['group_id'],
148 2
				'NAME'			=> $group_name,
149 2
				'S_SELECTED'	=> in_array($group['group_id'], $hide_groups),
150 2
			));
151 2
		}
152 2
	}
153
154
	/**
155
	* Set page url
156
	*
157
	* @param string $u_action Custom form action
158
	* @return void
159
	*/
160 28
	public function set_page_url($u_action)
161
	{
162 28
		$this->u_action = $u_action;
163 28
	}
164
165
	/**
166
	* Get ACP page title for Ads module
167
	*
168
	* @return string	Language string for Ads ACP module
169
	*/
170 1
	public function get_page_title()
171
	{
172 1
		return $this->user->lang('ACP_ADMANAGEMENT_TITLE');
173
	}
174
175
	/**
176
	* Add an advertisement
177
	*
178
	* @return void
179
	*/
180 11
	public function action_add()
181
	{
182 7
		$preview = $this->request->is_set_post('preview');
183 7
		$submit = $this->request->is_set_post('submit');
184
185 7
		add_form_key('phpbb/admanagement/add');
186 7
		if ($preview || $submit)
187 7
		{
188 6
			$data = $this->get_form_data('phpbb/admanagement/add');
189
190 View Code Duplication
			if ($preview)
191 6
			{
192 1
				$this->ad_preview($data['ad_code']);
193 1
			}
194
			else if (empty($this->errors))
195 5
			{
196 11
				$ad_id = $this->manager->insert_ad($data);
197 1
				$this->manager->insert_ad_locations($ad_id, $data['ad_locations']);
198
199 1
				$this->log('ADD', $data['ad_name']);
200
201 1
				$this->success('ACP_AD_ADD_SUCCESS');
202
			}
203
204 5
			$this->assign_locations($data);
205 5
			$this->assign_form_data($data);
206 5
		}
207
		else
208
		{
209 1
			$this->assign_locations();
210
		}
211
212
		// Set output vars for display in the template
213 6
		$this->template->assign_vars(array(
214 6
			'S_ADD_AD'				=> true,
215 6
			'U_BACK'				=> $this->u_action,
216 6
			'PICKER_DATE_FORMAT'	=> self::DATE_FORMAT,
217 6
		));
218 6
	}
219
220
	/**
221
	* Edit an advertisement
222
	*
223
	* @return void
224
	*/
225 9
	public function action_edit()
226
	{
227 9
		$ad_id = $this->request->variable('id', 0);
228 9
		$preview = $this->request->is_set_post('preview');
229 9
		$submit = $this->request->is_set_post('submit');
230
231 9
		add_form_key('phpbb/admanagement/edit/' . $ad_id);
232 9
		if ($preview || $submit)
233 9
		{
234 7
			$data = $this->get_form_data('phpbb/admanagement/edit/' . $ad_id);
235
236
			if ($preview)
237 7
			{
238 1
				$this->ad_preview($data['ad_code']);
239 1
			}
240 View Code Duplication
			else if (empty($this->errors))
241 6
			{
242 2
				$success = $this->manager->update_ad($ad_id, $data);
243
244
				if ($success)
245 2
				{
246
					// Only insert new ad locations to DB when ad exists
247 1
					$this->manager->delete_ad_locations($ad_id);
248 1
					$this->manager->insert_ad_locations($ad_id, $data['ad_locations']);
249
250 1
					$this->log('EDIT', $data['ad_name']);
251
252 1
					$this->success('ACP_AD_EDIT_SUCCESS');
253
				}
254 1
				$this->error('ACP_AD_DOES_NOT_EXIST');
255
			}
256 5
		}
257
		else
258
		{
259
			// Load ad data
260 2
			$data = $this->manager->get_ad($ad_id);
261 2
			if (empty($data))
262 2
			{
263 1
				$this->error('ACP_AD_DOES_NOT_EXIST');
264
			}
265
266
			// Load ad template locations
267 1
			$data['ad_locations'] = $this->manager->get_ad_locations($ad_id);
268
		}
269
270
		// Set output vars for display in the template
271 6
		$this->template->assign_vars(array(
272 6
			'S_EDIT_AD'				=> true,
273 6
			'EDIT_ID'				=> $ad_id,
274 6
			'U_BACK'				=> $this->u_action,
275 6
			'PICKER_DATE_FORMAT'	=> self::DATE_FORMAT,
276 6
		));
277 6
		$this->assign_locations($data);
278 6
		$this->assign_form_data($data);
279 6
	}
280
281
	/**
282
	* Enable an advertisement
283
	*
284
	* @return void
285
	*/
286 3
	public function action_enable()
287
	{
288 3
		$this->ad_enable(true);
289 1
	}
290
291
	/**
292
	* Disable an advertisement
293
	*
294
	* @return void
295
	*/
296 3
	public function action_disable()
297
	{
298 3
		$this->ad_enable(false);
299 1
	}
300
301
	/**
302
	* Delete an advertisement
303
	*
304
	* @return void
305
	*/
306 3
	public function action_delete()
307
	{
308 3
		$ad_id = $this->request->variable('id', 0);
309
		if ($ad_id)
310 3
		{
311 3
			if (confirm_box(true))
312 3
			{
313
				// Get ad data so that we can log ad name
314 2
				$ad_data = $this->manager->get_ad($ad_id);
315
316
				// Delete ad and it's template locations
317 2
				$this->manager->delete_ad_locations($ad_id);
318 2
				$success = $this->manager->delete_ad($ad_id);
319
320
				// Only notify user on error or if not ajax
321 2
				if (!$success)
322 2
				{
323 1
					$this->error('ACP_AD_DELETE_ERRORED');
324
				}
325
				else
326
				{
327 1
					$this->log('DELETE', $ad_data['ad_name']);
328
329 1
					if (!$this->request->is_ajax())
330 1
					{
331 1
						$this->success('ACP_AD_DELETE_SUCCESS');
332
					}
333
				}
334
			}
335
			else
336
			{
337 1
				confirm_box(false, $this->user->lang('CONFIRM_OPERATION'), build_hidden_fields(array(
338 1
					'id'		=> $ad_id,
339 1
					'i'			=> $this->request->variable('i', ''),
340 1
					'mode'		=> $this->request->variable('mode', ''),
341
					'action'	=> 'delete'
342 1
				)));
343
			}
344 1
		}
345 1
	}
346
347
	/**
348
	* Display the ads
349
	*
350
	* @return void
351
	*/
352 1
	public function list_ads()
353
	{
354 1
		foreach ($this->manager->get_all_ads() as $row)
355
		{
356 1
			$ad_enabled = (int) $row['ad_enabled'];
357 1
			$ad_end_date = (int) $row['ad_end_date'];
358 1
			$ad_expired = $ad_end_date > 0 && $ad_end_date < time();
359 1
			if ($ad_expired && $ad_enabled)
360 1
			{
361 1
				$ad_enabled = 0;
362 1
				$this->manager->update_ad($row['ad_id'], array('ad_enabled' => 0));
363 1
			}
364
365 1
			$this->template->assign_block_vars('ads', array(
366 1
				'NAME'					=> $row['ad_name'],
367 1
				'END_DATE'				=> $ad_end_date ? $this->user->format_date($ad_end_date, self::DATE_FORMAT) : '',
368 1
				'S_END_DATE_EXPIRED'	=> $ad_expired,
369 1
				'S_ENABLED'				=> $ad_enabled,
370 1
				'U_ENABLE'				=> $this->u_action . '&amp;action=' . ($ad_enabled ? 'disable' : 'enable') . '&amp;id=' . $row['ad_id'],
371 1
				'U_EDIT'				=> $this->u_action . '&amp;action=edit&amp;id=' . $row['ad_id'],
372 1
				'U_DELETE'				=> $this->u_action . '&amp;action=delete&amp;id=' . $row['ad_id'],
373 1
			));
374 1
		}
375
376
		// Set output vars for display in the template
377 1
		$this->template->assign_var('U_ACTION_ADD', $this->u_action . '&amp;action=add');
378 1
	}
379
380
	/**
381
	* Perform general tasks
382
	*
383
	* @return void
384
	*/
385 9
	protected function setup()
386
	{
387 9
		$this->user->add_lang_ext('phpbb/admanagement', 'acp');
388
389 9
		$this->template->assign_var('S_PHPBB_ADMANAGEMENT', true);
390 9
	}
391
392
	/**
393
	* Enable/disable an advertisement
394
	*
395
	* @param	bool	$enable	Enable or disable the advertisement?
396
	* @return void
397
	*/
398 4
	protected function ad_enable($enable)
399
	{
400 4
		$ad_id = $this->request->variable('id', 0);
401
402 4
		$success = $this->manager->update_ad($ad_id, array(
403 4
			'ad_enabled'	=> (int) $enable,
404 4
		));
405
406
		// If AJAX was used, show user a result message
407 4
		if ($this->request->is_ajax())
408 4
		{
409
			$json_response = new \phpbb\json_response;
410
			$json_response->send(array(
411
				'text'	=> $this->user->lang($enable ? 'ENABLED' : 'DISABLED'),
412
				'title'	=> $this->user->lang('AD_ENABLE_TITLE', (int) $enable),
413
			));
414
		}
415
416
		// Otherwise, show traditional infobox
417
		if ($success)
418 4
		{
419 2
			$this->success($enable ? 'ACP_AD_ENABLE_SUCCESS' : 'ACP_AD_DISABLE_SUCCESS');
420
		}
421
		else
422
		{
423 2
			$this->error($enable ? 'ACP_AD_ENABLE_ERRORED' : 'ACP_AD_DISABLE_ERRORED');
424
		}
425
	}
426
427
	/**
428
	* Get admin form data.
429
	*
430
	* @param	string	$form_name	The form name.
431
	* @return	array	Form data
432
	*/
433 13
	protected function get_form_data($form_name)
434
	{
435
		$data = array(
436 13
			'ad_name'		=> $this->request->variable('ad_name', '', true),
437 13
			'ad_note'		=> $this->request->variable('ad_note', '', true),
438 13
			'ad_code'		=> $this->request->variable('ad_code', '', true),
439 13
			'ad_enabled'	=> $this->request->variable('ad_enabled', 0),
440 13
			'ad_locations'	=> $this->request->variable('ad_locations', array('')),
441 13
			'ad_end_date'	=> $this->request->variable('ad_end_date', ''),
442 13
		);
443
444
		// Validate form key
445 13
		if (!check_form_key($form_name))
446 13
		{
447 2
			$this->errors[] = $this->user->lang('FORM_INVALID');
448 2
		}
449
450
		// Validate ad name
451 13
		if ($data['ad_name'] === '')
452 13
		{
453 2
			$this->errors[] = $this->user->lang('AD_NAME_REQUIRED');
454 2
		}
455 13
		if (truncate_string($data['ad_name'], self::MAX_NAME_LENGTH) !== $data['ad_name'])
456 13
		{
457 2
			$this->errors[] = $this->user->lang('AD_NAME_TOO_LONG', self::MAX_NAME_LENGTH);
458 2
		}
459
460
		// Validate ad end date
461 13
		if (preg_match('#^\d{4}\-\d{2}\-\d{2}$#', $data['ad_end_date']))
462 13
		{
463 4
			$data['ad_end_date'] = (int) $this->user->get_timestamp_from_format(self::DATE_FORMAT, $data['ad_end_date']);
464
465 4
			if ($data['ad_end_date'] < time())
466 4
			{
467 2
				$this->errors[] = $this->user->lang('AD_END_DATE_INVALID');
468 2
			}
469 4
		}
470 9
		else if ($data['ad_end_date'] !== '')
471 9
		{
472
			$this->errors[] = $this->user->lang('AD_END_DATE_INVALID');
473
		}
474
		else
475
		{
476 9
			$data['ad_end_date'] = 0;
477
		}
478
479 13
		return $data;
480
	}
481
482
	/**
483
	* Assign form data to the template.
484
	*
485
	* @param	array	$data	The form data.
486
	* @return void
487
	*/
488 11
	protected function assign_form_data($data)
489
	{
490 11
		$this->template->assign_vars(array(
491 11
			'S_ERROR'		=> (bool) count($this->errors),
492 11
			'ERROR_MSG'		=> count($this->errors) ? implode('<br />', $this->errors) : '',
493
494 11
			'AD_NAME'		=> $data['ad_name'],
495 11
			'AD_NOTE'		=> $data['ad_note'],
496 11
			'AD_CODE'		=> $data['ad_code'],
497 11
			'AD_ENABLED'	=> $data['ad_enabled'],
498 11
			'AD_END_DATE'	=> $this->prepare_end_date($data['ad_end_date']),
499 11
		));
500 11
	}
501
	/**
502
	* Prepare end date for display
503
	*
504
	* @param	mixed	$end_date	End date.
505
	* @return	string	End date prepared for display.
506
	*/
507 11
	protected function prepare_end_date($end_date)
508
	{
509 11
		if (empty($end_date))
510 11
		{
511 8
			return '';
512
		}
513 3
		else if (is_numeric($end_date))
514 3
		{
515 3
			return $this->user->format_date($end_date, self::DATE_FORMAT);
516
		}
517
518
		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...
519
	}
520
521
	/**
522
	* Assign template locations data to the template.
523
	*
524
	* @param	mixed	$data	The form data or nothing.
525
	* @return	void
526
	*/
527 12
	protected function assign_locations($data = false)
528
	{
529 12
		foreach ($this->location_manager->get_all_locations() as $location_id => $location_data)
530
		{
531 12
			$this->template->assign_block_vars('ad_locations', array(
532 12
				'LOCATION_ID'	=> $location_id,
533 12
				'LOCATION_DESC'	=> $location_data['desc'],
534 12
				'LOCATION_NAME'	=> $location_data['name'],
535 12
				'S_SELECTED'	=> $data ? in_array($location_id, $data['ad_locations']) : false,
536 12
			));
537 12
		}
538 12
	}
539
540
	/**
541
	* Prepare advertisement preview
542
	*
543
	* @param	string	$code	Ad code to preview
544
	* @return	void
545
	*/
546 2
	protected function ad_preview($code)
547
	{
548 2
		$this->template->assign_var('PREVIEW', htmlspecialchars_decode($code));
549 2
	}
550
551
	/**
552
	* Print success message.
553
	*
554
	* It takes arguments in the form of a language key, followed by language substitution values.
555
	*/
556 6
	protected function success()
557
	{
558 6
		trigger_error(call_user_func_array(array($this->user, 'lang'), func_get_args()) . adm_back_link($this->u_action));
559
	}
560
561
	/**
562
	* Print error message.
563
	*
564
	* It takes arguments in the form of a language key, followed by language substitution values.
565
	*/
566 5
	protected function error()
567
	{
568 5
		trigger_error(call_user_func_array(array($this->user, 'lang'), func_get_args()) . adm_back_link($this->u_action), E_USER_WARNING);
569
	}
570
571
	/**
572
	* Log action
573
	*
574
	* @param	string	$action		Performed action in uppercase
575
	* @param	string	$ad_name	Advertisement name
576
	* @return	void
577
	*/
578 3
	protected function log($action, $ad_name)
579
	{
580 3
		$this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'ACP_ADMANAGEMENT_' . $action . '_LOG', time(), array($ad_name));
581 3
	}
582
}
583