2 namespace wcf\data\poll
;
3 use wcf\data\
object\type\ObjectTypeCache
;
4 use wcf\data\poll\option\PollOptionEditor
;
5 use wcf\data\poll\option\PollOptionList
;
6 use wcf\data\AbstractDatabaseObjectAction
;
7 use wcf\data\IGroupedUserListAction
;
8 use wcf\system\exception\PermissionDeniedException
;
9 use wcf\system\exception\UserInputException
;
10 use wcf\system\user\GroupedUserList
;
14 * Executes poll-related actions.
16 * @author Alexander Ebert
17 * @copyright 2001-2019 WoltLab GmbH
18 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
19 * @package WoltLabSuite\Core\Data\Poll
21 * @method PollEditor[] getObjects()
22 * @method PollEditor getSingleObject()
24 class PollAction
extends AbstractDatabaseObjectAction
implements IGroupedUserListAction
{
28 protected $allowGuestAccess = ['getGroupedUserList'];
33 protected $className = PollEditor
::class;
39 protected $poll = null;
45 public function create() {
46 if (!isset($this->parameters
['data']['time'])) $this->parameters
['data']['time'] = TIME_NOW
;
48 /** @var Poll $poll */
49 $poll = parent
::create();
52 $sql = "INSERT INTO wcf".WCF_N
."_poll_option
53 (pollID, optionValue, showOrder)
55 $statement = WCF
::getDB()->prepareStatement($sql);
57 WCF
::getDB()->beginTransaction();
58 foreach ($this->parameters
['options'] as $showOrder => $option) {
61 $option['optionValue'],
65 WCF
::getDB()->commitTransaction();
73 public function update() {
77 $pollEditor = reset($this->objects
);
79 // get current options
80 $optionList = new PollOptionList();
81 $optionList->getConditionBuilder()->add("poll_option.pollID = ?", [$pollEditor->pollID
]);
82 $optionList->sqlOrderBy
= "poll_option.showOrder ASC";
83 $optionList->readObjects();
84 $options = $optionList->getObjects();
86 $newOptions = $updateOptions = [];
87 foreach ($this->parameters
['options'] as $showOrder => $option) {
88 // check if editing an existing option
89 if ($option['optionID']) {
90 // check if an update is required
91 if ($options[$option['optionID']]->showOrder
!= $showOrder ||
$options[$option['optionID']]->optionValue
!= $option['optionValue']) {
92 $updateOptions[$option['optionID']] = [
93 'optionValue' => $option['optionValue'],
94 'showOrder' => $showOrder
99 unset($options[$option['optionID']]);
103 'optionValue' => $option['optionValue'],
104 'showOrder' => $showOrder
109 if (!empty($newOptions) ||
!empty($updateOptions) ||
!empty($options)) {
110 WCF
::getDB()->beginTransaction();
112 // check if new options should be created
113 if (!empty($newOptions)) {
114 $sql = "INSERT INTO wcf".WCF_N
."_poll_option
115 (pollID, optionValue, showOrder)
117 $statement = WCF
::getDB()->prepareStatement($sql);
118 foreach ($newOptions as $option) {
119 $statement->execute([
121 $option['optionValue'],
127 // check if existing options should be updated
128 if (!empty($updateOptions)) {
129 $sql = "UPDATE wcf".WCF_N
."_poll_option
133 $statement = WCF
::getDB()->prepareStatement($sql);
134 foreach ($updateOptions as $optionID => $option) {
135 $statement->execute([
136 $option['optionValue'],
137 $option['showOrder'],
143 // check if options should be removed
144 if (!empty($options)) {
145 $sql = "DELETE FROM wcf".WCF_N
."_poll_option
147 $statement = WCF
::getDB()->prepareStatement($sql);
148 foreach ($options as $option) {
149 $statement->execute([$option->optionID
]);
153 // force recalculation of poll stats
154 $pollEditor->calculateVotes();
156 WCF
::getDB()->commitTransaction();
161 * Executes a user's vote.
163 public function vote() {
164 $poll = current($this->objects
);
167 $sql = "SELECT optionID
168 FROM wcf".WCF_N
."_poll_option_vote
171 $statement = WCF
::getDB()->prepareStatement($sql);
172 $statement->execute([
174 WCF
::getUser()->userID
176 $optionIDs = $statement->fetchAll(\PDO
::FETCH_COLUMN
);
177 $alreadyVoted = !empty($optionIDs);
179 // calculate the difference
180 foreach ($this->parameters
['optionIDs'] as $index => $optionID) {
181 $optionsIndex = array_search($optionID, $optionIDs);
182 if ($optionsIndex !== false) {
183 // ignore this option
184 unset($this->parameters
['optionIDs'][$index]);
185 unset($optionIDs[$optionsIndex]);
189 // insert new vote options
190 if (!empty($this->parameters
['optionIDs'])) {
191 $sql = "INSERT INTO wcf".WCF_N
."_poll_option_vote
192 (pollID, optionID, userID)
194 $statement = WCF
::getDB()->prepareStatement($sql);
195 foreach ($this->parameters
['optionIDs'] as $optionID) {
196 $statement->execute([
199 WCF
::getUser()->userID
203 // increase votes per option
204 $sql = "UPDATE wcf".WCF_N
."_poll_option
205 SET votes = votes + 1
207 $statement = WCF
::getDB()->prepareStatement($sql);
208 foreach ($this->parameters
['optionIDs'] as $optionID) {
209 $statement->execute([$optionID]);
213 // remove previous options
214 if (!empty($optionIDs)) {
215 $sql = "DELETE FROM wcf".WCF_N
."_poll_option_vote
218 $statement = WCF
::getDB()->prepareStatement($sql);
219 foreach ($optionIDs as $optionID) {
220 $statement->execute([
222 WCF
::getUser()->userID
226 // decrease votes per option
227 $sql = "UPDATE wcf".WCF_N
."_poll_option
228 SET votes = votes - 1
230 $statement = WCF
::getDB()->prepareStatement($sql);
231 foreach ($optionIDs as $optionID) {
232 $statement->execute([$optionID]);
236 // increase poll votes
237 if (!$alreadyVoted) {
238 $poll->increaseVotes();
245 public function validateGetGroupedUserList() {
246 $this->readInteger('pollID');
249 $this->poll
= new Poll($this->parameters
['pollID']);
250 if (!$this->poll
->pollID
) {
251 throw new UserInputException('pollID');
253 else if (!$this->poll
->canViewParticipants()) {
254 throw new PermissionDeniedException();
261 public function getGroupedUserList() {
263 $sql = "SELECT optionID, optionValue
264 FROM wcf".WCF_N
."_poll_option
266 ORDER BY ".($this->poll
->sortByVotes ?
"votes DESC" : "showOrder ASC");
267 $statement = WCF
::getDB()->prepareStatement($sql);
268 $statement->execute([$this->poll
->pollID
]);
270 while ($row = $statement->fetchArray()) {
271 $options[$row['optionID']] = new GroupedUserList($row['optionValue'], 'wcf.poll.noVotes');
275 $sql = "SELECT userID, optionID
276 FROM wcf".WCF_N
."_poll_option_vote
278 $statement = WCF
::getDB()->prepareStatement($sql);
279 $statement->execute([$this->poll
->pollID
]);
280 $voteData = $statement->fetchMap('optionID', 'userID', false);
283 foreach ($voteData as $optionID => $userIDs) {
284 $options[$optionID]->addUserIDs($userIDs);
287 // load user profiles
288 GroupedUserList
::loadUsers();
290 WCF
::getTPL()->assign([
291 'groupedUsers' => $options
296 'template' => WCF
::getTPL()->fetch('groupedUserList')
301 * Copies a poll from one object id to another.
303 public function copy() {
304 $sourceObjectType = ObjectTypeCache
::getInstance()->getObjectTypeByName('com.woltlab.wcf.poll', $this->parameters
['sourceObjectType']);
305 $targetObjectType = ObjectTypeCache
::getInstance()->getObjectTypeByName('com.woltlab.wcf.poll', $this->parameters
['targetObjectType']);
313 FROM wcf".WCF_N
."_poll
314 WHERE objectTypeID = ?
316 $statement = WCF
::getDB()->prepareStatement($sql);
317 $statement->execute([
318 $sourceObjectType->objectTypeID
,
319 $this->parameters
['sourceObjectID']
321 $row = $statement->fetchArray();
323 if ($row === false) {
330 $pollOptionList = new PollOptionList();
331 $pollOptionList->getConditionBuilder()->add("poll_option.pollID = ?", [$row['pollID']]);
332 $pollOptionList->readObjects();
340 $pollData['objectTypeID'] = $targetObjectType->objectTypeID
;
341 $pollData['objectID'] = $this->parameters
['targetObjectID'];
342 unset($pollData['pollID']);
344 $newPoll = PollEditor
::create($pollData);
348 foreach ($pollOptionList as $pollOption) {
349 $newOption = PollOptionEditor
::create([
350 'pollID' => $newPoll->pollID
,
351 'optionValue' => $pollOption->optionValue
,
352 'votes' => $pollOption->votes
,
353 'showOrder' => $pollOption->showOrder
356 $newOptionIDs[$pollOption->optionID
] = $newOption->optionID
;
360 WCF
::getDB()->beginTransaction();
361 foreach ($newOptionIDs as $oldOptionID => $newOptionID) {
362 $sql = "INSERT INTO wcf".WCF_N
."_poll_option_vote
363 (pollID, optionID, userID)
364 SELECT ".$newPoll->pollID
.", ".$newOptionID.", userID
365 FROM wcf".WCF_N
."_poll_option_vote
367 $statement = WCF
::getDB()->prepareStatement($sql);
368 $statement->execute([$oldOptionID]);
370 WCF
::getDB()->commitTransaction();
373 'pollID' => $newPoll->pollID