3 namespace wcf\data\poll
;
5 use wcf\data\AbstractDatabaseObjectAction
;
6 use wcf\data\IGroupedUserListAction
;
7 use wcf\data\
object\type\ObjectTypeCache
;
8 use wcf\data\poll\option\PollOptionEditor
;
9 use wcf\data\poll\option\PollOptionList
;
10 use wcf\system\exception\PermissionDeniedException
;
11 use wcf\system\exception\UserInputException
;
12 use wcf\system\user\GroupedUserList
;
16 * Executes poll-related actions.
18 * @author Alexander Ebert
19 * @copyright 2001-2019 WoltLab GmbH
20 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
21 * @package WoltLabSuite\Core\Data\Poll
23 * @method PollEditor[] getObjects()
24 * @method PollEditor getSingleObject()
26 class PollAction
extends AbstractDatabaseObjectAction
implements IGroupedUserListAction
31 protected $allowGuestAccess = ['getGroupedUserList'];
36 protected $className = PollEditor
::class;
48 public function create()
50 if (!isset($this->parameters
['data']['time'])) {
51 $this->parameters
['data']['time'] = TIME_NOW
;
54 /** @var Poll $poll */
55 $poll = parent
::create();
58 $sql = "INSERT INTO wcf" . WCF_N
. "_poll_option
59 (pollID, optionValue, showOrder)
61 $statement = WCF
::getDB()->prepareStatement($sql);
63 WCF
::getDB()->beginTransaction();
64 foreach ($this->parameters
['options'] as $showOrder => $option) {
67 $option['optionValue'],
71 WCF
::getDB()->commitTransaction();
79 public function update()
84 $pollEditor = \reset
($this->objects
);
86 // get current options
87 $optionList = new PollOptionList();
88 $optionList->getConditionBuilder()->add("poll_option.pollID = ?", [$pollEditor->pollID
]);
89 $optionList->sqlOrderBy
= "poll_option.showOrder ASC";
90 $optionList->readObjects();
91 $options = $optionList->getObjects();
93 $newOptions = $updateOptions = [];
94 foreach ($this->parameters
['options'] as $showOrder => $option) {
95 // check if editing an existing option
96 if ($option['optionID']) {
97 // check if an update is required
98 if ($options[$option['optionID']]->showOrder
!= $showOrder ||
$options[$option['optionID']]->optionValue
!= $option['optionValue']) {
99 $updateOptions[$option['optionID']] = [
100 'optionValue' => $option['optionValue'],
101 'showOrder' => $showOrder,
106 unset($options[$option['optionID']]);
109 'optionValue' => $option['optionValue'],
110 'showOrder' => $showOrder,
115 if (!empty($newOptions) ||
!empty($updateOptions) ||
!empty($options)) {
116 WCF
::getDB()->beginTransaction();
118 // check if new options should be created
119 if (!empty($newOptions)) {
120 $sql = "INSERT INTO wcf" . WCF_N
. "_poll_option
121 (pollID, optionValue, showOrder)
123 $statement = WCF
::getDB()->prepareStatement($sql);
124 foreach ($newOptions as $option) {
125 $statement->execute([
127 $option['optionValue'],
128 $option['showOrder'],
133 // check if existing options should be updated
134 if (!empty($updateOptions)) {
135 $sql = "UPDATE wcf" . WCF_N
. "_poll_option
139 $statement = WCF
::getDB()->prepareStatement($sql);
140 foreach ($updateOptions as $optionID => $option) {
141 $statement->execute([
142 $option['optionValue'],
143 $option['showOrder'],
149 // check if options should be removed
150 if (!empty($options)) {
151 $sql = "DELETE FROM wcf" . WCF_N
. "_poll_option
153 $statement = WCF
::getDB()->prepareStatement($sql);
154 foreach ($options as $option) {
155 $statement->execute([$option->optionID
]);
159 // force recalculation of poll stats
160 $pollEditor->calculateVotes();
162 WCF
::getDB()->commitTransaction();
167 * Executes a user's vote.
169 public function vote()
171 $poll = \
current($this->objects
);
174 $sql = "SELECT optionID
175 FROM wcf" . WCF_N
. "_poll_option_vote
178 $statement = WCF
::getDB()->prepareStatement($sql);
179 $statement->execute([
181 WCF
::getUser()->userID
,
183 $optionIDs = $statement->fetchAll(\PDO
::FETCH_COLUMN
);
184 $alreadyVoted = !empty($optionIDs);
186 // calculate the difference
187 foreach ($this->parameters
['optionIDs'] as $index => $optionID) {
188 $optionsIndex = \array_search
($optionID, $optionIDs);
189 if ($optionsIndex !== false) {
190 // ignore this option
191 unset($this->parameters
['optionIDs'][$index]);
192 unset($optionIDs[$optionsIndex]);
196 // insert new vote options
197 if (!empty($this->parameters
['optionIDs'])) {
198 $sql = "INSERT INTO wcf" . WCF_N
. "_poll_option_vote
199 (pollID, optionID, userID)
201 $statement = WCF
::getDB()->prepareStatement($sql);
202 foreach ($this->parameters
['optionIDs'] as $optionID) {
203 $statement->execute([
206 WCF
::getUser()->userID
,
210 // increase votes per option
211 $sql = "UPDATE wcf" . WCF_N
. "_poll_option
212 SET votes = votes + 1
214 $statement = WCF
::getDB()->prepareStatement($sql);
215 foreach ($this->parameters
['optionIDs'] as $optionID) {
216 $statement->execute([$optionID]);
220 // remove previous options
221 if (!empty($optionIDs)) {
222 $sql = "DELETE FROM wcf" . WCF_N
. "_poll_option_vote
225 $statement = WCF
::getDB()->prepareStatement($sql);
226 foreach ($optionIDs as $optionID) {
227 $statement->execute([
229 WCF
::getUser()->userID
,
233 // decrease votes per option
234 $sql = "UPDATE wcf" . WCF_N
. "_poll_option
235 SET votes = votes - 1
237 $statement = WCF
::getDB()->prepareStatement($sql);
238 foreach ($optionIDs as $optionID) {
239 $statement->execute([$optionID]);
243 // increase poll votes
244 if (!$alreadyVoted) {
245 $poll->increaseVotes();
252 public function validateGetGroupedUserList()
254 $this->readInteger('pollID');
257 $this->poll
= new Poll($this->parameters
['pollID']);
258 if (!$this->poll
->pollID
) {
259 throw new UserInputException('pollID');
260 } elseif (!$this->poll
->canViewParticipants()) {
261 throw new PermissionDeniedException();
268 public function getGroupedUserList()
271 $sql = "SELECT optionID, optionValue
272 FROM wcf" . WCF_N
. "_poll_option
274 ORDER BY " . ($this->poll
->sortByVotes ?
"votes DESC" : "showOrder ASC");
275 $statement = WCF
::getDB()->prepareStatement($sql);
276 $statement->execute([$this->poll
->pollID
]);
278 while ($row = $statement->fetchArray()) {
279 $options[$row['optionID']] = new GroupedUserList($row['optionValue'], 'wcf.poll.noVotes');
283 $sql = "SELECT userID, optionID
284 FROM wcf" . WCF_N
. "_poll_option_vote
286 $statement = WCF
::getDB()->prepareStatement($sql);
287 $statement->execute([$this->poll
->pollID
]);
288 $voteData = $statement->fetchMap('optionID', 'userID', false);
291 foreach ($voteData as $optionID => $userIDs) {
292 $options[$optionID]->addUserIDs($userIDs);
295 // load user profiles
296 GroupedUserList
::loadUsers();
298 WCF
::getTPL()->assign([
299 'groupedUsers' => $options,
304 'template' => WCF
::getTPL()->fetch('groupedUserList'),
309 * Copies a poll from one object id to another.
311 public function copy()
313 $sourceObjectType = ObjectTypeCache
::getInstance()->getObjectTypeByName(
314 'com.woltlab.wcf.poll',
315 $this->parameters
['sourceObjectType']
317 $targetObjectType = ObjectTypeCache
::getInstance()->getObjectTypeByName(
318 'com.woltlab.wcf.poll',
319 $this->parameters
['targetObjectType']
328 FROM wcf" . WCF_N
. "_poll
329 WHERE objectTypeID = ?
331 $statement = WCF
::getDB()->prepareStatement($sql);
332 $statement->execute([
333 $sourceObjectType->objectTypeID
,
334 $this->parameters
['sourceObjectID'],
336 $row = $statement->fetchArray();
338 if ($row === false) {
345 $pollOptionList = new PollOptionList();
346 $pollOptionList->getConditionBuilder()->add("poll_option.pollID = ?", [$row['pollID']]);
347 $pollOptionList->readObjects();
355 $pollData['objectTypeID'] = $targetObjectType->objectTypeID
;
356 $pollData['objectID'] = $this->parameters
['targetObjectID'];
357 unset($pollData['pollID']);
359 $newPoll = PollEditor
::create($pollData);
363 foreach ($pollOptionList as $pollOption) {
364 $newOption = PollOptionEditor
::create([
365 'pollID' => $newPoll->pollID
,
366 'optionValue' => $pollOption->optionValue
,
367 'votes' => $pollOption->votes
,
368 'showOrder' => $pollOption->showOrder
,
371 $newOptionIDs[$pollOption->optionID
] = $newOption->optionID
;
375 WCF
::getDB()->beginTransaction();
376 foreach ($newOptionIDs as $oldOptionID => $newOptionID) {
377 $sql = "INSERT INTO wcf" . WCF_N
. "_poll_option_vote
378 (pollID, optionID, userID)
379 SELECT " . $newPoll->pollID
. ", " . $newOptionID . ", userID
380 FROM wcf" . WCF_N
. "_poll_option_vote
382 $statement = WCF
::getDB()->prepareStatement($sql);
383 $statement->execute([$oldOptionID]);
385 WCF
::getDB()->commitTransaction();
388 'pollID' => $newPoll->pollID
,