src/models/Poll.php
<?php
namespace bizley\podium\models;
use bizley\podium\db\Query;
use bizley\podium\log\Log;
use bizley\podium\models\db\PollActiveRecord;
use bizley\podium\Podium;
use Exception;
use yii\helpers\ArrayHelper;
/**
* Poll model
* Forum polls.
*
* @author Paweł Bizley Brzozowski <pawel@positive.codes>
* @since 0.5
*
* @property array $currentVotes
* @property int $votesCount
* @property PollAnswer[] $sortedAnswers
*/
class Poll extends PollActiveRecord
{
/**
* Sorted answers.
* @return PollAnswer[]
*/
public function getSortedAnswers()
{
return $this->getAnswers()->orderBy(['votes' => SORT_DESC])->all();
}
/**
* Checks if user has already voted in poll.
* @param int $userId
* @return bool
*/
public function getUserVoted($userId)
{
return (new Query())->from('{{%podium_poll_vote}}')->where([
'poll_id' => $this->id,
'caster_id' => $userId
])->count('id') ? true : false;
}
/**
* Votes in poll.
* @param int $userId
* @param array $answers
* @return bool
*/
public function vote($userId, $answers)
{
$votes = [];
$time = time();
foreach ($answers as $answer) {
$votes[] = [$this->id, $answer, $userId, $time];
}
if (!empty($votes)) {
$transaction = static::getDb()->beginTransaction();
try {
if (!Podium::getInstance()->db->createCommand()->batchInsert(
'{{%podium_poll_vote}}', ['poll_id', 'answer_id', 'caster_id', 'created_at'], $votes
)->execute()) {
throw new Exception('Votes saving error!');
}
if (!PollAnswer::updateAllCounters(['votes' => 1], ['id' => $answers])) {
throw new Exception('Votes adding error!');
}
$transaction->commit();
return true;
} catch (Exception $e) {
$transaction->rollBack();
Log::error($e->getMessage(), $this->id, __METHOD__);
}
}
return false;
}
/**
* Checks if poll has given answer.
* @param int $answerId
* @return bool
*/
public function hasAnswer($answerId)
{
foreach ($this->answers as $answer) {
if ($answer->id == $answerId) {
return true;
}
}
return false;
}
/**
* Returns list of answers with the current number of votes.
* @return array
*/
public function getCurrentVotes()
{
$this->refresh();
return ArrayHelper::map($this->answers, 'id', 'votes');
}
/**
* Returns number of casted votes.
* @return int
*/
public function getVotesCount()
{
$votes = 0;
foreach ($this->answers as $answer) {
$votes += $answer->votes;
}
return $votes;
}
/**
* Performs poll delete with answers and votes.
* @return bool
*/
public function podiumDelete()
{
$transaction = static::getDb()->beginTransaction();
try {
if (!Podium::getInstance()->db->createCommand()->delete('{{%podium_poll_vote}}', ['poll_id' => $this->id])->execute()) {
throw new Exception('Poll Votes deleting error!');
}
if (!PollAnswer::deleteAll(['poll_id' => $this->id])) {
throw new Exception('Poll Answers deleting error!');
}
if (!$this->delete()) {
throw new Exception('Poll deleting error!');
}
$transaction->commit();
Log::info('Poll deleted', !empty($this->id) ? $this->id : '', __METHOD__);
return true;
} catch (Exception $e) {
$transaction->rollBack();
Log::error($e->getMessage(), null, __METHOD__);
}
return false;
}
/**
* Performs poll update.
* @return bool
*/
public function podiumEdit()
{
$transaction = static::getDb()->beginTransaction();
try {
if (!$this->save()) {
throw new Exception('Poll saving error!');
}
foreach ($this->editAnswers as $answer) {
foreach ($this->answers as $oldAnswer) {
if ($answer == $oldAnswer->answer) {
continue(2);
}
}
$pollAnswer = new PollAnswer();
$pollAnswer->poll_id = $this->id;
$pollAnswer->answer = $answer;
if (!$pollAnswer->save()) {
throw new Exception('Poll Answer saving error!');
}
}
foreach ($this->answers as $oldAnswer) {
foreach ($this->editAnswers as $answer) {
if ($answer == $oldAnswer->answer) {
continue(2);
}
}
if (!$oldAnswer->delete()) {
throw new Exception('Poll Answer deleting error!');
}
}
$transaction->commit();
Log::info('Poll updated', $this->id, __METHOD__);
return true;
} catch (Exception $e) {
$transaction->rollBack();
Log::error($e->getMessage(), null, __METHOD__);
}
return false;
}
}