idea   A
last analyzed

Complexity

Total Complexity 37

Size/Duplication

Total Lines 424
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 37
eloc 149
c 2
b 0
f 0
dl 0
loc 424
rs 9.44

15 Methods

Rating   Name   Duplication   Size   Complexity  
A set_implemented() 0 15 3
A set_ticket() 0 14 3
A set_duplicate() 0 14 3
A get_title() 0 10 2
A set_status() 0 7 1
A submit() 0 18 2
A set_title() 0 14 2
A set_rfc() 0 15 3
A get_idea_by_topic_id() 0 10 1
A get_idea() 0 10 1
B vote() 0 74 7
A get_voters() 0 21 2
A get_users_vote() 0 11 1
A remove_vote() 0 26 3
A delete() 0 18 3
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\factory;
12
13
use phpbb\ideas\ext;
14
15
/**
16
 * Class for handling a single idea
17
 */
18
class idea extends base
19
{
20
	/**
21
	 * Returns the specified idea.
22
	 *
23
	 * @param int $id The ID of the idea to return.
24
	 *
25
	 * @return array|false The idea row set, or false if not found.
26
	 */
27
	public function get_idea($id)
28
	{
29
		$sql = 'SELECT *
30
			FROM ' . $this->table_ideas . '
31
			WHERE idea_id = ' . (int) $id;
32
		$result = $this->db->sql_query_limit($sql, 1);
33
		$row = $this->db->sql_fetchrow($result);
34
		$this->db->sql_freeresult($result);
35
36
		return $row;
37
	}
38
39
	/**
40
	 * Returns an idea specified by its topic ID.
41
	 *
42
	 * @param int $id The ID of the idea to return.
43
	 *
44
	 * @return array|false The idea row set, or false if not found.
45
	 */
46
	public function get_idea_by_topic_id($id)
47
	{
48
		$sql = 'SELECT idea_id
49
			FROM ' . $this->table_ideas . '
50
			WHERE topic_id = ' . (int) $id;
51
		$result = $this->db->sql_query_limit($sql, 1);
52
		$idea_id = (int) $this->db->sql_fetchfield('idea_id');
53
		$this->db->sql_freeresult($result);
54
55
		return $this->get_idea($idea_id);
56
	}
57
58
	/**
59
	 * Updates the status of an idea.
60
	 *
61
	 * @param int $idea_id The ID of the idea.
62
	 * @param int $status  The ID of the status.
63
	 *
64
	 * @return void
65
	 */
66
	public function set_status($idea_id, $status)
67
	{
68
		$sql_ary = array(
69
			'idea_status' => (int) $status,
70
		);
71
72
		$this->update_idea_data($sql_ary, $idea_id, $this->table_ideas);
73
	}
74
75
	/**
76
	 * Sets the ID of the duplicate for an idea.
77
	 *
78
	 * @param int    $idea_id   ID of the idea to be updated.
79
	 * @param string $duplicate Idea ID of duplicate.
80
	 *
81
	 * @return bool True if set, false if invalid.
82
	 */
83
	public function set_duplicate($idea_id, $duplicate)
84
	{
85
		if ($duplicate && !is_numeric($duplicate))
86
		{
87
			return false;
88
		}
89
90
		$sql_ary = array(
91
			'duplicate_id'	=> (int) $duplicate,
92
		);
93
94
		$this->update_idea_data($sql_ary, $idea_id, $this->table_ideas);
95
96
		return true;
97
	}
98
99
	/**
100
	 * Sets the RFC link of an idea.
101
	 *
102
	 * @param int    $idea_id ID of the idea to be updated.
103
	 * @param string $rfc     Link to the RFC.
104
	 *
105
	 * @return bool True if set, false if invalid.
106
	 */
107
	public function set_rfc($idea_id, $rfc)
108
	{
109
		$match = '/^https?:\/\/area51\.phpbb\.com\/phpBB\/viewtopic\.php/';
110
		if ($rfc && !preg_match($match, $rfc))
111
		{
112
			return false;
113
		}
114
115
		$sql_ary = array(
116
			'rfc_link'	=> $rfc, // string is escaped by build_array()
117
		);
118
119
		$this->update_idea_data($sql_ary, $idea_id, $this->table_ideas);
120
121
		return true;
122
	}
123
124
	/**
125
	 * Sets the ticket ID of an idea.
126
	 *
127
	 * @param int    $idea_id ID of the idea to be updated.
128
	 * @param string $ticket  Ticket ID.
129
	 *
130
	 * @return bool True if set, false if invalid.
131
	 */
132
	public function set_ticket($idea_id, $ticket)
133
	{
134
		if ($ticket && !is_numeric($ticket))
135
		{
136
			return false;
137
		}
138
139
		$sql_ary = array(
140
			'ticket_id'	=> (int) $ticket,
141
		);
142
143
		$this->update_idea_data($sql_ary, $idea_id, $this->table_ideas);
144
145
		return true;
146
	}
147
148
	/**
149
	 * Sets the implemented version of an idea.
150
	 *
151
	 * @param int    $idea_id ID of the idea to be updated.
152
	 * @param string $version Version of phpBB the idea was implemented in.
153
	 *
154
	 * @return bool True if set, false if invalid.
155
	 */
156
	public function set_implemented($idea_id, $version)
157
	{
158
		$match = '/^\d\.\d\.\d+(-\w+)?$/';
159
		if ($version && !preg_match($match, $version))
160
		{
161
			return false;
162
		}
163
164
		$sql_ary = array(
165
			'implemented_version'	=> $version, // string is escaped by build_array()
166
		);
167
168
		$this->update_idea_data($sql_ary, $idea_id, $this->table_ideas);
169
170
		return true;
171
	}
172
173
	/**
174
	 * Sets the title of an idea.
175
	 *
176
	 * @param int    $idea_id ID of the idea to be updated.
177
	 * @param string $title   New title.
178
	 *
179
	 * @return boolean True if updated, false if invalid length.
180
	 */
181
	public function set_title($idea_id, $title)
182
	{
183
		if (utf8_clean_string($title) === '')
184
		{
185
			return false;
186
		}
187
188
		$sql_ary = array(
189
			'idea_title' => truncate_string($title, ext::SUBJECT_LENGTH),
190
		);
191
192
		$this->update_idea_data($sql_ary, $idea_id, $this->table_ideas);
193
194
		return true;
195
	}
196
197
	/**
198
	 * Get the title of an idea.
199
	 *
200
	 * @param int $id ID of an idea
201
	 *
202
	 * @return string The idea's title, empty string if not found
203
	 */
204
	public function get_title($id)
205
	{
206
		$sql = 'SELECT idea_title
207
			FROM ' . $this->table_ideas . '
208
			WHERE idea_id = ' . (int) $id;
209
		$result = $this->db->sql_query_limit($sql, 1);
210
		$idea_title = $this->db->sql_fetchfield('idea_title');
211
		$this->db->sql_freeresult($result);
212
213
		return $idea_title ?: '';
214
	}
215
216
	/**
217
	 * Submit new idea data to the ideas table
218
	 *
219
	 * @param array $data An array of post data from a newly posted idea
220
	 *
221
	 * @return int The ID of the new idea.
222
	 */
223
	public function submit($data)
224
	{
225
		$sql_ary = [
226
			'idea_title'	=> $data['topic_title'],
227
			'idea_author'	=> $data['poster_id'],
228
			'idea_date'		=> $data['post_time'],
229
			'topic_id'		=> $data['topic_id'],
230
		];
231
232
		$idea_id = $this->insert_idea_data($sql_ary, $this->table_ideas);
233
234
		// Initial vote
235
		if (($idea = $this->get_idea($idea_id)) !== false)
236
		{
237
			$this->vote($idea, $data['poster_id'], 1);
238
		}
239
240
		return $idea_id;
241
	}
242
243
	/**
244
	 * Deletes an idea and the topic to go with it.
245
	 *
246
	 * @param int $id       The ID of the idea to be deleted.
247
	 * @param int $topic_id The ID of the idea topic. Optional, but preferred.
248
	 *
249
	 * @return boolean Whether the idea was deleted or not.
250
	 */
251
	public function delete($id, $topic_id = 0)
252
	{
253
		if (!$topic_id)
254
		{
255
			$idea = $this->get_idea($id);
256
			$topic_id = $idea ? $idea['topic_id'] : 0;
257
		}
258
259
		// Delete topic
260
		delete_posts('topic_id', $topic_id);
261
262
		// Delete idea
263
		$deleted = $this->delete_idea_data($id, $this->table_ideas);
264
265
		// Delete votes
266
		$this->delete_idea_data($id, $this->table_votes);
267
268
		return $deleted;
269
	}
270
271
	/**
272
	 * Submits a vote on an idea.
273
	 *
274
	 * @param array $idea    The idea returned by get_idea().
275
	 * @param int   $user_id The ID of the user voting.
276
	 * @param int   $value   Up (1) or down (0)?
277
	 *
278
	 * @return array|string Array of information or string on error.
279
	 */
280
	public function vote(&$idea, $user_id, $value)
281
	{
282
		// Validate $vote - must be 0 or 1
283
		if ($value !== 0 && $value !== 1)
284
		{
285
			return 'INVALID_VOTE';
286
		}
287
288
		// Check whether user has already voted - update if they have
289
		if ($row = $this->get_users_vote($idea['idea_id'], $user_id))
290
		{
291
			if ($row['vote_value'] != $value)
292
			{
293
				$sql = 'UPDATE ' . $this->table_votes . '
294
					SET vote_value = ' . $value . '
295
					WHERE user_id = ' . (int) $user_id . '
296
						AND idea_id = ' . (int) $idea['idea_id'];
297
				$this->db->sql_query($sql);
298
299
				if ($value == 1)
300
				{
301
					// Change to upvote
302
					$idea['idea_votes_up']++;
303
					$idea['idea_votes_down']--;
304
				}
305
				else
306
				{
307
					// Change to downvote
308
					$idea['idea_votes_up']--;
309
					$idea['idea_votes_down']++;
310
				}
311
312
				$sql_ary = array(
313
					'idea_votes_up'	    => $idea['idea_votes_up'],
314
					'idea_votes_down'	=> $idea['idea_votes_down'],
315
				);
316
317
				$this->update_idea_data($sql_ary, $idea['idea_id'], $this->table_ideas);
318
			}
319
320
			return array(
321
				'message'	    => $this->language->lang('UPDATED_VOTE'),
322
				'votes_up'	    => $idea['idea_votes_up'],
323
				'votes_down'	=> $idea['idea_votes_down'],
324
				'points'        => $this->language->lang('TOTAL_POINTS', $idea['idea_votes_up'] - $idea['idea_votes_down']),
325
				'voters'		=> $this->get_voters($idea['idea_id']),
326
			);
327
		}
328
329
		// Insert vote into votes table.
330
		$sql_ary = array(
331
			'idea_id'		=> (int) $idea['idea_id'],
332
			'user_id'		=> (int) $user_id,
333
			'vote_value'	=> (int) $value,
334
		);
335
336
		$this->insert_idea_data($sql_ary, $this->table_votes);
337
338
		// Update number of votes in ideas table
339
		$idea['idea_votes_' . ($value ? 'up' : 'down')]++;
340
341
		$sql_ary = array(
342
			'idea_votes_up'	    => $idea['idea_votes_up'],
343
			'idea_votes_down'	=> $idea['idea_votes_down'],
344
		);
345
346
		$this->update_idea_data($sql_ary, $idea['idea_id'], $this->table_ideas);
347
348
		return array(
349
			'message'	    => $this->language->lang('VOTE_SUCCESS'),
350
			'votes_up'	    => $idea['idea_votes_up'],
351
			'votes_down'	=> $idea['idea_votes_down'],
352
			'points'        => $this->language->lang('TOTAL_POINTS', $idea['idea_votes_up'] - $idea['idea_votes_down']),
353
			'voters'		=> $this->get_voters($idea['idea_id']),
354
		);
355
	}
356
357
	/**
358
	 * Remove a user's vote from an idea
359
	 *
360
	 * @param array   $idea    The idea returned by get_idea().
361
	 * @param int     $user_id The ID of the user voting.
362
	 *
363
	 * @return array Array of information.
364
	 */
365
	public function remove_vote(&$idea, $user_id)
366
	{
367
		// Only change something if user has already voted
368
		if ($row = $this->get_users_vote($idea['idea_id'], $user_id))
369
		{
370
			$sql = 'DELETE FROM ' . $this->table_votes . '
371
				WHERE idea_id = ' . (int) $idea['idea_id'] . '
372
					AND user_id = ' . (int) $user_id;
373
			$this->db->sql_query($sql);
374
375
			$idea['idea_votes_' . ($row['vote_value'] == 1 ? 'up' : 'down')]--;
376
377
			$sql_ary = array(
378
				'idea_votes_up'	    => $idea['idea_votes_up'],
379
				'idea_votes_down'	=> $idea['idea_votes_down'],
380
			);
381
382
			$this->update_idea_data($sql_ary, $idea['idea_id'], $this->table_ideas);
383
		}
384
385
		return array(
386
			'message'	    => $this->language->lang('UPDATED_VOTE'),
387
			'votes_up'	    => $idea['idea_votes_up'],
388
			'votes_down'	=> $idea['idea_votes_down'],
389
			'points'        => $this->language->lang('TOTAL_POINTS', $idea['idea_votes_up'] - $idea['idea_votes_down']),
390
			'voters'		=> $this->get_voters($idea['idea_id']),
391
		);
392
	}
393
394
	/**
395
	 * Returns voter info on an idea.
396
	 *
397
	 * @param int $id ID of the idea.
398
	 *
399
	 * @return array Array of row data
400
	 */
401
	public function get_voters($id)
402
	{
403
		$sql = 'SELECT iv.user_id, iv.vote_value, u.username, u.user_colour
404
			FROM ' . $this->table_votes . ' as iv,
405
				' . USERS_TABLE . ' as u
406
			WHERE iv.idea_id = ' . (int) $id . '
407
				AND iv.user_id = u.user_id
408
			ORDER BY u.username ASC';
409
		$result = $this->db->sql_query($sql);
410
		$rows = $this->db->sql_fetchrowset($result);
411
		$this->db->sql_freeresult($result);
412
413
		// Process the username for the template now, so it is
414
		// ready to use in AJAX responses and DOM injections.
415
		$profile_url = append_sid(generate_board_url() . "/memberlist.$this->php_ext", array('mode' => 'viewprofile'));
416
		foreach ($rows as &$row)
417
		{
418
			$row['user'] = get_username_string('full', $row['user_id'], $row['username'], $row['user_colour'], false, $profile_url);
419
		}
420
421
		return $rows;
422
	}
423
424
	/**
425
	 * Get a user's stored vote value for a given idea
426
	 *
427
	 * @param int $idea_id The idea id
428
	 * @param int $user_id The user id
429
	 * @return mixed Array with the row data, false if the row does not exist
430
	 */
431
	protected function get_users_vote($idea_id, $user_id)
432
	{
433
		$sql = 'SELECT idea_id, vote_value
434
			FROM ' . $this->table_votes . '
435
			WHERE idea_id = ' . (int) $idea_id . '
436
				AND user_id = ' . (int) $user_id;
437
		$result = $this->db->sql_query_limit($sql, 1);
438
		$row = $this->db->sql_fetchrow();
439
		$this->db->sql_freeresult($result);
440
441
		return $row;
442
	}
443
}
444