Rewrite RankAuditionEntries action and use it in the new seat audition form controller.
This commit is contained in:
parent
b8ce2bc6db
commit
349da644b7
|
|
@ -4,105 +4,82 @@
|
|||
|
||||
namespace App\Actions\Tabulation;
|
||||
|
||||
use App\Exceptions\TabulationException;
|
||||
use App\Exceptions\AuditionAdminException;
|
||||
use App\Models\Audition;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
use function is_numeric;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class RankAuditionEntries
|
||||
{
|
||||
protected CalculateEntryScore $calculator;
|
||||
|
||||
public function __construct(CalculateEntryScore $calculator)
|
||||
{
|
||||
$this->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
|
||||
* Get ranked entries for the provided audition for either seating or advancement.
|
||||
*
|
||||
* @throws TabulationException
|
||||
* If the rank_type is seating, the ranked entries are returned in descending order of seating total.
|
||||
* If the rank_type is advancement, the ranked entries are returned in descending order of advancement total.
|
||||
*
|
||||
* The ranked entries are returned as a Collection of Entry objects.
|
||||
*
|
||||
* @param string $rank_type advancement|seating
|
||||
* @return Collection|void
|
||||
*
|
||||
* @throws AuditionAdminException
|
||||
*/
|
||||
public function calculateRank(string $mode, Audition $audition): Collection
|
||||
public function __invoke(Audition $audition, string $rank_type)
|
||||
{
|
||||
$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;
|
||||
}
|
||||
if ($rank_type !== 'seating' && $rank_type !== 'advancement') {
|
||||
throw new AuditionAdminException('Invalid rank type: '.$rank_type.' (must be seating or advancement)');
|
||||
}
|
||||
|
||||
return 0;
|
||||
$cache_duration = 15;
|
||||
|
||||
if ($rank_type === 'seating') {
|
||||
return cache()->remember('rank_seating_'.$audition->id, $cache_duration, function () use ($audition) {
|
||||
return $this->get_seating_ranks($audition);
|
||||
});
|
||||
$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
|
||||
private function get_seating_ranks(Audition $audition): Collection
|
||||
{
|
||||
if ($mode !== 'seating' && $mode !== 'advancement') {
|
||||
throw new TabulationException('Mode must be seating or advancement');
|
||||
}
|
||||
if (! $audition->exists()) {
|
||||
throw new TabulationException('Invalid audition provided');
|
||||
return $audition->entries()
|
||||
->whereHas('totalScore')
|
||||
->with('totalScore')
|
||||
->with('student.school')
|
||||
->join('entry_total_scores', 'entries.id', '=', 'entry_total_scores.entry_id')
|
||||
->orderBy('entry_total_scores.seating_total', 'desc')
|
||||
->orderByRaw('COALESCE(JSON_EXTRACT(entry_total_scores.seating_subscore_totals, "$[0]"), -999999) DESC')
|
||||
->orderByRaw('COALESCE(JSON_EXTRACT(entry_total_scores.seating_subscore_totals, "$[1]"), -999999) DESC')
|
||||
->orderByRaw('COALESCE(JSON_EXTRACT(entry_total_scores.seating_subscore_totals, "$[2]"), -999999) DESC')
|
||||
->orderByRaw('COALESCE(JSON_EXTRACT(entry_total_scores.seating_subscore_totals, "$[3]"), -999999) DESC')
|
||||
->orderByRaw('COALESCE(JSON_EXTRACT(entry_total_scores.seating_subscore_totals, "$[4]"), -999999) DESC')
|
||||
->orderByRaw('COALESCE(JSON_EXTRACT(entry_total_scores.seating_subscore_totals, "$[5]"), -999999) DESC')
|
||||
->orderByRaw('COALESCE(JSON_EXTRACT(entry_total_scores.seating_subscore_totals, "$[6]"), -999999) DESC')
|
||||
->orderByRaw('COALESCE(JSON_EXTRACT(entry_total_scores.seating_subscore_totals, "$[7]"), -999999) DESC')
|
||||
->orderByRaw('COALESCE(JSON_EXTRACT(entry_total_scores.seating_subscore_totals, "$[8]"), -999999) DESC')
|
||||
->orderByRaw('COALESCE(JSON_EXTRACT(entry_total_scores.seating_subscore_totals, "$[9]"), -999999) DESC')
|
||||
->select('entries.*')
|
||||
->get();
|
||||
}
|
||||
|
||||
private function get_advancement_ranks(Audition $audition): Collection
|
||||
{
|
||||
return $audition->entries()
|
||||
->whereHas('totalScore')
|
||||
->with('totalScore')
|
||||
->with('student.school')
|
||||
->join('entry_total_scores', 'entries.id', '=', 'entry_total_scores.entry_id')
|
||||
->orderBy('entry_total_scores.advancement_total', 'desc')
|
||||
->orderByRaw('COALESCE(JSON_EXTRACT(entry_total_scores.advancement_subscore_totals, "$[0]"), -999999) DESC')
|
||||
->orderByRaw('COALESCE(JSON_EXTRACT(entry_total_scores.advancement_subscore_totals, "$[1]"), -999999) DESC')
|
||||
->orderByRaw('COALESCE(JSON_EXTRACT(entry_total_scores.advancement_subscore_totals, "$[2]"), -999999) DESC')
|
||||
->orderByRaw('COALESCE(JSON_EXTRACT(entry_total_scores.advancement_subscore_totals, "$[3]"), -999999) DESC')
|
||||
->orderByRaw('COALESCE(JSON_EXTRACT(entry_total_scores.advancement_subscore_totals, "$[4]"), -999999) DESC')
|
||||
->orderByRaw('COALESCE(JSON_EXTRACT(entry_total_scores.advancement_subscore_totals, "$[5]"), -999999) DESC')
|
||||
->orderByRaw('COALESCE(JSON_EXTRACT(entry_total_scores.advancement_subscore_totals, "$[6]"), -999999) DESC')
|
||||
->orderByRaw('COALESCE(JSON_EXTRACT(entry_total_scores.advancement_subscore_totals, "$[7]"), -999999) DESC')
|
||||
->orderByRaw('COALESCE(JSON_EXTRACT(entry_total_scores.advancement_subscore_totals, "$[8]"), -999999) DESC')
|
||||
->orderByRaw('COALESCE(JSON_EXTRACT(entry_total_scores.advancement_subscore_totals, "$[9]"), -999999) DESC')
|
||||
->select('entries.*')
|
||||
->get();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
namespace App\Http\Controllers\Tabulation;
|
||||
|
||||
use App\Actions\Tabulation\GetAuditionSeats;
|
||||
use App\Actions\Tabulation\RankAuditionEntries;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Audition;
|
||||
use Illuminate\Http\Request;
|
||||
|
|
@ -11,25 +12,9 @@ class SeatAuditionFormController extends Controller
|
|||
{
|
||||
public function __invoke(Request $request, Audition $audition)
|
||||
{
|
||||
$ranker = app(RankAuditionEntries::class);
|
||||
// Get scored entries in order
|
||||
$scored_entries = $audition->entries()
|
||||
->whereHas('totalScore')
|
||||
->with('totalScore')
|
||||
->with('student.school')
|
||||
->join('entry_total_scores', 'entries.id', '=', 'entry_total_scores.entry_id')
|
||||
->orderBy('entry_total_scores.seating_total', 'desc')
|
||||
->orderByRaw('COALESCE(JSON_EXTRACT(entry_total_scores.seating_subscore_totals, "$[0]"), -999999) DESC')
|
||||
->orderByRaw('COALESCE(JSON_EXTRACT(entry_total_scores.seating_subscore_totals, "$[1]"), -999999) DESC')
|
||||
->orderByRaw('COALESCE(JSON_EXTRACT(entry_total_scores.seating_subscore_totals, "$[2]"), -999999) DESC')
|
||||
->orderByRaw('COALESCE(JSON_EXTRACT(entry_total_scores.seating_subscore_totals, "$[3]"), -999999) DESC')
|
||||
->orderByRaw('COALESCE(JSON_EXTRACT(entry_total_scores.seating_subscore_totals, "$[4]"), -999999) DESC')
|
||||
->orderByRaw('COALESCE(JSON_EXTRACT(entry_total_scores.seating_subscore_totals, "$[5]"), -999999) DESC')
|
||||
->orderByRaw('COALESCE(JSON_EXTRACT(entry_total_scores.seating_subscore_totals, "$[6]"), -999999) DESC')
|
||||
->orderByRaw('COALESCE(JSON_EXTRACT(entry_total_scores.seating_subscore_totals, "$[7]"), -999999) DESC')
|
||||
->orderByRaw('COALESCE(JSON_EXTRACT(entry_total_scores.seating_subscore_totals, "$[8]"), -999999) DESC')
|
||||
->orderByRaw('COALESCE(JSON_EXTRACT(entry_total_scores.seating_subscore_totals, "$[9]"), -999999) DESC')
|
||||
->select('entries.*')
|
||||
->get();
|
||||
$scored_entries = $ranker($audition, 'seating');
|
||||
|
||||
// Get unscored entries sorted by draw number
|
||||
$unscored_entries = $audition->entries()
|
||||
|
|
|
|||
Loading…
Reference in New Issue