calculator = $calculator; } public function rank(string $mode, Audition $audition): Collection { $cacheKey = 'audition'.$audition->id.$mode; return Cache::remember($cacheKey, 300, function () use ($mode, $audition) { return $this->calculateRank($mode, $audition); }); } /** * For a given audition, return a collection of entries ranked by total score. Each entry will have a * property rank that either is their rank or a flag reflecting no-show, declined, or failed-prelim status * * @throws TabulationException */ public function calculateRank(string $mode, Audition $audition): Collection { $this->basicValidation($mode, $audition); $entries = match ($mode) { 'seating' => $audition->entries()->forSeating()->with('scoreSheets')->withCount('bonusScores')->get(), 'advancement' => $audition->entries()->forAdvancement()->with('scoreSheets')->get(), }; foreach ($entries as $entry) { $entry->setRelation('audition', $audition); try { $entry->score_totals = $this->calculator->calculate($mode, $entry); } catch (TabulationException $ex) { $entry->score_totals = [-1]; $entry->score_message = $ex->getMessage(); } } // Sort entries based on their total score, then by subscores in tiebreak order $entries = $entries->sort(function ($a, $b) { for ($i = 0; $i < count($a->score_totals); $i++) { if (! array_key_exists($i, $a->score_totals)) { return -1; } if (! array_key_exists($i, $b->score_totals)) { return -1; } if ($a->score_totals[$i] > $b->score_totals[$i]) { return -1; } elseif ($a->score_totals[$i] < $b->score_totals[$i]) { return 1; } } return 0; }); $rank = 1; $rawRank = 1; foreach ($entries as $entry) { $entry->rank = $rank; $entry->raw_rank = $rawRank; // We don't really get a rank for seating if we have certain flags if ($mode === 'seating') { if ($entry->hasFlag('failed_prelim')) { $entry->rank = 'Failed Prelim'; } elseif ($entry->hasFlag('declined')) { $entry->rank = 'Declined'; } elseif ($entry->hasFlag('no_show')) { $entry->rank = 'No Show'; } } if (is_numeric($entry->rank)) { $rank++; } $rawRank++; } return $entries; } protected function basicValidation($mode, Audition $audition): void { if ($mode !== 'seating' && $mode !== 'advancement') { throw new TabulationException('Mode must be seating or advancement'); } if (! $audition->exists()) { throw new TabulationException('Invalid audition provided'); } } }