From 0e76202cde6af51907f10900bd9d7185588dcca4 Mon Sep 17 00:00:00 2001 From: Tobias Werth Date: Sat, 6 Sep 2025 12:38:04 +0200 Subject: [PATCH] Fix scoreboard update after rejudging. Previous buggy flow was something like: - fetch all submissions that for this team/contest/problem combination - that are valid - and have a valid judging The idea of https://github.com/DOMjudge/domjudge/blob/95df1de7bce91f43600cfcb8760ea85762936614/webapp/src/Service/ScoreboardService.php#L240 was that this would filter the OneToMany collection down to only valid judgings. This is also what happens on the database side. However, on the doctrine side, the entity manager keeps a cache, and if the submission is already in the cache with the full collection of valid and invalid judgings, it will only merged with new data from the database query, no data (i.e. no judgings) will magically disappear. In order to fix this, we explicitly filter on the PHP side. An alternative would be to add a new `OneToMany` mapping with a `where` on it and use that. Fixes https://github.com/DOMjudge/domjudge/issues/2883 --- webapp/src/Entity/Submission.php | 20 ++++++++++++++++++++ webapp/src/Service/ScoreboardService.php | 4 ++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/webapp/src/Entity/Submission.php b/webapp/src/Entity/Submission.php index 74f481c4d0..66ab393d7b 100644 --- a/webapp/src/Entity/Submission.php +++ b/webapp/src/Entity/Submission.php @@ -359,6 +359,16 @@ public function getJudgings(): Collection return $this->judgings; } + public function getValidJudging(): ?Judging + { + foreach ($this->judgings as $j) { + if ($j->getValid()) { + return $j; + } + } + return null; + } + public function setLanguage(?Language $language = null): Submission { $this->language = $language; @@ -537,6 +547,16 @@ public function getExternalJudgements(): Collection return $this->external_judgements; } + public function getValidExternalJudgement(): ?ExternalJudgement + { + foreach ($this->external_judgements as $ej) { + if ($ej->getValid()) { + return $ej; + } + } + return null; + } + public function setFileForApi(?FileWithName $fileForApi = null): Submission { $this->fileForApi = $fileForApi; diff --git a/webapp/src/Service/ScoreboardService.php b/webapp/src/Service/ScoreboardService.php index 21d8b60178..db9e99ecd7 100644 --- a/webapp/src/Service/ScoreboardService.php +++ b/webapp/src/Service/ScoreboardService.php @@ -262,9 +262,9 @@ public function calculateScoreRow( foreach ($submissions as $submission) { /** @var Judging|ExternalJudgement|null $judging */ if ($useExternalJudgements) { - $judging = $submission->getExternalJudgements()->first() ?: null; + $judging = $submission->getValidExternalJudgement(); } else { - $judging = $submission->getJudgings()->first() ?: null; + $judging = $submission->getValidJudging(); } // three things will happen in the loop in this order: