createPoll()   A
last analyzed

Complexity

Conditions 3
Paths 4

Size

Total Lines 28
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 16
nc 4
nop 9
dl 0
loc 28
ccs 10
cts 10
cp 1
crap 3
rs 9.7333
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
/**
4
 * This file contains those functions pertaining to polls, including removing
5
 * resetting votes, editing, adding, and more
6
 *
7
 * @package   ElkArte Forum
8
 * @copyright ElkArte Forum contributors
9
 * @license   BSD http://opensource.org/licenses/BSD-3-Clause (see accompanying LICENSE.txt file)
10
 *
11
 * @version 2.0 dev
12
 *
13
 */
14
15
use BBC\ParserWrapper;
16
use ElkArte\User;
17
18
/**
19
 * This function deals with the poll ID associated to a topic.
20
 * It allows to retrieve or update the poll ID associated with this topic ID.
21
 *
22
 * If $pollID is not passed, the current poll ID of the topic, if any, is returned.
23
 * If $pollID is passed, the topic is updated to point to the new poll.
24
 *
25
 * @param int $topicID the ID of the topic
26
 * @param int|null $pollID = null the ID of the poll, if any. If null is passed, it retrieves the current ID.
27
 * @return int
28
 */
29
function associatedPoll($topicID, $pollID = null)
30
{
31
	// Retrieve the poll ID.
32 8
	if ($pollID === null)
33
	{
34 6
		require_once(SUBSDIR . '/Topic.subs.php');
35 6
		$pollID = topicAttribute($topicID, array('id_poll'));
36
37 6
		return $pollID['id_poll'];
38
	}
39
40 8
	setTopicAttribute($topicID, array('id_poll' => $pollID));
41
42 8
	return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type integer.
Loading history...
43
}
44
45
/**
46
 * Remove a poll.
47
 *
48
 * @param int[]|int $pollID The id of the poll to remove
49
 */
50
function removePoll($pollID)
51
{
52
	$db = database();
53 2
54
	$pollID = is_array($pollID) ? $pollID : array($pollID);
55 2
56
	// Remove votes.
57
	$db->query('', '
58 2
		DELETE FROM {db_prefix}log_polls
59
		WHERE id_poll IN ({array_int:id_polls})',
60
		array(
61
			'id_polls' => $pollID,
62 2
		)
63
	);
64
65
	// Remove the choices associated with this poll.
66
	$db->query('', '
67 2
		DELETE FROM {db_prefix}poll_choices
68
		WHERE id_poll IN ({array_int:id_polls})',
69
		array(
70
			'id_polls' => $pollID,
71 2
		)
72
	);
73
74
	// Remove the poll.
75
	$db->query('', '
76 2
		DELETE FROM {db_prefix}polls
77
		WHERE id_poll IN ({array_int:id_polls})',
78
		array(
79
			'id_polls' => $pollID,
80 2
		)
81
	);
82
}
83 2
84
/**
85
 * Reset votes for the poll.
86
 *
87
 * @param int $pollID The ID of the poll to reset the votes on
88
 */
89
function resetVotes($pollID)
90
{
91
	$db = database();
92
93
	$db->query('', '
94
		UPDATE {db_prefix}polls
95
		SET 
96
			num_guest_voters = {int:no_votes}, reset_poll = {int:time}
97
		WHERE id_poll = {int:id_poll}',
98
		array(
99
			'no_votes' => 0,
100
			'id_poll' => $pollID,
101
			'time' => time(),
102
		)
103
	);
104
105
	$db->query('', '
106
		UPDATE {db_prefix}poll_choices
107
		SET 
108
			votes = {int:no_votes}
109
		WHERE id_poll = {int:id_poll}',
110
		array(
111
			'no_votes' => 0,
112
			'id_poll' => $pollID,
113
		)
114
	);
115
116
	$db->query('', '
117
		DELETE FROM {db_prefix}log_polls
118
		WHERE id_poll = {int:id_poll}',
119
		array(
120
			'id_poll' => $pollID,
121
		)
122
	);
123
}
124
125
/**
126
 * Get all poll information you wanted to know.
127
 *
128
 * - Only returns info on the poll, not its options.
129
 *
130
 * @param int $id_poll The id of the poll to load
131
 * @param bool $ignore_permissions if true permissions are not checked.
132
 *             If false, {query_see_board} boardsAllowedTo('poll_view') and
133
 *             $modSettings['postmod_active'] will be considered in the query.
134
 *             This param is currently used only in SSI, it may be useful in any
135
 *             kind of integration
136
 * @return array|false array of poll information, or false if no poll is found
137
 */
