Completed
Pull Request — master (#16)
by Jakub
12:33
created

admin_controller::assign_form_data()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 13
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 2

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 13
ccs 11
cts 11
cp 1
rs 9.4285
cc 2
eloc 9
nc 1
nop 1
crap 2
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 31
	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 31
		$this->template = $template;
74 31
		$this->user = $user;
75 31
		$this->request = $request;
76 31
		$this->manager = $manager;
77 31
		$this->location_manager = $location_manager;
78 31
		$this->log = $log;
79 31
		$this->config_text = $config_text;
80 31
		$this->cache = $cache;
81 31
		$this->php_ext = $php_ext;
82 31
		$this->ext_path = $ext_path;
83 31
	}
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
	public function mode_settings()
111
	{
112
		$this->setup();
113
		$this->user->add_lang('common');
114
115
		add_form_key('phpbb/admanagement/settings');
116
		if ($this->request->is_set_post('submit'))
117
		{
118
			// Validate form key
119
			if (!check_form_key('phpbb/admanagement/settings'))
120
			{
121
				$errors[] = $this->user->lang('FORM_INVALID');
0 ignored issues
show
Coding Style Comprehensibility introduced by
$errors was never initialized. Although not strictly required by PHP, it is generally a good practice to add $errors = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

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