From ab7d1f8aafed243d9262bc38db9cfbab95daa680 Mon Sep 17 00:00:00 2001 From: Fabian Schmid Date: Fri, 23 Oct 2026 23:14:39 +0200 Subject: [PATCH 1/2] [Improvement] Excel: provide CellType and ExcelException for ilExcel --- .../ILIAS/Excel/classes/class.ilExcel.php | 68 ++++++++++++------- components/ILIAS/Excel/src/CellType.php | 32 +++++++++ components/ILIAS/Excel/src/ExcelException.php | 28 ++++++++ .../tests/{ExcelTestTBD.php => ExcelTest.php} | 22 ++++++ 4 files changed, 127 insertions(+), 23 deletions(-) create mode 100644 components/ILIAS/Excel/src/CellType.php create mode 100644 components/ILIAS/Excel/src/ExcelException.php rename components/ILIAS/Excel/tests/{ExcelTestTBD.php => ExcelTest.php} (69%) diff --git a/components/ILIAS/Excel/classes/class.ilExcel.php b/components/ILIAS/Excel/classes/class.ilExcel.php index 8d8e666d1fc6..d7fd6a91bd6d 100755 --- a/components/ILIAS/Excel/classes/class.ilExcel.php +++ b/components/ILIAS/Excel/classes/class.ilExcel.php @@ -26,6 +26,8 @@ use PhpOffice\PhpSpreadsheet\Style\Border; use PhpOffice\PhpSpreadsheet\Cell\DataType; use ILIAS\FileUpload\MimeType; +use ILIAS\Excel\CellType; +use ILIAS\Excel\ExcelException; /* * Wrapper for Microsoft Excel Import/Export (based on PHPSpreadsheet, formerPHPExcel which is deprecated) @@ -63,7 +65,7 @@ class ilExcel protected string $type; /** - * @throws \PhpOffice\PhpSpreadsheet\Exception + * @throws ExcelException */ public function __construct() { @@ -72,7 +74,24 @@ public function __construct() $this->lng = $DIC->language(); $this->setFormat(self::FORMAT_XML); $this->workbook = new Spreadsheet(); - $this->workbook->removeSheetByIndex(0); + $this->wrapped(fn() => $this->workbook->removeSheetByIndex(0)); + } + + /** + * Runs a call to the library and translates its exceptions, so they do not leave this wrapper. + * + * @template T + * @param callable(): T $call + * @return T + * @throws ExcelException + */ + private function wrapped(callable $call): mixed + { + try { + return $call(); + } catch (\PhpOffice\PhpSpreadsheet\Exception $e) { + throw new ExcelException($e->getMessage(), $e->getCode(), $e); + } } // @@ -81,10 +100,12 @@ public function __construct() /** * Loads a spreadsheet from file + * + * @throws ExcelException */ public function loadFromFile(string $filename): void { - $this->workbook = IOFactory::load($filename); + $this->workbook = $this->wrapped(fn(): Spreadsheet => IOFactory::load($filename)); } // @@ -117,7 +138,7 @@ public function setFormat(string $a_format): void /** * Add sheet * - * @throws \PhpOffice\PhpSpreadsheet\Exception + * @throws ExcelException */ public function addSheet( string $a_name, @@ -133,8 +154,7 @@ public function addSheet( // see https://github.com/PHPOffice/PHPExcel/issues/79 $a_name = ilStr::shortenTextExtended($a_name, 31); - $sheet = new Worksheet($this->workbook, $a_name); - $this->workbook->addSheet($sheet); + $this->wrapped(fn() => $this->workbook->addSheet(new Worksheet($this->workbook, $a_name))); $new_index = $this->workbook->getSheetCount() - 1; if ($a_activate) { @@ -145,11 +165,11 @@ public function addSheet( } /** - * @throws \PhpOffice\PhpSpreadsheet\Exception + * @throws ExcelException */ public function setActiveSheet(int $a_index): void { - $this->workbook->setActiveSheetIndex($a_index); + $this->wrapped(fn() => $this->workbook->setActiveSheetIndex($a_index)); } @@ -283,15 +303,18 @@ public function setCellByCoordinates($a_coords, $a_value): void * @param int $a_row * @param int $col * @param mixed $value - * @param ?string $datatype Explicit data type, see DataType::TYPE_* + * @param CellType|string|null $datatype Explicit data type; strings are deprecated, use {@see CellType} */ public function setCell( int $a_row, int $col, $value, - ?string $datatype = null + CellType|string|null $datatype = null ): void { $coordinate = $this->getCoordByColumnAndRow($col, $a_row); + if ($datatype instanceof CellType) { + $datatype = $datatype->value; + } if ($datatype === DataType::TYPE_STRING) { $this->workbook->getActiveSheet()->setCellValueExplicit( @@ -437,7 +460,7 @@ protected function prepareStorage(string $a_file_name): string /** * Send workbook to client - * @throws \PhpOffice\PhpSpreadsheet\Writer\Exception + * @throws ExcelException */ public function sendToClient(string $a_file_name): void { @@ -456,8 +479,7 @@ public function sendToClient(string $a_file_name): void } $tmp_name = ilFileUtils::ilTempnam(); - $writer = IOFactory::createWriter($this->workbook, $this->format); - $writer->save($tmp_name); + $this->wrapped(fn() => IOFactory::createWriter($this->workbook, $this->format)->save($tmp_name)); ilFileDelivery::deliverFileAttached($tmp_name, $a_file_name, $a_mime_type, true); } @@ -465,24 +487,22 @@ public function sendToClient(string $a_file_name): void /** * Save workbook to file * - * @throws \PhpOffice\PhpSpreadsheet\Writer\Exception + * @throws ExcelException */ public function writeToFile(string $a_file): void { $a_file = $this->prepareStorage($a_file); - $writer = IOFactory::createWriter($this->workbook, $this->format); - $writer->save($a_file); + $this->wrapped(fn() => IOFactory::createWriter($this->workbook, $this->format)->save($a_file)); } /** - * @throws \PhpOffice\PhpSpreadsheet\Writer\Exception + * @throws ExcelException */ public function writeToTmpFile(): string { - $writer = IOFactory::createWriter($this->workbook, $this->format); $filename = ilFileUtils::ilTempnam(); - $writer->save($filename); + $this->wrapped(fn() => IOFactory::createWriter($this->workbook, $this->format)->save($filename)); return $filename; } @@ -560,7 +580,7 @@ public function getCoordByColumnAndRow( } /** - * @throws \PhpOffice\PhpSpreadsheet\Exception + * @throws ExcelException */ public function addLink( int $a_row, @@ -568,7 +588,9 @@ public function addLink( string $a_path ): void { $coordinate = $this->getCoordByColumnAndRow($a_column, $a_row); - $this->workbook->getActiveSheet()->getCell($coordinate)->getHyperlink()->setUrl($a_path); + $this->wrapped( + fn() => $this->workbook->getActiveSheet()->getCell($coordinate)->getHyperlink()->setUrl($a_path) + ); } /** @@ -582,11 +604,11 @@ public function columnIndexAdjustment(int $column): int /** * @param string $coordinatesRange A coordinates range string like 'A1:B5' - * @throws \PhpOffice\PhpSpreadsheet\Exception + * @throws ExcelException */ public function mergeCells(string $coordinatesRange): void { - $this->workbook->getActiveSheet()->mergeCells($coordinatesRange); + $this->wrapped(fn() => $this->workbook->getActiveSheet()->mergeCells($coordinatesRange)); } private function cleanupNonCharachters(string $string): string diff --git a/components/ILIAS/Excel/src/CellType.php b/components/ILIAS/Excel/src/CellType.php new file mode 100644 index 000000000000..c64f19483002 --- /dev/null +++ b/components/ILIAS/Excel/src/CellType.php @@ -0,0 +1,32 @@ +getCoordByColumnAndRow(2, 2) ); } + + public function testExceptionsOfTheLibraryAreTranslated(): void + { + $excel = new ilExcel(); + $excel->addSheet('first'); + + try { + $excel->setActiveSheet(5); + $this->fail('No exception thrown for a missing sheet.'); + } catch (\ILIAS\Excel\ExcelException $e) { + $this->assertInstanceOf(\PhpOffice\PhpSpreadsheet\Exception::class, $e->getPrevious()); + } + } + + public function testExplicitStringDataTypeKeepsNumericText(): void + { + $excel = new ilExcel(); + $excel->addSheet('first'); + $excel->setCell(1, 0, '007', \ILIAS\Excel\CellType::STRING); + + $this->assertSame('007', $excel->getCell(1, 0)); + } } From 90a6549bb2534cde260151970d28255889e23212 Mon Sep 17 00:00:00 2001 From: Fabian Schmid Date: Fri, 23 Oct 2026 23:14:40 +0200 Subject: [PATCH 2/2] [Improvement] use CellType and ExcelException of Excel instead of phpspreadsheet --- .../classes/Content/class.ilDclContentImporter.php | 2 +- .../Fields/Text/class.ilDclTextRecordFieldModel.php | 4 ++-- .../class.ilDclTextSelectionRecordFieldModel.php | 6 +++--- .../class.ilExerciseManagementCollectFilesJob.php | 10 +++++----- .../ILIAS/Exercise/classes/class.ilObjExercise.php | 2 +- .../Survey/Evaluation/class.ilSurveyEvaluationGUI.php | 2 +- .../ILIAS/Test/src/ExportImport/ResultsExportExcel.php | 3 +-- 7 files changed, 14 insertions(+), 15 deletions(-) diff --git a/components/ILIAS/DataCollection/classes/Content/class.ilDclContentImporter.php b/components/ILIAS/DataCollection/classes/Content/class.ilDclContentImporter.php index 2b13a640776a..0188a2cad1ad 100755 --- a/components/ILIAS/DataCollection/classes/Content/class.ilDclContentImporter.php +++ b/components/ILIAS/DataCollection/classes/Content/class.ilDclContentImporter.php @@ -71,7 +71,7 @@ public function __construct(int $ref_id, ?int $table_id = null) /** * @throws ilException - * @throws \PhpOffice\PhpSpreadsheet\Exception + * @throws \ILIAS\Excel\ExcelException * @throws ilDateTimeException */ public function import(string $file, bool $simulate = false): array diff --git a/components/ILIAS/DataCollection/classes/Fields/Text/class.ilDclTextRecordFieldModel.php b/components/ILIAS/DataCollection/classes/Fields/Text/class.ilDclTextRecordFieldModel.php index 09d956f935c7..e5ab46f64c72 100755 --- a/components/ILIAS/DataCollection/classes/Fields/Text/class.ilDclTextRecordFieldModel.php +++ b/components/ILIAS/DataCollection/classes/Fields/Text/class.ilDclTextRecordFieldModel.php @@ -18,7 +18,7 @@ declare(strict_types=1); -use PhpOffice\PhpSpreadsheet\Cell\DataType; +use ILIAS\Excel\CellType; class ilDclTextRecordFieldModel extends ilDclBaseRecordFieldModel { @@ -50,7 +50,7 @@ public function fillExcelExport(ilExcel $worksheet, int &$row, int &$col): void $col += 2; } } else { - $worksheet->setCell($row, $col, $value, DataType::TYPE_STRING); + $worksheet->setCell($row, $col, $value, CellType::STRING); $col++; } } diff --git a/components/ILIAS/DataCollection/classes/Fields/TextSelection/class.ilDclTextSelectionRecordFieldModel.php b/components/ILIAS/DataCollection/classes/Fields/TextSelection/class.ilDclTextSelectionRecordFieldModel.php index 036172f094fb..8336c626a937 100755 --- a/components/ILIAS/DataCollection/classes/Fields/TextSelection/class.ilDclTextSelectionRecordFieldModel.php +++ b/components/ILIAS/DataCollection/classes/Fields/TextSelection/class.ilDclTextSelectionRecordFieldModel.php @@ -18,16 +18,16 @@ declare(strict_types=1); -use PhpOffice\PhpSpreadsheet\Cell\DataType; +use ILIAS\Excel\CellType; class ilDclTextSelectionRecordFieldModel extends ilDclSelectionRecordFieldModel { /** - * @throws \PhpOffice\PhpSpreadsheet\Exception + * @throws \ILIAS\Excel\ExcelException */ public function fillExcelExport(ilExcel $worksheet, int &$row, int &$col): void { - $worksheet->setCell($row, $col, $this->getExportValue(), DataType::TYPE_STRING); + $worksheet->setCell($row, $col, $this->getExportValue(), CellType::STRING); $col++; } } diff --git a/components/ILIAS/Exercise/classes/BackgroundTasks/class.ilExerciseManagementCollectFilesJob.php b/components/ILIAS/Exercise/classes/BackgroundTasks/class.ilExerciseManagementCollectFilesJob.php index b26ac17493ab..c76708ec1379 100755 --- a/components/ILIAS/Exercise/classes/BackgroundTasks/class.ilExerciseManagementCollectFilesJob.php +++ b/components/ILIAS/Exercise/classes/BackgroundTasks/class.ilExerciseManagementCollectFilesJob.php @@ -113,7 +113,7 @@ public function isStateless(): bool /** * run the job * @throws \ILIAS\BackgroundTasks\Exceptions\InvalidArgumentException - * @throws \PhpOffice\PhpSpreadsheet\Exception + * @throws \ILIAS\Excel\ExcelException * @throws ilDatabaseException * @throws ilExerciseException * @throws ilObjectNotFoundException @@ -186,7 +186,7 @@ public function getExpectedTimeOfTaskInSeconds(): int /** * Set the Excel column titles. - * @throws \PhpOffice\PhpSpreadsheet\Exception + * @throws \ILIAS\Excel\ExcelException */ protected function addColumnTitles(): void { @@ -282,7 +282,7 @@ protected function isExcelNeeded(int $a_ass_type, bool $a_has_fbk): bool /** * Add criteria data to the excel. - * @throws \PhpOffice\PhpSpreadsheet\Exception + * @throws \ILIAS\Excel\ExcelException */ protected function addCriteriaToExcel( int $feedback_giver, @@ -442,7 +442,7 @@ public function addLink( * write assignment data to excel file * @todo Refactoring needed, long method... * @param int $assignment_id - * @throws \PhpOffice\PhpSpreadsheet\Exception + * @throws \ILIAS\Excel\ExcelException * @throws ilDatabaseException * @throws ilExerciseException * @throws ilObjectNotFoundException @@ -483,7 +483,7 @@ protected function collectAssignmentData(int $assignment_id): void } if ($this->isExcelNeeded($assignment_type, $ass_has_feedback)) { - // PhpSpreadsheet object + // spreadsheet $this->excel = new ilExcel(); //Excel sheet title diff --git a/components/ILIAS/Exercise/classes/class.ilObjExercise.php b/components/ILIAS/Exercise/classes/class.ilObjExercise.php index 2f5dfdf9b923..ebbef6d176ab 100755 --- a/components/ILIAS/Exercise/classes/class.ilObjExercise.php +++ b/components/ILIAS/Exercise/classes/class.ilObjExercise.php @@ -614,7 +614,7 @@ public function updateAllUsersStatus(): void /** * Exports grades as excel - * @throws \PhpOffice\PhpSpreadsheet\Exception + * @throws \ILIAS\Excel\ExcelException * @throws ilExcUnknownAssignmentTypeException */ public function exportGradesExcel(): void diff --git a/components/ILIAS/Survey/Evaluation/class.ilSurveyEvaluationGUI.php b/components/ILIAS/Survey/Evaluation/class.ilSurveyEvaluationGUI.php index b4e7dd5c2c81..e63bf6f0849c 100755 --- a/components/ILIAS/Survey/Evaluation/class.ilSurveyEvaluationGUI.php +++ b/components/ILIAS/Survey/Evaluation/class.ilSurveyEvaluationGUI.php @@ -425,7 +425,7 @@ public function exportCumulatedResults( /** * Export details (excel only) * @param ilSurveyEvaluationResults|array $a_results - * @throws \PhpOffice\PhpSpreadsheet\Exception + * @throws \ILIAS\Excel\ExcelException */ protected function exportResultsDetailsExcel( ilExcel $a_excel, diff --git a/components/ILIAS/Test/src/ExportImport/ResultsExportExcel.php b/components/ILIAS/Test/src/ExportImport/ResultsExportExcel.php index 446a7dd0a9f7..64ee5cf2b77d 100755 --- a/components/ILIAS/Test/src/ExportImport/ResultsExportExcel.php +++ b/components/ILIAS/Test/src/ExportImport/ResultsExportExcel.php @@ -22,7 +22,6 @@ use ILIAS\TestQuestionPool\Questions\GeneralQuestionPropertiesRepository; use ILIAS\Data\DateFormat\DateFormat; -use PhpOffice\PhpSpreadsheet\Cell\DataType; /** * @author Fabian Helfer @@ -130,7 +129,7 @@ public function write(): ?string } /** - * @throws \PhpOffice\PhpSpreadsheet\Writer\Exception + * @throws \ILIAS\Excel\ExcelException */ public function deliver(): void {