138
function pollInfo($id_poll, $ignore_permissions = true)
139
{
140
	global $modSettings;
141
142
	$db = database();
143 2
144
	$boardsAllowed = array();
145 2
	if ($ignore_permissions === false)
146
	{
147 2
		$boardsAllowed = boardsAllowedTo('poll_view');
148 2
149
		if (empty($boardsAllowed))
150
		{
151
			return false;
152
		}
153
	}
154
155
	// Read info from the db
156
	$request = $db->query('', '
157
		SELECT
158
			p.question, p.voting_locked, p.hide_results, p.expire_time, p.max_votes, p.change_vote,
159 2
			p.guest_vote, p.id_member, COALESCE(mem.real_name, p.poster_name) AS poster_name,
160
			p.num_guest_voters, p.reset_poll' . ($ignore_permissions ? '' : ',
161
			b.id_board') . '
162
		FROM {db_prefix}polls AS p
163 2
			LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = p.id_member)' . ($ignore_permissions ? '' : '
164 2
			INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board)') . '
165
		WHERE p.id_poll = {int:id_poll}' . ($ignore_permissions ? '' : ((in_array(0, $boardsAllowed) ? '' : '
166 2
			AND b.id_board IN ({array_int:boards_allowed_see})') . (!$modSettings['postmod_active'] ? '' : '
167 2
			AND t.approved = {int:is_approved}'))) . '
168 2
		LIMIT 1',
169 2
		array(
170 2
			'id_poll' => $id_poll,
171
			'boards_allowed_see' => $boardsAllowed,
172
			'is_approved' => 1,
173 2
		)
174 2
	);
175 2
	$poll_info = $request->fetch_assoc();
176
	$request->free_result();
177
178 2
	if (empty($poll_info))
179 2
	{
180
		return false;
181 2
	}
182
183 2
	$request = $db->query('', '
184
		SELECT COUNT(DISTINCT id_member) AS total
185
		FROM {db_prefix}log_polls
186
		WHERE id_poll = {int:id_poll}
187
			AND id_member != {int:not_guest}',
188
		array(
189
			'id_poll' => $id_poll,
190
			'not_guest' => 0,
191
		)
192
	);
193
	list ($poll_info['total']) = $request->fetch_row();
194
	$request->free_result();
195
196
	// Total voters needs to include guest voters
197
	$poll_info['total'] += $poll_info['num_guest_voters'];
198
199
	return $poll_info;
200
}
201
202
/**
203
 * Retrieve poll information, for the poll associated
204
 * to topic $topicID.
205
 *
206
 * @param int $topicID the topic with an associated poll.
207
 *
208
 * @return string[]|bool
209
 */
210
function pollInfoForTopic($topicID)
211
{
212
	$db = database();
213
214
	// Check if a poll currently exists on this topic, and get the id, question and starter.
215
	$request = $db->query('', '
216 2
		SELECT
217
			t.id_member_started, p.id_poll, p.voting_locked, p.question,
218
			p.hide_results, p.expire_time, p.max_votes, p.change_vote,
219 2
			m.subject, p.guest_vote, p.id_member AS poll_starter
220
		FROM {db_prefix}topics AS t
221
			INNER JOIN {db_prefix}messages AS m ON (m.id_msg = t.id_first_msg)
222
			LEFT JOIN {db_prefix}polls AS p ON (p.id_poll = t.id_poll)
223
		WHERE t.id_topic = {int:current_topic}
224
		LIMIT 1',
225
		array(
226
			'current_topic' => $topicID,
227
		)
228
	);
229
230 2
	// The topic must exist
231
	if ($request->num_rows() === 0)
232
	{
233
		return false;
234
	}
235 2
236
	// Get the poll information.
237
	$pollinfo = $request->fetch_assoc();
238
	$request->free_result();
239
240
	return $pollinfo;
241 2
}
242 2
243
/**
244 2
 * Retrieve the id of the topic associated to a poll
245
 *
246
 * @param int $pollID the topic with an associated poll.
247
 * @return array the topic id and the board id, false if no topics found
248
 */
249
function topicFromPoll($pollID)
250
{
251
	$db = database();
252
253
	// Check if a poll currently exists on this topic, and get the id, question and starter.
254
	$request = $db->query('', '
255
		SELECT
256
			t.id_topic, b.id_board
257
		FROM {db_prefix}topics AS t
258
			LEFT JOIN {db_prefix}polls AS p ON (p.id_poll = t.id_poll)
259
			LEFT JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board)
260
		WHERE p.id_poll = {int:current_poll}
261
		LIMIT 1',
262
		array(
263
			'current_poll' => $pollID,
264
		)
265
	);
266
267
	// The topic must exist
268
	if ($request->num_rows() === 0)
269
	{
270
		$topicID = false;
271
	}
272
	// Get the poll information.
273
	else
274
	{
275
		list ($topicID, $boardID) = $request->fetch_row();
276
	}
