diff --git a/src/Service/DataExportService.php b/src/Service/DataExportService.php index 29eeb0e..2b97159 100644 --- a/src/Service/DataExportService.php +++ b/src/Service/DataExportService.php @@ -223,7 +223,7 @@ class DataExportService } } - /** Raw crosstab: one row per candidate, one column per question, cell = the answer text they gave. */ + /** Raw crosstab: one row per candidate, one column per question, cell = the answer text they gave (bold when correct). */ private function fillRawAnswersSheet(Worksheet $sheet, Quiz $quiz): void { /** @var list $questions */ @@ -240,11 +240,14 @@ class DataExportService /** @var array> $answersByCandidateAndQuestion */ $answersByCandidateAndQuestion = []; + /** @var array> $correctnessByCandidateAndQuestion */ + $correctnessByCandidateAndQuestion = []; foreach ($questions as $question) { foreach ($question->answers as $answer) { foreach ($answer->givenAnswers as $givenAnswer) { $candidateId = $givenAnswer->candidate->id->toString(); $answersByCandidateAndQuestion[$candidateId][$question->id->toString()] = $answer->text; + $correctnessByCandidateAndQuestion[$candidateId][$question->id->toString()] = $answer->isRightAnswer; } } } @@ -252,13 +255,22 @@ class DataExportService $row = 2; foreach ($quiz->candidateData as $quizCandidate) { $candidate = $quizCandidate->candidate; + $candidateId = $candidate->id->toString(); $line = [$candidate->name]; foreach ($questions as $question) { - $line[] = $answersByCandidateAndQuestion[$candidate->id->toString()][$question->id->toString()] ?? ''; + $line[] = $answersByCandidateAndQuestion[$candidateId][$question->id->toString()] ?? ''; } $sheet->fromArray($line, null, 'A'.$row); + + foreach ($questions as $columnIndex => $question) { + if ($correctnessByCandidateAndQuestion[$candidateId][$question->id->toString()] ?? false) { + $column = Coordinate::stringFromColumnIndex(2 + $columnIndex); + $sheet->getStyle($column.$row)->getFont()->setBold(true); + } + } + ++$row; } diff --git a/tests/Service/DataExportServiceTest.php b/tests/Service/DataExportServiceTest.php index 5b3efb9..66815f5 100644 --- a/tests/Service/DataExportServiceTest.php +++ b/tests/Service/DataExportServiceTest.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace Tvdt\Tests\Service; +use PhpOffice\PhpSpreadsheet\Cell\Coordinate; use PhpOffice\PhpSpreadsheet\Reader; use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; use PHPUnit\Framework\Attributes\CoversClass; @@ -201,6 +202,50 @@ final class DataExportServiceTest extends DatabaseTestCase $this->assertSame('Man', $claudiaRow[$questionColumnIndex]); } + public function testRawAnswersSheetBoldsCorrectAnswersOnly(): void + { + $season = $this->getSeasonByCode('krtek'); + $quiz = $this->entityManager->getRepository(Quiz::class)->findOneBy(['name' => 'Quiz 1', 'season' => $season]); + $this->assertInstanceOf(Quiz::class, $quiz); + + /** @var Question $firstQuestion */ + $firstQuestion = $quiz->questions->first(); + $correctAnswer = $firstQuestion->answers->filter(static fn (Answer $answer): bool => $answer->isRightAnswer)->first(); + $wrongAnswer = $firstQuestion->answers->filter(static fn (Answer $answer): bool => !$answer->isRightAnswer)->first(); + $this->assertInstanceOf(Answer::class, $correctAnswer); + $this->assertInstanceOf(Answer::class, $wrongAnswer); + + $candidateWithCorrectAnswer = $this->getCandidateBySeasonAndName($season, 'Claudia'); + $candidateWithWrongAnswer = $this->getCandidateBySeasonAndName($season, 'Eelco'); + + $this->quizCandidateRepository->createIfNotExist($quiz, $candidateWithCorrectAnswer); + $this->quizCandidateRepository->createIfNotExist($quiz, $candidateWithWrongAnswer); + + $this->entityManager->persist(new GivenAnswer($candidateWithCorrectAnswer, $quiz, $correctAnswer)); + $this->entityManager->persist(new GivenAnswer($candidateWithWrongAnswer, $quiz, $wrongAnswer)); + $this->entityManager->flush(); + + $zip = $this->openZip($this->getUserByEmail('user2@example.org')); + $quizContent = $zip->getFromName('krtek-Krtek-Weekend/Quiz-1.xlsx'); + $this->assertIsString($quizContent); + $zip->close(); + + $sheet = $this->loadSheet($quizContent, 'Raw answers'); + $rows = $sheet->toArray(); + $header = $rows[0]; + + $questionColumnIndex = array_search($firstQuestion->question, $header, true); + $this->assertIsInt($questionColumnIndex); + $column = Coordinate::stringFromColumnIndex($questionColumnIndex + 1); + + $candidateNames = array_column(\array_slice($rows, 1), 0); + $correctRowNumber = 2 + array_search('Claudia', $candidateNames, true); + $wrongRowNumber = 2 + array_search('Eelco', $candidateNames, true); + + $this->assertTrue($sheet->getStyle($column.$correctRowNumber)->getFont()->getBold(), 'Expected the correct answer to be bold'); + $this->assertFalse($sheet->getStyle($column.$wrongRowNumber)->getFont()->getBold(), 'Expected the wrong answer to not be bold'); + } + public function testQuizInfoSheetShowsDropoutsFinalizationAndDisabledQuestions(): void { $season = $this->getSeasonByCode('krtek');