From 938456087abd4c2031b439388fab838b0909df22 Mon Sep 17 00:00:00 2001 From: Marijn Doeve Date: Fri, 10 Jul 2026 19:30:37 +0200 Subject: [PATCH] fix: support more than 25 columns in data export sheets (#205) range('A', ...) silently truncates its end argument to one byte once a sheet needs a column past 'Z' (e.g. 26+ questions), triggering a PHP warning and mis-sizing columns. Replace it with a helper that walks column indexes via Coordinate::stringFromColumnIndex, which handles multi-letter columns correctly. Fixes PHP-SYMFONY-3Z --- src/Service/DataExportService.php | 22 +++++++-- ...DataExportServiceRawAnswersColumnsTest.php | 47 +++++++++++++++++++ 2 files changed, 66 insertions(+), 3 deletions(-) create mode 100644 tests/Service/DataExportServiceRawAnswersColumnsTest.php diff --git a/src/Service/DataExportService.php b/src/Service/DataExportService.php index 396084a..29eeb0e 100644 --- a/src/Service/DataExportService.php +++ b/src/Service/DataExportService.php @@ -263,7 +263,7 @@ class DataExportService } $lastColumnIndex = 1 + \count($questions); - foreach (range('A', Coordinate::stringFromColumnIndex($lastColumnIndex)) as $column) { + foreach ($this->columnLetters($lastColumnIndex) as $column) { $sheet->getColumnDimension($column)->setWidth(30); $sheet->getStyle($column.':'.$column)->getAlignment()->setWrapText(true); } @@ -297,7 +297,7 @@ class DataExportService ++$row; } - foreach (range('A', Coordinate::stringFromColumnIndex(2 + \count($candidates))) as $column) { + foreach ($this->columnLetters(2 + \count($candidates)) as $column) { $sheet->getColumnDimension($column)->setAutoSize(true); } } @@ -405,7 +405,7 @@ class DataExportService } $lastColumnIndex = $answerStartColumnIndex + max(1, 2 * $maxAnswers); - foreach (range('A', Coordinate::stringFromColumnIndex($lastColumnIndex)) as $column) { + foreach ($this->columnLetters($lastColumnIndex) as $column) { $sheet->getColumnDimension($column)->setAutoSize(true); } } @@ -426,6 +426,22 @@ class DataExportService } } + /** + * Column letters from 'A' up to and including the given 1-based column index. + * Unlike range('A', ...), this works past 'Z' (e.g. index 27 => 'AA'). + * + * @return list + */ + private function columnLetters(int $lastColumnIndex): array + { + $letters = []; + for ($columnIndex = 1; $columnIndex <= $lastColumnIndex; ++$columnIndex) { + $letters[] = Coordinate::stringFromColumnIndex($columnIndex); + } + + return $letters; + } + /** @throws FilesystemException */ private function writeToTempFile(Spreadsheet $spreadsheet): string { diff --git a/tests/Service/DataExportServiceRawAnswersColumnsTest.php b/tests/Service/DataExportServiceRawAnswersColumnsTest.php new file mode 100644 index 0000000..369d073 --- /dev/null +++ b/tests/Service/DataExportServiceRawAnswersColumnsTest.php @@ -0,0 +1,47 @@ +createStub(EntityManagerInterface::class), + $this->createStub(QuizSpreadsheetService::class), + $this->createStub(QuizRepository::class), + ); + + $quiz = new Quiz(); + for ($i = 0; $i < 26; ++$i) { + $question = new Question(); + $question->question = 'Question '.($i + 1); + $quiz->addQuestion($question); + } + + $sheet = new Spreadsheet()->getActiveSheet(); + + $method = new \ReflectionMethod(DataExportService::class, 'fillRawAnswersSheet'); + $method->invoke($subject, $sheet, $quiz); + + $this->assertEqualsWithDelta(30.0, $sheet->getColumnDimension('AA')->getWidth(), \PHP_FLOAT_EPSILON); + } +}