277
278
	$request->free_result();
279
280
	return array($topicID, $boardID);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $boardID does not seem to be defined for all execution paths leading up to this point.
Loading history...
281
}
282
283
/**
284
 * Return poll options, customized for a given member.
285
 *
286
 * What it does:
287
 *
288
 * - The function adds to poll options the information if the user
289
 * has voted in this poll.
290
 * - It censors the label in the result array.
291
 *
292
 * @param int $id_poll The id of the poll to query
293
 * @param int $id_member The id of the member
294
 *
295
 * @return array
296
 */
297
function pollOptionsForMember($id_poll, $id_member)
298
{
299
	$db = database();
300
301
	// Get the choices
302
	$pollOptions = array();
303
	$db->fetchQuery('
304
		SELECT 
305
			pc.id_choice, pc.label, pc.votes, COALESCE(lp.id_choice, -1) AS voted_this
306
		FROM {db_prefix}poll_choices AS pc
307
			LEFT JOIN {db_prefix}log_polls AS lp ON (lp.id_choice = pc.id_choice AND lp.id_poll = {int:id_poll} AND lp.id_member = {int:current_member} AND lp.id_member != {int:not_guest})
308
		WHERE pc.id_poll = {int:id_poll}
309
		ORDER by pc.id_choice',
310
		array(
311
			'current_member' => $id_member,
312
			'id_poll' => $id_poll,
313
			'not_guest' => 0,
314
		)
315
	)->fetch_callback(
316
		function ($row) use (&$pollOptions) {
317
			$row['label'] = censor($row['label']);
318
			$pollOptions[$row['id_choice']] = $row;
319
		}
320
	);
321
322
	return $pollOptions;
323
}
324
325
/**
326
 * Returns poll options.
327
 * It censors the label in the result array.
328
 *
329
 * @param int $id_poll The id of the poll to load its options
330
 *
331
 * @return array
332
 */
333
function pollOptions($id_poll)
334
{
335
	$db = database();
336
337
	$pollOptions = array();
338
	$db->fetchQuery('
339
		SELECT 
340
			label, votes, id_choice
341 2
		FROM {db_prefix}poll_choices
342
		WHERE id_poll = {int:id_poll}',
343 2
		array(
344 2
			'id_poll' => $id_poll,
345
		)
346
	)->fetch_callback(
347
		function ($row) use (&$pollOptions) {
348
			$row['label'] = censor($row['label']);
349
			$pollOptions[$row['id_choice']] = $row;
350 2
		}
351
	);
352 2
353
	return $pollOptions;
354 2
}
355 2
356 2
/**
357
 * Create a poll
358
 *
359 2
 * @param string $question The title/question of the poll
360
 * @param int $id_member = false The id of the creator
361
 * @param string $poster_name The name of the poll creator
362
 * @param int $max_votes = 1 The maximum number of votes you can do
363
 * @param int $hide_results = 1 If the results should be hidden
364
 * @param int $expire = 0 The time in days that this poll will expire
365
 * @param int $can_change_vote = 0 If you can change your vote
366
 * @param int $can_guest_vote = 0 If guests can vote
367
 * @param mixed[] $options = array() The poll options
368
 * @return int the id of the created poll
369
 */
370
function createPoll($question, $id_member, $poster_name, $max_votes = 1, $hide_results = 1, $expire = 0, $can_change_vote = 0, $can_guest_vote = 0, array $options = array())
371
{
372
	$expire = empty($expire) ? 0 : time() + $expire * 3600 * 24;
373
374
	$db = database();
375
	$db->insert('',
376
		'{db_prefix}polls',
377
		array(
378
			'question' => 'string-255', 'hide_results' => 'int', 'max_votes' => 'int', 'expire_time' => 'int', 'id_member' => 'int',
379 8
			'poster_name' => 'string-255', 'change_vote' => 'int', 'guest_vote' => 'int'
380
		),
381 8
		array(
382 8
			$question, $hide_results, $max_votes, $expire, $id_member,
383 8
			$poster_name, $can_change_vote, $can_guest_vote,
384
		),
385 8
		array('id_poll')
386
	);
387
388
	$id_poll = $db->insert_id('{db_prefix}polls');
389 8
390 8
	if (!empty($options))
391
	{
392 8
		addPollOptions($id_poll, $options);
0 ignored issues
show
Bug introduced by
It seems like $id_poll can also be of type boolean; however, parameter $id_poll of addPollOptions() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

392
		addPollOptions(/** @scrutinizer ignore-type */ $id_poll, $options);
Loading history...
393
	}
394
395 8
	call_integration_hook('integrate_poll_add_edit', array($id_poll, false));
396
397 8
	return $id_poll;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $id_poll also could return the type boolean which is incompatible with the documented return type integer.
Loading history...
398
}
399
400
/**
401
 * Modify an existing poll
402 8
 *
403
 * @param int $id_poll The id of the poll that should be updated
404 8
 * @param string $question The title/question of the poll
405
 * @param int $max_votes = 1 The maximum number of votes you can do
406
 * @param int $hide_results = 1 If the results should be hidden
407
 * @param int $expire = 0 The time in days that this poll will expire
408
 * @param int $can_change_vote = 0 If you can change your vote
409
 * @param int $can_guest_vote = 0 If guests can vote
410
 */
