auditionadmin/app/Actions/Tabulation/TotalEntryScores.php

93 lines
3.7 KiB
PHP

<?php
namespace App\Actions\Tabulation;
use App\Models\BonusScore;
use App\Models\Entry;
use App\Models\EntryTotalScore;
use App\Models\ScoreSheet;
/**
* Handles the calculation of a total score for an entry, including seating and advancement scores,
* based on scoring sheets and subscores defined in the audition's scoring guide.
*/
class TotalEntryScores
{
public function __construct()
{
}
public function __invoke(Entry $entry, bool $force_recalculation = false): void
{
if ($force_recalculation) {
EntryTotalScore::where('entry_id', $entry->id)->delete();
}
// bail out if a total score is already calculated
if (EntryTotalScore::where('entry_id', $entry->id)->count() > 0) {
return;
}
$requiredSubscores = $entry->audition->scoringGuide->subscores;
$newTotaledScore = EntryTotalScore::make();
$newTotaledScore->entry_id = $entry->id;
// deal with seating scores
// TODO: Consider a rewrite to pull the scoreSheets from the entry model so they may be preloaded
$scoreSheets = ScoreSheet::where('entry_id', $entry->id)->orderBy('seating_total', 'desc')->get();
// bail out if there are not enough score sheets
$assignedJudges = $entry->audition->judges()->count();
if ($scoreSheets->count() == 0 || $scoreSheets->count() < $assignedJudges) {
return;
}
if (auditionSetting('olympic_scoring') && $scoreSheets->count() > 2) {
// under olympic scoring, drop the first and last element
$scoreSheets->shift();
$scoreSheets->pop();
}
$newTotaledScore->seating_total = round($scoreSheets->avg('seating_total'), 6);
$seatingSubscores = $requiredSubscores
->filter(fn ($subscore) => $subscore->for_seating == true)
->sortBy('tiebreak_order');
$total_seating_subscores = [];
foreach ($seatingSubscores as $subscore) {
$runningTotal = 0;
foreach ($scoreSheets as $scoreSheet) {
$runningTotal += $scoreSheet->subscores[$subscore->id]['score'];
}
$total_seating_subscores[] = round($runningTotal / $scoreSheets->count(), 4);
}
$newTotaledScore->seating_subscore_totals = $total_seating_subscores;
// deal with advancement scores
$scoreSheets = ScoreSheet::where('entry_id', $entry->id)->orderBy('advancement_total', 'desc')->get();
if (auditionSetting('olympic_scoring') && $scoreSheets->count() > 2) {
// under olympic scoring, drop the first and last element
$scoreSheets->shift();
$scoreSheets->pop();
}
$newTotaledScore->advancement_total = round($scoreSheets->avg('advancement_total'), 6);
$advancement_subscores = $requiredSubscores
->filter(fn ($subscore) => $subscore->for_advance == true)
->sortBy('tiebreak_order');
$total_advancement_subscores = [];
foreach ($advancement_subscores as $subscore) {
$runningTotal = 0;
foreach ($scoreSheets as $scoreSheet) {
$runningTotal += $scoreSheet->subscores[$subscore->id]['score'];
}
$total_advancement_subscores[] = round($runningTotal / $scoreSheets->count(), 4);
}
$newTotaledScore->advancement_subscore_totals = $total_advancement_subscores;
// pull in bonus scores
$bonusScores = BonusScore::where('entry_id', $entry->id)
->selectRaw('SUM(score) as total')
->value('total');
$newTotaledScore->bonus_total = $bonusScores;
$newTotaledScore->save();
}
}