private static function _getVotesOverTime($vars, $users = false) { $time = time(); $startDate = Lib\Url::GetInt('startDate', $time - 3600 * 24, $vars); // Default to the last 24 hours $endDate = Lib\Url::GetInt('endDate', $time, $vars); $bracketId = Lib\Url::GetInt('bracketId', null, $vars); $granularity = Lib\Url::GetInt('granularity', 2, $vars); $cacheKey = '_getVotesOverTime_' . implode('_', [$startDate, $endDate, $bracketId, $granularity, $users]); $retVal = Lib\Cache::Get($cacheKey); if (false === $retVal && $bracketId) { $selectCount = $users ? 'DISTINCT user_id' : '1'; $result = Lib\Db::Query('SELECT COUNT(' . $selectCount . ') AS total, DATE(FROM_UNIXTIME(vote_date)) AS date, HOUR(FROM_UNIXTIME(vote_date)) AS hour, (MINUTE(FROM_UNIXTIME(vote_date)) % :granularity) AS hour_fraction FROM votes WHERE bracket_id = :bracketId AND vote_date BETWEEN :start AND :end GROUP BY date, hour, hour_fraction ORDER BY date, hour, hour_fraction', [':granularity' => $granularity, ':bracketId' => $bracketId, ':start' => $startDate, ':end' => $endDate]); if ($result && $result->count) { $retVal = []; while ($row = Lib\Db::Fetch($result)) { $obj = new stdClass(); $obj->date = (int) $row->date; $obj->hour = (int) $row->hour; $obj->minutes = $row->hour_fraction == 0 ? 0 : 60 * ((int) $row->hour_fraction / $granularity); $obj->count = (int) $row->total; $retVal[] = $obj; } Lib\Cache::Set($cacheKey, $retVal, STATS_CACHE_DURATION); } } return $retVal; }
public static function set($key, $value) { if (!self::$_sess instanceof stdClass) { self::$_sess = new stdClass(); } self::$_sess->{$key} = $value; Cache::Set(SESSION_NAME . '_' . self::$_id, self::$_sess, SESSION_EXPIRE); }
/** * Gets all characters for a bracket */ public static function getByBracketId($bracketId) { $retVal = null; if (is_numeric($bracketId)) { $cacheKey = 'Character_getByBracketId_' . $bracketId; $retVal = Lib\Cache::Get($cacheKey); if (false === $retVal) { $retVal = null; // TODO - make order by column configurable $retVal = Character::queryReturnAll(['bracketId' => $bracketId], ['source' => 'ASC', 'name' => 'ASC']); Lib\Cache::Set($cacheKey, $retVal); } } return $retVal; }
/** * Returns an array of parent items for this object */ public function getParents() { $cacheKey = 'MalItem::getItemParents_' . $this->id; $retVal = Lib\Cache::Get($cacheKey); if (false === $retVal && $this->id) { $retVal = null; $result = Lib\Db::Query('SELECT i.* FROM mal_xref x INNER JOIN mal_items i ON i.item_id = x.mal_parent WHERE x.mal_child = :id ORDER BY x.mal_parent ASC', [':id' => $this->id]); if ($result && $result->count) { $retVal = []; while ($row = Lib\Db::Fetch($result)) { $retVal[] = new MalItem($row); } } Lib\Cache::Set($retVal, 3600); } return $retVal; }
public static function generate(array $params) { $message = null; $bracket = self::_getBracket(array_shift($params)); if ($bracket) { $cacheKey = 'Controller::Admin::Advance_bracketAdvanceTime_' . $bracket->id; $lastBracketAdvance = Lib\Cache::Get($cacheKey); if (!$lastBracketAdvance || $lastBracketAdvance + self::BRACKET_ADVANCE_DELAY < time()) { Lib\Cache::Set($cacheKey, time()); $bracket->advance(); $message = new stdClass(); $message->type = 'success'; $message->message = $bracket->name . ' has advanced to the next round'; self::_refreshCaches($bracket); } else { $message = new stdClass(); $message->type = 'error'; $delta = $lastBracketAdvance + self::BRACKET_ADVANCE_DELAY - time(); $time = Lib\Util::relativeTime(time() - $delta); $message->message = $bracket->name . ' was recently advanced. Please wait ' . $time . ' before advancing again.'; } } return self::_main($message, true); }
/** * Gets the unvoted rounds for a bracket and tier */ public static function getBracketRounds($bracketId, $tier, $group = false, $ignoreCache = false) { // If no user, check as guest $user = User::getCurrentUser(); if (!$user) { $user = new User(); $user->id = 0; } $cacheKey = 'GetBracketRounds_' . $bracketId . '_' . $tier . '_' . ($group !== false ? $group : 'all') . '_' . $user->id; $retVal = Lib\Cache::Get($cacheKey); if (false === $retVal || $ignoreCache) { $params = [':bracketId' => $bracketId, ':tier' => $tier, ':userId' => $user->id]; if (false !== $group) { $params[':group'] = $group; // Check to see how many rounds there are in the group total. If there's only one, come back and get them all $row = Lib\Db::Fetch(Lib\Db::Query('SELECT COUNT(1) AS total FROM round WHERE bracket_id = :bracketId AND round_tier = :tier AND round_group = :group', [':bracketId' => $bracketId, ':tier' => $tier, ':group' => $group])); if (is_object($row) && (int) $row->total == 1) { $retVal = self::getBracketRounds($bracketId, $tier, false, $ignoreCache); $result = null; } else { $result = Lib\Db::Query('SELECT *, (SELECT character_id FROM votes WHERE user_id = :userId AND round_id = r.round_id) AS user_vote FROM round r WHERE r.bracket_id = :bracketId AND r.round_tier = :tier AND r.round_group = :group ORDER BY r.round_order', $params); } } else { $result = Lib\Db::Query('SELECT *, (SELECT character_id FROM votes WHERE user_id = :userId AND round_id = r.round_id) AS user_vote FROM round r WHERE r.bracket_id = :bracketId AND r.round_tier = :tier ORDER BY r.round_order', $params); } if ($result && $result->count > 0) { $retVal = []; // Hashmap of characters to retrieve in the next step $characters = []; while ($row = Lib\Db::Fetch($result)) { $round = new Round($row); // If the tier is not 0, character2 is "nobody", and the number of items is not a power of two // this is a wildcard round and the user has already voted if ($row->round_tier != 0 && $row->round_character2_id == 1 && ($result->count + 1 & $result->count) != 0) { return null; } // Save off the character IDs for retrieval later $characters[$row->round_character1_id] = true; $characters[$row->round_character2_id] = true; $retVal[] = $round; } // Retrieve the characters $result = Character::query(['id' => ['in' => array_keys($characters)]]); if ($result && $result->count) { while ($row = Lib\Db::Fetch($result)) { $character = new Character($row); $characters[$character->id] = $character; } // Replace all the instances for the rounds foreach ($retVal as $round) { $round->character1 = $characters[$round->character1Id]; $round->character2 = $characters[$round->character2Id]; // Flag the character the user voted for if the voted if ($round->votedCharacterId) { if ($round->votedCharacterId == $round->character1->id) { $round->character1->voted = true; } else { $round->character2->voted = true; } } } } } Lib\Cache::Set($cacheKey, $retVal); } return $retVal; }
private static function _vote($user) { $out = new stdClass(); $out->success = false; $bracketId = Lib\Url::Post('bracketId', true); $bracket = Api\Bracket::getById($bracketId); if ($bracket) { $state = $bracket ? (int) $bracket->state : null; if ($bracket->isLocked()) { $out->message = 'Voting is closed for this round. Please refresh to see the latest round.'; } else { if ($state === BS_ELIMINATIONS || $state === BS_VOTING) { if (self::_verifyAccountAge($user, $bracket)) { // Break the votes down into an array of round/character objects $votes = []; foreach ($_POST as $key => $val) { if (strpos($key, 'round:') === 0) { $key = str_replace('round:', '', $key); $obj = new stdClass(); $obj->roundId = (int) $key; $obj->characterId = (int) $val; $votes[] = $obj; } } $count = count($votes); if ($count > 0) { $query = 'INSERT INTO `votes` (`user_id`, `vote_date`, `round_id`, `character_id`, `bracket_id`) VALUES '; $params = [':userId' => $user->id, ':date' => time(), ':bracketId' => $bracketId]; $insertCount = 0; // Only run an insert for rounds that haven't been voted on $rounds = Api\Votes::getOpenRounds($user, $votes); for ($i = 0; $i < $count; $i++) { if (!isset($rounds[$votes[$i]->roundId])) { $query .= '(:userId, :date, :round' . $i . ', :character' . $i . ', :bracketId),'; $params[':round' . $i] = $votes[$i]->roundId; $params[':character' . $i] = $votes[$i]->characterId; $insertCount++; $rounds[$votes[$i]->roundId] = true; } } if ($insertCount > 0) { $query = substr($query, 0, strlen($query) - 1); if (Lib\Db::Query($query, $params)) { $out->success = true; // I am vehemently against putting markup in the controller, but there's much refactor needed to make this right // So, that's a note that it will be changed in the future $out->message = 'Your votes were successfully submitted! <a href="/results/' . $bracket->perma . '">View Results</a>'; // Oops, I did it again... if ($bracket->externalId) { $out->message .= ' or <a href="http://redd.it/' . $bracket->externalId . '" target="_blank">discuss on reddit</a>.'; } // Clear any user related caches $round = Api\Round::getById($votes[0]->roundId); Lib\Cache::Set('GetBracketRounds_' . $bracketId . '_' . $round->tier . '_' . $round->group . '_' . $user->id, false); Lib\Cache::Set('GetBracketRounds_' . $bracketId . '_' . $round->tier . '_all_' . $user->id, false); Lib\Cache::Set('CurrentRound_' . $bracketId . '_' . $user->id, false); $bracket->getVotesForUser($user, true); } else { $out->message = 'There was an unexpected error. Please try again in a few moments.'; } } else { $out->message = 'Voting for this round has closed'; $out->code = 'closed'; } } else { $out->message = 'No votes were submitted'; } } else { $out->message = 'Your reddit account is not old enough to vote in this bracket'; } } else { $out->message = 'Voting is closed on this bracket'; $out->code = 'closed'; } } } else { $out->message = 'Invalid parameters'; } return $out; }
/** * Makes an internal API call */ private static function _internal($module, $method, $params, $cache) { global $_apiHits; $cacheKey = md5($module . '-' . $method . '-' . serialize($params)); $retVal = Lib\Cache::Get($cacheKey); if ($retVal === false || $cache == 0) { $_apiHits++; $retVal = Api\DxApi::handleRequest($module, $method, $params); Lib\Cache::Set($cacheKey, $retVal); } return $retVal; }
/** * Makes an API call to another instance of DxApi via REST */ private static function _external($module, $method, $params, $cache, $apiUri) { global $_apiHits; $qs = '/index.php?type=json&method=' . $module . '.' . $method; // Build the query string if (count($params) > 0) { foreach ($params as $key => $val) { $qs .= "&{$key}=" . urlencode($val); } } // Check to see if there is a cached version of this $cacheKey = md5($apiUri . $qs); $retVal = Cache::Get($cacheKey); if ($retVal === false || $cache == 0) { $_apiHits++; $file = file_get_contents($apiUri . $qs); $retVal = json_decode($file); // Only cache on success if ($retVal->status->ret_code == 0) { Cache::Set($cacheKey, $retVal, $cache); } } // Return the request return $retVal; }
/** * Retrieves a stashed message from caches and then clears it */ protected static function _getStashedMessage() { $retVal = null; if (self::$_user) { $cacheKey = self::_stashCacheKey(); $retVal = Lib\Cache::Get($cacheKey); Lib\Cache::Set($cacheKey, false); } return $retVal; }
/** * Advances a standard bracket tier */ private function _advanceBracket() { $rounds = Round::getCurrentRounds($this->id, true); if (count($rounds) > 1) { for ($i = 0, $count = count($rounds); $i < $count; $i += 2) { // Get the round winners $winner1 = $rounds[$i]->getWinnerId(); $winner2 = $rounds[$i + 1]->getWinnerId(); // Create the round for the next tier $newRound = new Round(); $newRound->bracketId = $this->id; $newRound->tier = $rounds[$i]->tier + 1; $newRound->group = $rounds[$i]->group; $newRound->order = $i / 2; $newRound->character1Id = $winner1; $newRound->character2Id = $winner2; $newRound->sync(); // Finalize the current tier $rounds[$i]->getVoteCount(); $rounds[$i]->final = true; $rounds[$i]->sync(); $rounds[$i + 1]->getVoteCount(); $rounds[$i + 1]->final = true; $rounds[$i + 1]->sync(); } } else { if (count($rounds) === 1) { $round = $rounds[0]; $round->getVoteCount(); $round->final = true; $round->sync(); $this->winner = $round->getWinner(); $this->winnerCharacterId = $this->winner->id; $this->state = BS_FINAL; $this->sync(); } } // Clear the results cache Lib\Cache::Set('Api:Bracket:getResults_' . $this->id, false, 1); }
/** * Gets a record from the database by the primary key */ private function _getById($id) { $retVal = null; if (self::_verifyProperties($this)) { if (is_numeric($id)) { $cacheKey = 'Lib:Dal:' . $this->_dbTable . '_getById_' . $id; $retVal = Cache::Get($cacheKey); if (!$retVal) { $query = 'SELECT `' . implode('`, `', $this->_dbMap) . '` FROM `' . $this->_dbTable . '` '; $query .= 'WHERE `' . $this->_dbMap[$this->_dbPrimaryKey] . '` = :id LIMIT 1'; $result = Db::Query($query, [':id' => $id]); if (null !== $result && $result->count === 1) { $retVal = Db::Fetch($result); Cache::Set($cacheKey, $retVal); } } if ($retVal) { $this->copyFromDbRow($retVal); } } else { throw new Exception('ID must be a number'); } } else { throw new Exception('Class must have "_dbTable", "_dbMap", and "_dbPrimaryKey" properties to use method "getById"'); } }