411
function modifyPoll($id_poll, $question, $max_votes = 1, $hide_results = 1, $expire = 0, $can_change_vote = 0, $can_guest_vote = 0)
412
{
413
	$db = database();
414
415
	$db->query('', '
416
		UPDATE {db_prefix}polls
417
		SET 
418
			question = {string:question}, change_vote = {int:change_vote},' . (allowedTo('moderate_board') ? '
419
			hide_results = {int:hide_results}, expire_time = {int:expire_time}, max_votes = {int:max_votes},
420
			guest_vote = {int:guest_vote}' : '
421
			hide_results = CASE WHEN expire_time = {int:expire_time_zero} AND {int:hide_results} = 2 THEN 1 ELSE {int:hide_results} END') . '
422
		WHERE id_poll = {int:id_poll}',
423
		array(
424
			'id_poll' => $id_poll,
425
			'question' => $question,
426
			'max_votes' => $max_votes,
427
			'hide_results' => $hide_results,
428
			'expire_time' => $expire,
429
			'change_vote' => $can_change_vote,
430
			'guest_vote' => $can_guest_vote,
431
			'expire_time_zero' => 0,
432
		)
433
	);
434
435
	call_integration_hook('integrate_poll_add_edit', array($id_poll, true));
436
}
437
438
/**
439
 * Add options to an already created poll
440
 *
441
 * @param int $id_poll The id of the poll you're adding the options to
442
 * @param mixed[] $options The options to choose from
443
 */
444
function addPollOptions($id_poll, array $options)
445
{
446
	$db = database();
447
448
	$pollOptions = array();
449
	foreach ($options as $i => $option)
450
	{
451
		$pollOptions[] = array($id_poll, $i, $option);
452
	}
453
454
	$db->insert('insert',
455 2
		'{db_prefix}poll_choices',
456
		array('id_poll' => 'int', 'id_choice' => 'int', 'label' => 'string-255'),
457 2
		$pollOptions,
458 2
		array('id_poll', 'id_choice')
459
	);
460 2
}
461
462
/**
463 2
 * Insert some options to an already created poll
464 2
 *
465 2
 * @param mixed[] $options An array holding the poll choices
466 1
 */
467 2
function insertPollOptions($options)
468
{
469 2
	$db = database();
470
471
	$db->insert('',
472
		'{db_prefix}poll_choices',
473
		array(
474
			'id_poll' => 'int', 'id_choice' => 'int', 'label' => 'string-255', 'votes' => 'int',
475
		),
476
		$options,
477
		array()
478
	);
479
}
480
481
/**
482
 * Add a single option to an already created poll
483
 *
484
 * @param mixed[] $options An array holding the poll choices
485
 */
486
function modifyPollOption($options)
487
{
488
	$db = database();
489
490
	foreach ($options as $option)
491
	{
492
		$db->query('', '
493
			UPDATE {db_prefix}poll_choices
494
			SET 
495
				label = {string:option_name}
496
			WHERE id_poll = {int:id_poll}
497
				AND id_choice = {int:id_choice}',
498
			array(
499
				'id_poll' => $option[0],
500
				'id_choice' => $option[1],
501
				'option_name' => $option[2],
502
			)
503
		);
504
	}
505
}
506
507
/**
508
 * Delete a bunch of options from a poll
509
 *
510
 * @param int $id_poll The id of the poll you're deleting the options from
511
 * @param int[] $id_options An array holding the choice id
512
 */
513
function deletePollOptions($id_poll, $id_options)
514
{
515
	$db = database();
516
517
	$db->query('', '
518
		DELETE FROM {db_prefix}log_polls
519
		WHERE id_poll = {int:id_poll}
520
			AND id_choice IN ({array_int:delete_options})',
521
		array(
522
			'delete_options' => $id_options,
523
			'id_poll' => $id_poll,
524
		)
525
	);
526
527
	$db->query('', '
528
		DELETE FROM {db_prefix}poll_choices
529
		WHERE id_poll = {int:id_poll}
530
			AND id_choice IN ({array_int:delete_options})',
531
		array(
532
			'delete_options' => $id_options,
533
			'id_poll' => $id_poll,
534
		)
535
	);
536
}
537
538
/**
539
 * Retrieves the topic and, if different, poll starter
540
 * for the poll associated with the $id_topic.
541
 *
542
 * @param int $id_topic The id of the topic
543
 *
544
 * @return array
545
 */
