idea_controller   A
last analyzed

Complexity

Total Complexity 41

Size/Duplication

Total Lines 266
Duplicated Lines 0 %

Importance

Changes 8
Bugs 1 Features 0
Metric Value
wmc 41
eloc 80
c 8
b 1
f 0
dl 0
loc 266
rs 9.1199

12 Methods

Rating   Name   Duplication   Size   Complexity  
A delete() 0 32 3
A removevote() 0 17 5
A vote() 0 19 5
A implemented() 0 9 3
A duplicate() 0 9 3
A is_own() 0 3 1
A rfc() 0 9 4
A ticket() 0 9 4
A status() 0 11 4
A is_mod() 0 3 1
A get_hash() 0 3 1
B idea() 0 34 7

How to fix   Complexity   

Complex Class

Complex classes like idea_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.

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 idea_controller, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 *
4
 * Ideas extension for the phpBB Forum Software package.
5
 *
6
 * @copyright (c) phpBB Limited <https://www.phpbb.com>
7
 * @license GNU General Public License, version 2 (GPL-2.0)
8
 *
9
 */
10
11
namespace phpbb\ideas\controller;
12
13
use phpbb\exception\http_exception;
14
use phpbb\ideas\ext;
15
use Symfony\Component\HttpFoundation\JsonResponse;
16
use Symfony\Component\HttpFoundation\RedirectResponse;
17
18
class idea_controller extends base
19
{
20
	/** @var array of idea data */
21
	protected $data;
22
23
	/* @var \phpbb\ideas\factory\idea */
24
	protected $entity;
25
26
	/**
27
	 * Controller for /idea/{idea_id}
28
	 *
29
	 * @param $idea_id int The ID of the requested idea, maybe?
30
	 * @throws http_exception
31
	 * @return JsonResponse|RedirectResponse
32
	 */
33
	public function idea($idea_id)
34
	{
35
		if (!$this->is_available())
36
		{
37
			throw new http_exception(404, 'IDEAS_NOT_AVAILABLE');
38
		}
39
40
		$this->data = $this->entity->get_idea($idea_id);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->entity->get_idea($idea_id) can also be of type false. However, the property $data is declared as type array. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

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

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
41
		if (!$this->data)
42
		{
43
			throw new http_exception(404, 'IDEA_NOT_FOUND');
44
		}
45
46
		$mode = $this->request->variable('mode', '');
47
		if (!empty($mode) && $this->request->is_ajax())
48
		{
49
			$result = $this->$mode();
50
51
			return new JsonResponse($result);
52
		}
53
54
		$params = array(
55
			'f' => $this->config['ideas_forum_id'],
56
			't' => $this->data['topic_id']
57
		);
58
59
		if ($unread = ($this->request->variable('view', '') === 'unread'))
60
		{
61
			$params = array_merge($params, array('view' => 'unread'));
62
		}
63
64
		$url = append_sid(generate_board_url() . "/viewtopic.$this->php_ext", $params, false) . ($unread ? '#unread' : '');
65
66
		return new RedirectResponse($url);
67
	}
68
69
	/**
70
	 * Delete action (deletes an idea via confirm dialog)
71
	 *
72
	 * @throws http_exception
73
	 * @return void
74
	 * @access public
75
	 */
76
	public function delete()
77
	{
78
		if (!$this->is_mod())
79
		{
80
			throw new http_exception(403, 'NO_AUTH_OPERATION');
81
		}
82
83
		if (confirm_box(true))
84
		{
85
			include $this->root_path . 'includes/functions_admin.' . $this->php_ext;
86
			$this->entity->delete($this->data['idea_id'], $this->data['topic_id']);
87
88
			$redirect = $this->helper->route('phpbb_ideas_index_controller');
89
			$message = $this->language->lang('IDEA_DELETED') . '<br /><br />' . $this->language->lang('RETURN_IDEAS', '<a href="' . $redirect . '">', '</a>');
90
			meta_refresh(3, $redirect);
91
			trigger_error($message); // trigger error needed for data-ajax
92
		}
93
		else
94
		{
95
			confirm_box(
96
				false,
97
				$this->language->lang('CONFIRM_DELETE'),
98
				build_hidden_fields(array(
99
					'idea_id' => $this->data['idea_id'],
100
					'mode' => 'delete',
101
				)),
102
				'confirm_body.html',
103
				$this->helper->route(
104
					'phpbb_ideas_idea_controller',
105
					array(
106
						'idea_id' => $this->data['idea_id'],
107
						'mode'    => 'delete',
108
					)
109
				)
110
			);
111
		}
112
	}
113
114
	/**
115
	 * Duplicate action (sets an idea's duplicate link)
116
	 *
117
	 * @return bool True if set, false if not
118
	 * @access public
119
	 */
120
	public function duplicate()
121
	{
122
		if ($this->is_mod() && check_link_hash($this->get_hash(), "duplicate_{$this->data['idea_id']}"))
123
		{
124
			$duplicate = $this->request->variable('duplicate', 0);
125
			return $this->entity->set_duplicate($this->data['idea_id'], $duplicate);
126
		}
127
128
		return false;
129
	}
130
131
	/**
132
	 * Remove vote action (remove a user's vote from an idea)
133
	 *
134
	 * @return array|false|string Array of vote data, an error message, or false if failed
135
	 * @access public
136
	 */
137
	public function removevote()
138
	{
139
		if ($this->data['idea_status'] === ext::$statuses['IMPLEMENTED'] || $this->data['idea_status'] === ext::$statuses['DUPLICATE'] || !check_link_hash($this->get_hash(), "removevote_{$this->data['idea_id']}"))
140
		{
141
			return false;
142
		}
143
144
		if ($this->auth->acl_get('f_vote', (int) $this->config['ideas_forum_id']))
145
		{
146
			$result = $this->entity->remove_vote($this->data, $this->user->data['user_id']);
147
		}
148
		else
149
		{
150
			$result = $this->language->lang('NO_AUTH_OPERATION');
151
		}
152
153
		return $result;
154
	}
155
156
	/**
157
	 * RFC action (sets an idea's rfc link)
158
	 *
159
	 * @return bool True if set, false if not
160
	 * @access public
161
	 */
162
	public function rfc()
163
	{
164
		if (($this->is_own() || $this->is_mod()) && check_link_hash($this->get_hash(), "rfc_{$this->data['idea_id']}"))
165
		{
166
			$rfc = $this->request->variable('rfc', '');
167
			return $this->entity->set_rfc($this->data['idea_id'], $rfc);
168
		}
169
170
		return false;
171
	}
172
173
	/**
174
	 * Status action (sets an idea's status)
175
	 *
176
	 * @return bool True if set, false if not
177
	 * @access public
178
	 */
179
	public function status()
180
	{
181
		$status = $this->request->variable('status', 0);
182
183
		if ($status && $this->is_mod() && check_link_hash($this->get_hash(), "status_{$this->data['idea_id']}"))
184
		{
185
			$this->entity->set_status($this->data['idea_id'], $status);
186
			return true;
187
		}
188
189
		return false;
190
	}
191
192
	/**
193
	 * Ticket action (sets an idea's ticket link)
194
	 *
195
	 * @return bool True if set, false if not
196
	 * @access public
197
	 */
198
	public function ticket()
199
	{
200
		if (($this->is_own() || $this->is_mod()) && check_link_hash($this->get_hash(), "ticket_{$this->data['idea_id']}"))
201
		{
202
			$ticket = $this->request->variable('ticket', 0);
203
			return $this->entity->set_ticket($this->data['idea_id'], $ticket);
204
		}
205
206
		return false;
207
	}
208
209
	/**
210
	 * Implemented action (sets an idea's implemented phpBB version)
211
	 *
212
	 * @return bool True if set, false if not
213
	 * @access public
214
	 */
215
	public function implemented()
216
	{
217
		if ($this->is_mod() && check_link_hash($this->get_hash(), "implemented_{$this->data['idea_id']}"))
218
		{
219
			$version = $this->request->variable('implemented', '');
220
			return $this->entity->set_implemented($this->data['idea_id'], $version);
221
		}
222
223
		return false;
224
	}
225
226
	/**
227
	 * Vote action (sets an idea's vote)
228
	 *
229
	 * @return array|false|string Array of vote data, an error message, or false if failed
230
	 * @access public
231
	 */
232
	public function vote()
233
	{
234
		$vote = $this->request->variable('v', 1);
235
236
		if ($this->data['idea_status'] === ext::$statuses['IMPLEMENTED'] || $this->data['idea_status'] === ext::$statuses['DUPLICATE'] || !check_link_hash($this->get_hash(), "vote_{$this->data['idea_id']}"))
237
		{
238
			return false;
239
		}
240
241
		if ($this->auth->acl_get('f_vote', (int) $this->config['ideas_forum_id']))
242
		{
243
			$result = $this->entity->vote($this->data, $this->user->data['user_id'], $vote);
244
		}
245
		else
246
		{
247
			$result = $this->language->lang('NO_AUTH_OPERATION');
248
		}
249
250
		return $result;
251
	}
252
253
	/**
254
	 * Get a hash query parameter
255
	 *
256
	 * @return string The hash
257
	 * @access protected
258
	 */
259
	protected function get_hash()
260
	{
261
		return $this->request->variable('hash', '');
262
	}
263
264
	/**
265
	 * Does the user have moderator privileges?
266
	 *
267
	 * @return bool
268
	 * @access protected
269
	 */
270
	protected function is_mod()
271
	{
272
		return $this->auth->acl_get('m_', (int) $this->config['ideas_forum_id']);
273
	}
274
275
	/**
276
	 * Is the user the author of the idea?
277
	 *
278
	 * @return bool
279
	 * @access protected
280
	 */
281
	protected function is_own()
282
	{
283
		return $this->data['idea_author'] === $this->user->data['user_id'];
284
	}
285
}
286