/** * Returns the votes of a given user for this bracket * @param User $user The user to fetch votes for * @param bool $force Bypass cache and force read from DB */ public function getVotesForUser(User $user, $force = false) { $retVal = null; if ($user instanceof User) { $cacheKey = 'Api:Bracket:getVotesForUser_' . $this->id . '_' . $user->id; $retVal = Lib\Cache::fetchLongCache(function () use($user) { $params = [':userId' => $user->id, ':bracketId' => $this->id]; $result = Lib\Db::Query('SELECT round_id, character_id FROM votes WHERE user_id = :userId AND bracket_id = :bracketId', $params); $retVal = []; if ($result && $result->count) { while ($row = Lib\Db::Fetch($result)) { $retVal[$row->round_id] = (int) $row->character_id; } } return $retVal; }, $cacheKey, $force); } return $retVal; }
/** * Generates a list of characters in a bracket (ordered by seed) and their performance * in said bracket */ public static function getEntrantPerformanceStats(Bracket $bracket, $force = false) { return Lib\Cache::fetchLongCache(function () use($bracket) { // Get all tourney rounds and characters for this bracket $characters = Character::queryReturnAll(['bracketId' => $bracket->id, 'seed' => ['null' => false]], ['seed' => 'asc']); $rounds = Round::queryReturnAll(['bracketId' => $bracket->id, 'final' => 1, 'tier' => ['gt' => 0]], ['id' => 'asc']); // Create a hash out of the characters $temp = []; foreach ($characters as $character) { $temp[$character->id] = $character; } $characters = $temp; // Sort the rounds out based on character for faster access later $characterRounds = []; foreach ($rounds as $round) { // Decorate the round with full character models $round->character1 = $characters[$round->character1Id]; $round->character2 = $characters[$round->character2Id]; self::_addRoundToCharacterRounds($round, $round->character1Id, $characterRounds); self::_addRoundToCharacterRounds($round, $round->character2Id, $characterRounds); } $retVal = []; foreach ($characters as $character) { $roundsForCharacter = array_values($characterRounds[$character->id]); $closestDiff = -1; $closestRound = null; $lostTo = null; $totalVotes = 0; foreach ($roundsForCharacter as $round) { // Heheheh... so gross $isCharacter1 = $round->character1Id == $character->id; $totalVotes += $isCharacter1 ? $round->character1Votes : $round->character2Votes; $diff = abs($round->character1Votes - $round->character2Votes); if ($diff < $closestDiff || $closestDiff === -1) { $closestDiff = $diff; // This case should be small enough that re-instantiating through a loop // shouldn't prove too much of a performance concern (especially since // it's generated only once per new round). Will monitor in production $closestRound = (object) ['character' => $isCharacter1 ? $round->character2 : $round->character1, 'difference' => $closestDiff, 'round' => $round]; } $lost = $isCharacter1 && $round->character1Votes < $round->character2Votes || !$isCharacter1 && $round->character2Votes < $round->character1Votes; $lostTo = $lost ? (object) ['character' => $isCharacter1 ? $round->character2 : $round->character1, 'lostBy' => $diff, 'round' => $round] : null; } $retVal[] = (object) ['character' => $character, 'closestRound' => $closestRound, 'lostTo' => $lostTo, 'totalVotes' => $totalVotes, 'group' => chr(65 + $roundsForCharacter[0]->group)]; } return $retVal; }, 'Stats::PerformanceStats_' . $bracket->id, $force); }