546
function pollStarters($id_topic)
547
{
548
	$db = database();
549
550
	$pollStarters = array();
551
	$request = $db->query('', '
552
		SELECT 
553
			t.id_member_started, p.id_member AS poll_starter
554
		FROM {db_prefix}topics AS t
555
			INNER JOIN {db_prefix}polls AS p ON (p.id_poll = t.id_poll)
556
		WHERE t.id_topic = {int:current_topic}
557
		LIMIT 1',
558
		array(
559
			'current_topic' => $id_topic,
560
		)
561 2
	);
562
563 2
	if ($request->num_rows() !== 0)
564 2
	{
565
		$pollStarters = $request->fetch_row();
566
	}
567
568
	$request->free_result();
569
570
	return $pollStarters;
571
}
572 2
573
/**
574
 * Check if they have already voted, or voting is locked.
575
 *
576 2
 * @param int $topic the topic with an associated poll
577
 * @return mixed[]
578 2
 */
579
function checkVote($topic)
580
{
581 2
	$db = database();
582
583 2
	return $db->fetchQuery('
584
		SELECT 
585
			COALESCE(lp.id_choice, -1) AS selected, p.voting_locked, p.id_poll, p.expire_time, p.max_votes, p.change_vote,
586
			p.guest_vote, p.reset_poll, p.num_guest_voters
587
		FROM {db_prefix}topics AS t
588
			INNER JOIN {db_prefix}polls AS p ON (p.id_poll = t.id_poll)
589
			LEFT JOIN {db_prefix}log_polls AS lp ON (p.id_poll = lp.id_poll AND lp.id_member = {int:current_member} AND lp.id_member != {int:not_guest})
590
		WHERE t.id_topic = {int:current_topic}
591
		LIMIT 1',
592
		array(
593
			'current_member' => User::$info->id,
0 ignored issues
show
Bug Best Practice introduced by
The property id does not exist on ElkArte\Helper\ValuesContainer. Since you implemented __get, consider adding a @property annotation.
Loading history...
594
			'current_topic' => $topic,
595
			'not_guest' => 0,
596
		)
597
	)->fetch_assoc();
598
}
599
600
/**
601
 * Removes the member's vote from a poll.
602
 *
603
 * @param int $id_member The id of the member
604
 * @param int $id_poll The topic with an associated poll.
605
 */
606
function removeVote($id_member, $id_poll)
607
{
608
	$db = database();
609
610
	$db->query('', '
611
		DELETE FROM {db_prefix}log_polls
612
		WHERE id_member = {int:current_member}
613
			AND id_poll = {int:id_poll}',
614
		array(
615
			'current_member' => $id_member,
616
			'id_poll' => $id_poll,
617
		)
618
	);
619
}
620
621
/**
622
 * Used to decrease the vote counter for the given poll.
623
 *
624
 * @param int $id_poll The id of the poll to lower the vote count
625
 * @param int[] $options The available poll options
626
 */
627
function decreaseVoteCounter($id_poll, $options)
628
{
629
	$db = database();
630
631
	$db->query('', '
632
		UPDATE {db_prefix}poll_choices
633
		SET 
634
		 	votes = votes - 1
635
		WHERE id_poll = {int:id_poll}
636
			AND id_choice IN ({array_int:poll_options})
637
			AND votes > {int:votes}',
638
		array(
639
			'poll_options' => $options,
640
			'id_poll' => $id_poll,
641
			'votes' => 0,
642
		)
643
	);
644
}
645
646
/**
647
 * Increase the vote counter for the given poll.
648
 *
649
 * @param int $id_poll The id of the poll to increase the vote count
650
 * @param int[] $options The available poll options
651
 */
652
function increaseVoteCounter($id_poll, $options)
653
{
654
	$db = database();
655
656
	$db->query('', '
657
		UPDATE {db_prefix}poll_choices
658
		SET 
659
			votes = votes + 1
660
		WHERE id_poll = {int:id_poll}
661
			AND id_choice IN ({array_int:poll_options})',
662
		array(
663
			'poll_options' => $options,
664
			'id_poll' => $id_poll,
665
		)
666
	);
667
}
668
669
/**
670
 * Add a vote to a poll.
671
 *
672
 * @param mixed[] $insert array of vote details, includes member and their choice
673
 */
674
function addVote($insert)
675
{
676
	$db = database();
677
678
	$db->insert('insert',
679
		'{db_prefix}log_polls',
680
		array('id_poll' => 'int', 'id_member' => 'int', 'id_choice' => 'int'),
681
		$insert,
682
		array('id_poll', 'id_member', 'id_choice')
683
	);
684
}
685
686
/**
687
 * Increase the vote counter for guest votes.
688
 *
689
 * @param int $id_poll The id of the poll to increase
690
 */
