Seditio Source
Root |
./othercms/xenForo 2.2.8/src/XF/Repository/Poll.php
<?php

namespace XF\Repository;

use
XF\Mvc\Entity\Repository;

use function
count, is_array;

class
Poll extends Repository
{
    public function
resetPollVotes(\XF\Entity\Poll $poll)
    {
       
$db = $this->db();

       
$db->beginTransaction();

       
$db->delete('xf_poll_vote', 'poll_id = ?', $poll->poll_id);
       
$this->rebuildPollData($poll->poll_id);

       
$db->commit();
    }

    public function
voteOnPoll(\XF\Entity\Poll $poll, $votes, \XF\Entity\User $voter = null)
    {
       
$voter = $voter ?: \XF::visitor();
       
$responses = $poll->Responses;

        if (!
is_array($votes))
        {
           
$votes = [$votes];
        }

        foreach (
$votes AS $k => $responseId)
        {
            if (!isset(
$responses[$responseId]))
            {
                unset(
$votes[$k]);
            }
        }

        if (!
$votes)
        {
            return
false;
        }

       
$db = $this->db();

       
$db->beginTransaction();

       
$rawPoll = $db->fetchRow("
            SELECT *
            FROM xf_poll
            WHERE poll_id = ?
            FOR UPDATE
        "
, $poll->poll_id);

       
$previousVotes = $db->delete('xf_poll_vote', 'poll_id = ? AND user_id = ?', [$poll->poll_id, $voter->user_id]);
       
$newVoter = ($previousVotes == 0);

        foreach (
$votes AS $responseId)
        {
           
// votes have been validated against this poll

            /** @var \XF\Entity\PollResponse $response */
           
$response = $responses[$responseId];

           
$inserted = $db->insert('xf_poll_vote', [
               
'user_id' => $voter->user_id,
               
'poll_response_id' => $responseId,
               
'poll_id' => $poll->poll_id,
               
'vote_date' => \XF::$time
           
], false, false, 'IGNORE');
            if (
$newVoter && $inserted)
            {
               
// can take a short cut as we know they haven't voted before
                // otherwise we need to do a rebuild
               
$response->updateForNewVote($voter);
            }
        }

       
$poll->clearCache('Votes');

        if (
$newVoter)
        {
           
$poll->voter_count = $rawPoll['voter_count'] + 1;
           
$poll->save(); // triggers the response cache rebuild
       
}
        else
        {
           
$this->rebuildPollData($poll->poll_id);
        }

       
$db->commit();

        return
true;
    }

    public function
rebuildPollData($pollId)
    {
       
$poll = $this->em->find('XF:Poll', $pollId);
        if (!
$poll)
        {
            return
false;
        }

       
$db = $this->db();

       
$results = $db->fetchAll("
            SELECT *
            FROM xf_poll_vote
            WHERE poll_id = ?
        "
, $poll->poll_id);

       
$votes = [];
       
$voters = [];

        foreach (
$results AS $vote)
        {
           
$votes[$vote['poll_response_id']][$vote['user_id']] = true;
           
$voters[$vote['user_id']] = true;
        }

       
$db->beginTransaction();

       
/** @var \XF\Entity\PollResponse $response */
       
foreach ($poll->Responses AS $response)
        {
           
$responseId = $response->poll_response_id;
           
$responseVotes = $votes[$responseId] ?? [];

           
$response->fastUpdate([
               
'response_vote_count' => count($responseVotes),
               
'voters' => $responseVotes
           
]);
        }

       
$voters = count($voters);
       
$responseCache = $this->getResponseCacheData($poll->poll_id);

       
$poll->fastUpdate([
           
'voter_count' => $voters,
           
'responses' => $responseCache
       
]);

       
$db->commit();

        return
true;
    }

    public function
getResponseCacheData($pollId)
    {
       
$cache = [];

       
$responses = $this->finder('XF:PollResponse')
            ->
where('poll_id', $pollId)
            ->
order('poll_response_id');

        foreach (
$responses->fetch() AS $response)
        {
           
$cache[$response->poll_response_id] = [
               
'response' => $response->response,
               
'response_vote_count' => $response->response_vote_count,
               
'voters' => $response->voters
           
];
        }

        return
$cache;
    }

   
/**
     * @return \XF\Poll\AbstractHandler[]
     */
   
public function getPollHandlers()
    {
       
$handlers = [];

        foreach (\
XF::app()->getContentTypeField('poll_handler_class') AS $contentType => $handlerClass)
        {
            if (
class_exists($handlerClass))
            {
               
$handlerClass = \XF::extendClass($handlerClass);
               
$handlers[$contentType] = new $handlerClass($contentType);
            }
        }

        return
$handlers;
    }

   
/**
     * @param string $type
     * @param bool $throw
     *
     * @return \XF\Poll\AbstractHandler|null
     */
   
public function getPollHandler($type, $throw = false)
    {
       
$handlerClass = \XF::app()->getContentTypeFieldValue($type, 'poll_handler_class');
        if (!
$handlerClass)
        {
            if (
$throw)
            {
                throw new \
InvalidArgumentException("No poll handler for '$type'");
            }
            return
null;
        }

        if (!
class_exists($handlerClass))
        {
            if (
$throw)
            {
                throw new \
InvalidArgumentException("Poll handler for '$type' does not exist: $handlerClass");
            }
            return
null;
        }

       
$handlerClass = \XF::extendClass($handlerClass);
        return new
$handlerClass($type);
    }
}