auditionadmin/app/Actions/Tabulation/TotalEntryScores.php

91 lines
3.6 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
{
// TODO Verify accuracy of calculations, particularly for olympic scoring
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 no score sheets
if ($scoreSheets->count() == 0) {
return;
}
if (auditionSetting('olympic_scoring' && $scoreSheets->count() > 2)) {
// under olympic scoring, drop the first and last element
$scoreSheets->shift();
$scoreSheets->pop();
}
$newTotaledScore->seating_total = $scoreSheets->avg('seating_total');
$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[] = $runningTotal / $scoreSheets->count();
}
$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 = $scoreSheets->avg('advancement_total');
$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[] = $runningTotal / $scoreSheets->count();
}
$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();
}
}