691
function increaseGuestVote($id_poll)
692
{
693
	$db = database();
694
695
	$db->query('', '
696
		UPDATE {db_prefix}polls
697
		SET 
698
			num_guest_voters = num_guest_voters + 1
699
		WHERE id_poll = {int:id_poll}',
700
		array(
701
			'id_poll' => $id_poll,
702
		)
703
	);
704
}
705
706
/**
707
 * Determines who voted what.
708
 *
709
 * @param int $id_member id of the member who's vote choice we want
710
 * @param int $id_poll id fo the poll the member voted in
711
 *
712
 * @return int[]
713
 */
714
function determineVote($id_member, $id_poll)
715
{
716
	$db = database();
717
	$pollOptions = [];
718
719
	$db->fetchQuery('
720
		SELECT 
721
			id_choice
722
		FROM {db_prefix}log_polls
723
		WHERE id_member = {int:current_member}
724
			AND id_poll = {int:id_poll}',
725
		array(
726
			'current_member' => $id_member,
727
			'id_poll' => $id_poll,
728
		)
729
	)->fetch_callback(
730
		function ($row) use (&$pollOptions) {
731
			if (isset($row['id_choice']))
732
			{
733
				$pollOptions[] = $row['id_choice'];
734
			}
735
		}
736
	);
737
738
	return $pollOptions;
739
}
740
741
/**
742
 * Get some basic details from a poll
743
 *
744
 * @param int $id_topic
745
 * @return string[]|bool
746
 * @deprecated since 2.0 - use pollInfoForTopic instead
747
 */
748
function pollStatus($id_topic)
749
{
750
	\ElkArte\Errors\Errors::instance()->log_deprecated('pollStatus()', 'pollInfoForTopic()');
0 ignored issues
show
Bug introduced by
The type ElkArte\Errors\Errors was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
751
752
	return pollInfoForTopic($id_topic);
753
}
754
755
/**
756
 * Update the locked status from a given poll.
757
 *
758
 * @param int $id_poll The id of the poll to check
759
 * @param int $locked the value to set in voting_locked
760
 */
761
function lockPoll($id_poll, $locked)
762
{
763
	$db = database();
764
765
	$db->query('', '
766
		UPDATE {db_prefix}polls
767
		SET 
768
			voting_locked = {int:voting_locked}
769
		WHERE id_poll = {int:id_poll}',
770
		array(
771
			'voting_locked' => $locked,
772
			'id_poll' => $id_poll,
773
		)
774
	);
775
}
776
777
/**
778
 * Gets poll choices from a given poll.
779
 *
780
 * @param int $id_poll The id of the poll
781
 * @return array
782
 */
783
function getPollChoices($id_poll)
784
{
785
	$db = database();
786
787
	$choices = array();
788
	$number = 1;
789
	$db->fetchQuery('
790
		SELECT 
791
			label, votes, id_choice
792
		FROM {db_prefix}poll_choices
793
		WHERE id_poll = {int:id_poll}',
794
		array(
795
			'id_poll' => $id_poll,
796
		)
797
	)->fetch_callback(
798
		function ($row) use (&$choices, &$number) {
799
			$row['label'] = censor($row['label']);
800
			$choices[$row['id_choice']] = array(
801
				'id' => $row['id_choice'],
802
				'number' => $number++,
803
				'votes' => $row['votes'],
804
				'label' => $row['label'],
805
				'is_last' => false
806
			);
807
		}
808
	);
809
810
	return $choices;
811
}
812
813
/**
814
 * Get the poll starter from a given poll.
815
 *
816
 * @param int $id_topic The id of the topic that has an associated poll
817
 *
818
 * @return array
819
 * @throws \ElkArte\Exceptions\Exception no_board
820
 */
821
function getPollStarter($id_topic)
822
{
823
	$db = database();
824
825
	$request = $db->query('', '
826
		SELECT 
827
			t.id_member_started, t.id_poll, p.id_member AS poll_starter, p.expire_time
828
		FROM {db_prefix}topics AS t
829
			LEFT JOIN {db_prefix}polls AS p ON (p.id_poll = t.id_poll)
830
		WHERE t.id_topic = {int:current_topic}
831
		LIMIT 1',
832
		array(
833
			'current_topic' => $id_topic,
834
		)
835
	);
836
	if ($request->num_rows() === 0)
837
	{
838
		throw new \ElkArte\Exceptions\Exception('no_board');
839
	}
840
	$bcinfo = $request->fetch_assoc();
841
	$request->free_result();
842
843
	return $bcinfo;
844
}
845
846
/**
847
 * Loads in $context whatever is needed to show a poll
848
 *
849
 * @param int $poll_id simply a poll id...
850
 */
