I'm working on a website for a simracing hotlapping competition. Participants can submit an unlimited amount of lap times for a specific round in a specific season, and admins can either approve or deny these lap times. The fastest approved lap time for each participant is shown on that round's leaderboard.
In case it's relevant, I'm using this package to generate Snowflake IDs instead of incremental IDs or GUIDs.
I'm using a pretty simple enum for the lap time status;
enum LapTimeStatus: int
{
case SUBMITTED = 0;
case APPROVED = 1;
case DENIED = 2;
}
In the LapTime
model I cast this field to the enum, and I've of course added the relationship to the Round
model;
class LapTime extends Model
{
use HasFactory, Snowflake;
protected $casts = [
'status' => LapTimeStatus::class,
];
public function round(): BelongsTo
{
return $this->belongsTo(Round::class);
}
}
In the Round
model, I've set up the inverse of the relationship, as well as a method to fetch the lap times for the aforementioned leaderboard;
class Round extends Model
{
use HasFactory, Snowflake;
public function times(): HasMany
{
return $this->hasMany(LapTime::class);
}
public function timesForLeaderboard(): array
{
$times = $this->times()
->with('user')
->orderBy('lap_time')
->where('status', LapTimeStatus::APPROVED)
->get();
return $times->unique('user_id')->values()->toArray();
}
}
timesForLeaderboard
gets all approved times for that round, orders them by laptime (laptimes are stored in milliseconds for easy sorting), and makes sure only one lap time for each user is selected.
However, the ->where('status', LapTimeStatus::APPROVED)
line is causing issues. It works perfectly fine for the first season, however for whatever reason this line returns 0 models for each round, despite all of them having at least one approved lap time. I've been able to fix it by changing the line to ->where('status', (string) LapTimeStatus::APPROVED->value)
, but
- this seems like a band aid fix for a deeper issue, as it behaves correctly elsewhere and
- I'd have to make this change in a few other places, which I'd like to avoid.
Any idea what could be causing this inconsistent behaviour despite near-identical circumstances?
As requested, here's the DB schema
And as request as well, the LapTime
table migration;
return new class extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('lap_times', function (Blueprint $table) {
$table->unsignedBigInteger('id')->primary();
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
$table->foreignId('round_id')->constrained()->cascadeOnDelete();
$table->unsignedBigInteger('lap_time');
$table->string('video_url');
$table->unsignedInteger('status')->default(LapTimeStatus::SUBMITTED->value);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('lap_times');
}
};