Seating page lists entries in score order
This commit is contained in:
parent
6939a09eef
commit
6f0a4ac9bc
|
|
@ -21,6 +21,7 @@ class AllJudgesCount implements CalculateEntryScore
|
|||
$this->basicValidation($mode, $entry);
|
||||
$this->areAllJudgesIn($entry);
|
||||
$this->areAllJudgesValid($entry);
|
||||
|
||||
return $this->getJudgeTotals($mode, $entry);
|
||||
}
|
||||
|
||||
|
|
@ -30,8 +31,14 @@ class AllJudgesCount implements CalculateEntryScore
|
|||
foreach ($entry->audition->judges as $judge) {
|
||||
$scores[] = $this->calculator->__invoke($mode, $entry, $judge);
|
||||
}
|
||||
for ($i = 0; $i < count($scores[0]); $i++) {
|
||||
$sums[] = $scores[0][$i] + $scores[1][$i];
|
||||
// Sum each subscore from the judges
|
||||
foreach ($scores as $score) {
|
||||
$index = 0;
|
||||
foreach ($score as $value) {
|
||||
$sums[$index] = $sums[$index] ?? 0;
|
||||
$sums[$index] += $value;
|
||||
$index++;
|
||||
}
|
||||
}
|
||||
|
||||
return $sums;
|
||||
|
|
|
|||
|
|
@ -6,5 +6,6 @@ use App\Models\Entry;
|
|||
|
||||
interface CalculateEntryScore
|
||||
{
|
||||
|
||||
public function calculate(string $mode, Entry $entry): array;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,71 @@
|
|||
<?php
|
||||
|
||||
/** @noinspection PhpUnhandledExceptionInspection */
|
||||
|
||||
namespace App\Actions\Tabulation;
|
||||
|
||||
use App\Exceptions\TabulationException;
|
||||
use App\Models\Audition;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
|
||||
class RankAuditionEntries
|
||||
{
|
||||
protected CalculateEntryScore $calculator;
|
||||
|
||||
public function __construct(CalculateEntryScore $calculator)
|
||||
{
|
||||
$this->calculator = $calculator;
|
||||
}
|
||||
|
||||
public function booo()
|
||||
{
|
||||
return 'blah';
|
||||
}
|
||||
|
||||
public function rank(string $mode, Audition $audition): Collection
|
||||
{
|
||||
$this->basicValidation($mode, $audition);
|
||||
$entries = match ($mode) {
|
||||
'seating' => $audition->entries()->forSeating()->get(),
|
||||
'advancement' => $audition->entries()->forAdvancement()->get(),
|
||||
};
|
||||
|
||||
foreach ($entries as $entry) {
|
||||
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 ($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;
|
||||
foreach ($entries as $entry) {
|
||||
$entry->rank = $rank;
|
||||
$rank++;
|
||||
}
|
||||
|
||||
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');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
namespace App\Http\Controllers\Tabulation;
|
||||
|
||||
use App\Actions\Tabulation\CalculateEntryScore;
|
||||
use App\Actions\Tabulation\RankAuditionEntries;
|
||||
use App\Exceptions\TabulationException;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Audition;
|
||||
|
|
@ -12,30 +13,31 @@ use Illuminate\Http\Request;
|
|||
class SeatAuditionController extends Controller
|
||||
{
|
||||
protected CalculateEntryScore $calc;
|
||||
protected RankAuditionEntries $ranker;
|
||||
|
||||
public function __construct(CalculateEntryScore $calc)
|
||||
public function __construct(CalculateEntryScore $calc, RankAuditionEntries $ranker)
|
||||
{
|
||||
$this->calc = $calc;
|
||||
$this->ranker = $ranker;
|
||||
}
|
||||
|
||||
public function __invoke(Request $request, Audition $audition)
|
||||
{
|
||||
$entryData = [];
|
||||
$entries = Entry::forSeating()->with('student.school')->where('audition_id', $audition->id)->get();
|
||||
#$entries = Entry::forSeating()->with('student.school')->where('audition_id', $audition->id)->get();
|
||||
$entries = $this->ranker->rank('seating', $audition);
|
||||
$entries->load('student.school');
|
||||
foreach ($entries as $entry) {
|
||||
try {
|
||||
$totalScore = $this->calc->calculate('seating', $entry);
|
||||
} catch (TabulationException $ex) {
|
||||
$totalScore[0] = $ex->getMessage();
|
||||
}
|
||||
$totalScoreColumn = $entry->score_totals[0] >= 0 ?
|
||||
$entry->score_totals[0] : $entry->score_message;
|
||||
$entryData[] = [
|
||||
'rank' => 'not implemented',
|
||||
'rank' => $entry->rank,
|
||||
'id' => $entry->id,
|
||||
'studentName' => $entry->student->full_name(),
|
||||
'schoolName' => $entry->student->school->name,
|
||||
'drawNumber' => $entry->draw_number,
|
||||
'totalScore' => $totalScore[0],
|
||||
'fullyScored' => is_numeric($totalScore[0]),
|
||||
'totalScore' => $totalScoreColumn,
|
||||
'fullyScored' => $entry->score_totals[0] >= 0,
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,45 +3,20 @@
|
|||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Actions\Tabulation\CalculateEntryScore;
|
||||
use App\Actions\Tabulation\CalculateScoreSheetTotal;
|
||||
use App\Exceptions\TabulationException;
|
||||
use App\Models\Entry;
|
||||
use App\Models\User;
|
||||
use App\Actions\Tabulation\RankAuditionEntries;
|
||||
|
||||
class TestController extends Controller
|
||||
{
|
||||
protected CalculateEntryScore $bigCalc;
|
||||
public function __construct(CalculateEntryScore $bigCalc)
|
||||
protected RankAuditionEntries $rankomatic;
|
||||
|
||||
public function __construct(RankAuditionEntries $rankomatic)
|
||||
{
|
||||
$this->bigCalc = $bigCalc;
|
||||
$this->rankomatic = $rankomatic;
|
||||
}
|
||||
|
||||
public function flashTest()
|
||||
{
|
||||
$entries = Entry::forSeating()->with('student')->where('audition_id', 17)->get();
|
||||
$rows = [];
|
||||
foreach ($entries as $entry) {
|
||||
try {
|
||||
$totalScore = $this->bigCalc->calculate('seating', $entry)[0];
|
||||
} catch (TabulationException $ex){
|
||||
$totalScore = '--';
|
||||
}
|
||||
$rows[] = [
|
||||
'name' => $entry->student->full_name(),
|
||||
'totalScore' => $totalScore,
|
||||
];
|
||||
}
|
||||
$scoreCalc = new CalculateScoreSheetTotal;
|
||||
$bam = $scoreCalc('seating', Entry::find(916), User::find(65))[0];
|
||||
// try {
|
||||
// $test = $this->bigCalc->calculate('seating', Entry::find(1061))[0];
|
||||
// } catch (TabulationException $ex) {
|
||||
// dd($ex);
|
||||
// }
|
||||
|
||||
|
||||
|
||||
|
||||
return view('test', compact('rows', 'bam'));
|
||||
dd($this->rankomatic->booo());
|
||||
return view('test');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
|||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||
use Illuminate\Database\Eloquent\Relations\HasOneThrough;
|
||||
use Staudenmeir\BelongsToThrough;
|
||||
use App\Models\ScoreSheet;
|
||||
|
||||
class Entry extends Model
|
||||
|
|
@ -38,6 +39,7 @@ class Entry extends Model
|
|||
return $this->belongsTo(Audition::class);
|
||||
}
|
||||
|
||||
|
||||
public function school(): HasOneThrough
|
||||
{
|
||||
return $this->hasOneThrough(
|
||||
|
|
|
|||
|
|
@ -21,4 +21,9 @@ class Event extends Model
|
|||
return $this->hasMany(Ensemble::class)
|
||||
->orderBy('rank');
|
||||
}
|
||||
|
||||
public function entries()
|
||||
{
|
||||
return $this->hasManyThrough(Entry::class, Audition::class);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,9 @@
|
|||
|
||||
namespace App\Providers;
|
||||
|
||||
use App\Actions\Tabulation\AllJudgesCount;
|
||||
use App\Actions\Tabulation\CalculateEntryScore;
|
||||
use App\Actions\Tabulation\CalculateScoreSheetTotal;
|
||||
use App\Models\Audition;
|
||||
use App\Models\Entry;
|
||||
use App\Models\Room;
|
||||
|
|
@ -40,9 +43,9 @@ class AppServiceProvider extends ServiceProvider
|
|||
*/
|
||||
public function register(): void
|
||||
{
|
||||
// $this->app->singleton(DrawService::class, function () {
|
||||
// return new DrawService();
|
||||
// });
|
||||
$this->app->singleton(DrawService::class, function () {
|
||||
return new DrawService();
|
||||
});
|
||||
//
|
||||
// $this->app->singleton(AuditionService::class, function () {
|
||||
// return new AuditionService();
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
"laravel/pail": "^1.1",
|
||||
"laravel/tinker": "^2.9",
|
||||
"predis/predis": "^2.2",
|
||||
"staudenmeir/belongs-to-through": "^2.5",
|
||||
"symfony/http-client": "^7.1",
|
||||
"symfony/mailgun-mailer": "^7.1"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "7aab57ef52f0152526434decd76ef1e1",
|
||||
"content-hash": "cd8959ab9db27e12c6fce8cf87c52d90",
|
||||
"packages": [
|
||||
{
|
||||
"name": "bacon/bacon-qr-code",
|
||||
|
|
@ -3601,6 +3601,71 @@
|
|||
],
|
||||
"time": "2024-04-27T21:32:50+00:00"
|
||||
},
|
||||
{
|
||||
"name": "staudenmeir/belongs-to-through",
|
||||
"version": "v2.16",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/staudenmeir/belongs-to-through.git",
|
||||
"reference": "79667db6660fa0065b24415bab29a5f85a0128c7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/staudenmeir/belongs-to-through/zipball/79667db6660fa0065b24415bab29a5f85a0128c7",
|
||||
"reference": "79667db6660fa0065b24415bab29a5f85a0128c7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"illuminate/database": "^11.0",
|
||||
"php": "^8.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"barryvdh/laravel-ide-helper": "^3.0",
|
||||
"orchestra/testbench": "^9.0",
|
||||
"phpstan/phpstan": "^1.10",
|
||||
"phpunit/phpunit": "^10.5"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Staudenmeir\\BelongsToThrough\\IdeHelperServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Znck\\Eloquent\\": "src/",
|
||||
"Staudenmeir\\BelongsToThrough\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Rahul Kadyan",
|
||||
"email": "hi@znck.me"
|
||||
},
|
||||
{
|
||||
"name": "Jonas Staudenmeir",
|
||||
"email": "mail@jonas-staudenmeir.de"
|
||||
}
|
||||
],
|
||||
"description": "Laravel Eloquent BelongsToThrough relationships",
|
||||
"support": {
|
||||
"issues": "https://github.com/staudenmeir/belongs-to-through/issues",
|
||||
"source": "https://github.com/staudenmeir/belongs-to-through/tree/v2.16"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://paypal.me/JonasStaudenmeir",
|
||||
"type": "custom"
|
||||
}
|
||||
],
|
||||
"time": "2024-03-09T09:53:11+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/clock",
|
||||
"version": "v7.0.7",
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
@php use App\Enums\AuditionFlags;use App\Models\Audition;use App\Models\AuditionFlag;use App\Models\Entry;use App\Models\User; @endphp
|
||||
@php use App\Enums\AuditionFlags;use App\Models\Audition;use App\Models\AuditionFlag;use App\Models\Entry;use App\Models\Event;use App\Models\User; @endphp
|
||||
@php @endphp
|
||||
@inject('scoreservice','App\Services\ScoreService');
|
||||
@inject('auditionService','App\Services\AuditionService');
|
||||
|
|
@ -7,8 +7,9 @@
|
|||
@inject('drawService', 'App\Services\DrawService')
|
||||
<x-layout.app>
|
||||
<x-slot:page_title>Test Page - {{ $bam ?? '' }}</x-slot:page_title>
|
||||
@foreach($rows as $row)
|
||||
{{ $row['name'] }} - {{ $row['totalScore'] }}<hr>
|
||||
@endforeach
|
||||
|
||||
@foreach(Event::first()->entries->groupBy('student_id') as $student)
|
||||
Name: {{ $student[0]->student->full_name() }} <br>
|
||||
Entry Count: {{ $student->count() }}<hr>
|
||||
@endforeach
|
||||
</x-layout.app>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
|
||||
use App\Actions\Tabulation\AllJudgesCount;
|
||||
use App\Actions\Tabulation\RankAuditionEntries;
|
||||
use App\Exceptions\TabulationException;
|
||||
use App\Models\Audition;
|
||||
use App\Models\Entry;
|
||||
use App\Models\Room;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
it('throws an exception if an invalid mode is specified', function () {
|
||||
$ranker = new RankAuditionEntries(new AllJudgesCount());
|
||||
$ranker->rank('wrong', Audition::factory()->create());
|
||||
})->throws(TabulationException::class, 'Mode must be seating or advancement');
|
||||
it('throws an exception if an invalid audition is provided', function () {
|
||||
// Arrange
|
||||
$ranker = new RankAuditionEntries(new AllJudgesCount());
|
||||
// Act & Assert
|
||||
$ranker->rank('seating', Audition::factory()->make());
|
||||
})->throws(TabulationException::class, 'Invalid audition provided');
|
||||
it('includes all entries of the given mode in the return', function () {
|
||||
$audition = Audition::factory()->create();
|
||||
$entries = Entry::factory()->seatingOnly()->count(10)->create(['audition_id' => $audition->id]);
|
||||
$otherEntries = Entry::factory()->advanceOnly()->count(10)->create(['audition_id' => $audition->id]);
|
||||
$ranker = new RankAuditionEntries(new AllJudgesCount());
|
||||
// Act
|
||||
$return = $ranker->rank('seating', $audition);
|
||||
// Assert
|
||||
foreach ($entries as $entry) {
|
||||
expect($return->pluck('id')->toArray())->toContain($entry->id);
|
||||
}
|
||||
foreach ($otherEntries as $entry) {
|
||||
expect($return->pluck('id')->toArray())->not()->toContain($entry->id);
|
||||
}
|
||||
});
|
||||
it('places entries in the proper order', function () {
|
||||
// Arrange
|
||||
loadSampleAudition();
|
||||
$judge = User::factory()->create();
|
||||
Room::find(1000)->addJudge($judge);
|
||||
$entries = Entry::factory()->count(5)->create(['audition_id' => 1000]);
|
||||
$scoreArray1 = [1001 => 90, 1002 => 90, 1003 => 90, 1004 => 90, 1005 => 90];
|
||||
$scoreArray2 = [1001 => 60, 1002 => 60, 1003 => 60, 1004 => 60, 1005 => 60];
|
||||
$scoreArray3 = [1001 => 80, 1002 => 80, 1003 => 80, 1004 => 80, 1005 => 80];
|
||||
$scoreArray4 = [1001 => 100, 1002 => 100, 1003 => 100, 1004 => 100, 1005 => 100];
|
||||
$scoreArray5 = [1001 => 70, 1002 => 70, 1003 => 70, 1004 => 70, 1005 => 70];
|
||||
enterScore($judge, $entries[0], $scoreArray1);
|
||||
enterScore($judge, $entries[1], $scoreArray2);
|
||||
enterScore($judge, $entries[2], $scoreArray3);
|
||||
enterScore($judge, $entries[3], $scoreArray4);
|
||||
enterScore($judge, $entries[4], $scoreArray5);
|
||||
$ranker = new RankAuditionEntries(new AllJudgesCount());
|
||||
$expectedOrder = [4, 1, 3, 5, 2];
|
||||
// Act
|
||||
$return = $ranker->rank('seating', Audition::find(1000));
|
||||
// Assert
|
||||
expect($return->pluck('id')->toArray())->toBe($expectedOrder);
|
||||
});
|
||||
Loading…
Reference in New Issue