851
function loadPollContext($poll_id)
852
{
853
	global $context, $txt;
854
855
	// Get the question and if it's locked.
856
	$pollinfo = pollInfo($poll_id);
857
858
	// Get all the options, and calculate the total votes.
859
	$pollOptions = pollOptionsForMember($poll_id, User::$info->id);
0 ignored issues
show
Bug Best Practice introduced by
The property id does not exist on ElkArte\Helper\ValuesContainer. Since you implemented __get, consider adding a @property annotation.
Loading history...
860
861
	// Compute total votes.
862
	$realtotal = 0;
863
	$pollinfo['has_voted'] = false;
864
	foreach ($pollOptions as $choice)
865
	{
866
		$realtotal += $choice['votes'];
867
		$pollinfo['has_voted'] |= $choice['voted_this'] != -1;
868
	}
869
870
	// If this is a guest we need to do our best to work out if they have voted, and what they voted for.
871
	if (User::$info->is_guest && $pollinfo['guest_vote'] && allowedTo('poll_vote'))
0 ignored issues
show
Bug Best Practice introduced by
The property is_guest does not exist on ElkArte\Helper\ValuesContainer. Since you implemented __get, consider adding a @property annotation.
Loading history...
872
	{
873
		if (!empty($_COOKIE['guest_poll_vote']) && preg_match('~^[0-9,;]+$~', $_COOKIE['guest_poll_vote']) && strpos($_COOKIE['guest_poll_vote'], ';' . $poll_id . ',') !== false)
874
		{
875
			// ;id,timestamp,[vote,vote...]; etc
876
			$guestinfo = explode(';', $_COOKIE['guest_poll_vote']);
877
878
			// Find the poll we're after.
879
			foreach ($guestinfo as $i => $guestvoted)
880
			{
881
				$guestvoted = explode(',', $guestvoted);
882
				if ($guestvoted[0] == $poll_id)
883
				{
884
					break;
885
				}
886
			}
887
888
			// Has the poll been reset since guest voted?
889
			if ($pollinfo['reset_poll'] > $guestvoted[1])
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $guestvoted seems to be defined by a foreach iteration on line 879. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
890
			{
891
				// Remove the poll info from the cookie to allow guest to vote again
892
				unset($guestinfo[$i]);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $i seems to be defined by a foreach iteration on line 879. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
893
				if (!empty($guestinfo))
894
				{
895
					$_COOKIE['guest_poll_vote'] = ';' . implode(';', $guestinfo);
896
				}
897
				else
898
				{
899
					unset($_COOKIE['guest_poll_vote']);
900
				}
901
			}
902
			else
903
			{
904
				// What did they vote for?
905
				unset($guestvoted[0], $guestvoted[1]);
906
				foreach ($pollOptions as $choice => $details)
907
				{
908
					$pollOptions[$choice]['voted_this'] = in_array($choice, $guestvoted) ? 1 : -1;
909
					$pollinfo['has_voted'] |= $pollOptions[$choice]['voted_this'] != -1;
910
				}
911
				unset($choice, $details, $guestvoted);
912
			}
913
			unset($guestinfo, $guestvoted, $i);
914
		}
915
	}
916
917
	$bbc_parser = ParserWrapper::instance();
918
919
	// Set up the basic poll information.
920
	$starter_href = getUrl('profile', ['action' => 'profile', 'u' => $pollinfo['id_member'], 'name' => $pollinfo['poster_name']]);
921
	$context['poll'] = array(
922
		'id' => $poll_id,
923
		'image' => 'normal_' . (empty($pollinfo['voting_locked']) ? 'poll' : 'locked_poll'),
924
		'question' => $bbc_parser->parsePoll($pollinfo['question']),
925
		'total_votes' => $pollinfo['total'],
926
		'change_vote' => !empty($pollinfo['change_vote']),
927
		'is_locked' => !empty($pollinfo['voting_locked']),
928
		'options' => array(),
929
		'lock' => allowedTo('poll_lock_any') || ($context['user']['started'] && allowedTo('poll_lock_own')),
930
		'edit' => allowedTo('poll_edit_any') || ($context['user']['started'] && allowedTo('poll_edit_own')),
931
		'allowed_warning' => $pollinfo['max_votes'] > 1 ? sprintf($txt['poll_options6'], min(count($pollOptions), $pollinfo['max_votes'])) : '',
932
		'is_expired' => !empty($pollinfo['expire_time']) && $pollinfo['expire_time'] < time(),
933
		'expire_time' => !empty($pollinfo['expire_time']) ? standardTime($pollinfo['expire_time']) : 0,
934
		'has_voted' => !empty($pollinfo['has_voted']),
935
		'starter' => array(
936
			'id' => $pollinfo['id_member'],
937
			'name' => $pollinfo['poster_name'],
938
			'href' => $pollinfo['id_member'] == 0 ? '' : $starter_href,
939
			'link' => $pollinfo['id_member'] == 0 ? $pollinfo['poster_name'] : '<a href="' . $starter_href . '">' . $pollinfo['poster_name'] . '</a>'
940
		)
941
	);
942
943
	// Make the lock and edit permissions defined above more directly accessible.
944
	$context['allow_lock_poll'] = $context['poll']['lock'];
945
	$context['allow_edit_poll'] = $context['poll']['edit'];
946
947
	// You're allowed to vote if:
948
	// 1. the poll did not expire, and
949
	// 2. you're either not a guest OR guest voting is enabled... and
950
	// 3. you're not trying to view the results, and
951
	// 4. the poll is not locked, and
952
	// 5. you have the proper permissions, and
953
	// 6. you haven't already voted before.
954
	$context['allow_vote'] = !$context['poll']['is_expired'] && (User::$info->is_guest === false || ($pollinfo['guest_vote'] && allowedTo('poll_vote'))) && empty($pollinfo['voting_locked']) && allowedTo('poll_vote') && !$context['poll']['has_voted'];
955
956
	// You're allowed to view the results if:
957
	// 1. you're just a super-nice-guy, or
958
	// 2. anyone can see them (hide_results == 0), or
959
	// 3. you can see them after you voted (hide_results == 1), or
960
	// 4. you've waited long enough for the poll to expire. (whether hide_results is 1 or 2.)
961
	$context['allow_poll_view'] = allowedTo('moderate_board') || $pollinfo['hide_results'] == 0 || ($pollinfo['hide_results'] == 1 && $context['poll']['has_voted']) || $context['poll']['is_expired'];
962
	$context['poll']['show_results'] = $context['allow_poll_view'] && (isset($_REQUEST['viewresults']) || isset($_REQUEST['viewResults']));
963
964
	// You're allowed to change your vote if:
965
	// 1. the poll did not expire, and
966
	// 2. you're not a guest... and
967
	// 3. the poll is not locked, and
968
	// 4. you have the proper permissions, and
969
	// 5. you have already voted, and
970
	// 6. the poll creator has said you can!
971
	$context['allow_change_vote'] = !$context['poll']['is_expired'] && User::$info->is_guest === false && empty($pollinfo['voting_locked']) && allowedTo('poll_vote') && $context['poll']['has_voted'] && $context['poll']['change_vote'];
972
973
	// You're allowed to return to voting options if:
974
	// 1. you are (still) allowed to vote.
975
	// 2. you are currently seeing the results.
976
	$context['allow_return_vote'] = $context['allow_vote'] && $context['poll']['show_results'];
977
978
	// Calculate the percentages and bar lengths...
979
	$divisor = $realtotal == 0 ? 1 : $realtotal;
0 ignored issues
show
introduced by
The condition $realtotal == 0 is always true.
Loading history...
980
981
	// Determine if a decimal point is needed in order for the options to add to 100%.
982
	$precision = $realtotal == 100 ? 0 : 1;
0 ignored issues
show
introduced by
The condition $realtotal == 100 is always false.
Loading history...
983
984
	// Now look through each option, and...
985
	foreach ($pollOptions as $i => $option)
986
	{
987
		// First calculate the percentage, and then the width of the bar...
988
		$bar = round(($option['votes'] * 100) / $divisor, $precision);
989
		$barWide = $bar == 0 ? 1 : floor(($bar * 8) / 3);
990
991
		// Now add it to the poll's contextual theme data.
992
		$context['poll']['options'][$i] = array(
993
			'id' => 'options-' . $i,
994
			'percent' => $bar,
995
			'votes' => $option['votes'],
996
			'voted_this' => $option['voted_this'] != -1, /* Todo: I notice 'bar' here is not used in the theme any longer - only in SSI. */
997
			'bar' => '<div class="poll_gradient" style="width: ' . $barWide . 'px;"></div>',
998
			'bar_ndt' => $bar > 0 ? '<div class="bar poll-bar" style="width: ' . $bar . '%;"></div>' : '<div class="bar poll-bar"></div>',
999
			'bar_width' => $barWide,
1000
			'option' => $bbc_parser->parsePoll($option['label']),
1001
			'vote_button' => '<input type="' . ($pollinfo['max_votes'] > 1 ? 'checkbox' : 'radio') . '" name="options[]" id="options-' . $i . '" value="' . $i . '" class="input_' . ($pollinfo['max_votes'] > 1 ? 'check' : 'radio') . '" />'
1002
		);
1003
	}
1004
}
1005