Flags for entries to store declined. Seating page will correctly display doubler status

This commit is contained in:
Matt Young 2024-06-21 10:44:38 -05:00
parent 30c2813ecf
commit f9e936fd07
5 changed files with 103 additions and 10 deletions

View File

@ -2,23 +2,28 @@
namespace App\Models;
use App\Exceptions\TabulationException;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
use Illuminate\Database\Eloquent\Relations\HasOneThrough;
class Entry extends Model
{
use HasFactory;
protected $guarded = [];
protected $hasCheckedScoreSheets = false;
public $final_scores_array; // Set by TabulationService
public $scoring_complete; // Set by TabulationService
public $is_doubler; // Set by DoublerService
protected $with = ['flags'];
public function student(): BelongsTo
{
return $this->belongsTo(Student::class);
@ -46,7 +51,19 @@ class Entry extends Model
}
/*
public function flags(): HasMany
{
return $this->hasMany(EntryFlag::class);
}
public function hasFlag($flag)
{
// return true if any flag in $this->flags has a flag_name of declined without making another db query if flags are loaded
return $this->flags->contains('flag_name', $flag);
}
/**
* Ensures score_sheets_count property is always available
*/
public function getScoreSheetsCountAttribute()
@ -54,6 +71,7 @@ class Entry extends Model
if (! isset($this->attributes['score_sheets_count'])) {
$this->attributes['score_sheets_count'] = $this->scoreSheets()->count();
}
return $this->attributes['score_sheets_count'];
}
}

16
app/Models/EntryFlag.php Normal file
View File

@ -0,0 +1,16 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class EntryFlag extends Model
{
// Possible flags include
// - declined: used if a doubler declines a seat in this audition. Checked by DoublerService
public function entry(): BelongsTo
{
return $this->belongsTo(Entry::class);
}
}

View File

@ -9,9 +9,13 @@ use Illuminate\Support\Facades\Cache;
class DoublerService
{
protected $doublersCacheKey = 'doublers';
protected $auditionCacheService;
protected $tabulationService;
protected $seatingService;
/**
* Create a new class instance.
*/
@ -24,12 +28,11 @@ class DoublerService
/**
* Returns a collection of students that have more than one entry
* @return \Illuminate\Database\Eloquent\Collection
*/
public function getDoublers(): \Illuminate\Database\Eloquent\Collection
{
// TODO creating or destroying an entry should refresh the doubler cache
return Cache::remember($this->doublersCacheKey, 3600, function () {
return Cache::remember($this->doublersCacheKey, 60, function () {
return Student::withCount('entries')
->with('entries')
->havingRaw('entries_count > ?', [1])
@ -37,6 +40,12 @@ class DoublerService
});
}
public function refreshDoublerCache()
{
Cache::forget($this->doublersCacheKey);
$this->getDoublers();
}
/**
* Returns an array of information about each entry for a specific doubler. Info for each entry includes
* auditionID
@ -45,25 +54,45 @@ class DoublerService
* unscored => How many entries remain to be scored in this audition
*
* @param int $studentId The ID of the doubler
* @return array
*/
public function getDoublerInfo($studentId): array
{
$doubler = $this->getDoublers()->firstWhere('id', $studentId);
// Split $doubler->entries into two arrays based on the result of hasFlag('declined')
$undecidedEntries = $doubler->entries->filter(function ($entry) {
return ! $entry->hasFlag('declined');
});
$acceptedEntry = null;
if ($undecidedEntries->count() == 1) {
$acceptedEntry = $undecidedEntries->first();
}
// TODO can I rewrite this?
// When getting a doubler we need to know
// 1) What their entries are
// 2) For each audition they're entered in, what is their rank
// 3) For each audition they're entered in, how many entries are unscored
// 4) How many are accepted on that instrument
$doubler = $this->getDoublers()->firstWhere('id',$studentId);
// 5) Status - accepted, declined or undecided
$info = [];
foreach ($doubler->entries as $entry) {
if ($entry->hasFlag('declined')) {
$status = 'declined';
} elseif ($entry === $acceptedEntry) {
$status = 'accepted';
} else {
$status = 'undecided';
}
$info[$entry->id] = [
'auditionID' => $entry->audition_id,
'auditionName' => $this->auditionCacheService->getAudition($entry->audition_id)->name,
'rank' => $this->tabulationService->entryRank($entry),
'unscored' => $this->tabulationService->remainingEntriesForAudition($entry->audition_id),
'limits' => $this->seatingService->getLimitForAudition($entry->audition_id),
'status' => $status,
];
$entry->audition = $this->auditionCacheService->getAudition($entry->audition_id);
}
@ -71,7 +100,6 @@ class DoublerService
return $info;
}
/**
* Checks if a student is a doubler based on the given student ID
*

View File

@ -0,0 +1,31 @@
<?php
use App\Models\Entry;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('entry_flags', function (Blueprint $table) {
$table->id();
$table->foreignIdFor(Entry::class)->constrained()->cascadeOnUpdate()->cascadeOnDelete();
$table->string('flag_name');
$table->unique(['entry_id', 'flag_name']);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('entry_flags');
}
};

View File

@ -8,7 +8,7 @@
<div class="flex items-start gap-x-3">
<p class="text-sm font-semibold leading-6 text-gray-900">
<a href="/tabulation/auditions/{{ $info['auditionID'] }}">
{{ $info['auditionName'] }}
{{ $info['auditionName'] }} - {{ $info['status'] }}
</a>
</p>