question = 'Is de mol een man of een vrouw?'; $geslacht->ordering = 1; $geslacht->addAnswer(new Answer('Man', true)); $geslacht->addAnswer(new Answer('Vrouw')); $quiz->addQuestion($geslacht); $identiteit = new Question(); $identiteit->question = 'Wie is de mol?'; $identiteit->ordering = 2; foreach ([ ['Emma', false], ['Jan', false], ['Sara', false], ['Piet', false], ['Lisa', true], ['Kees', false], ['Anna', false], ['Henk', false], ['Nina', false], ['Joost', false], ] as $i => [$name, $correct]) { $answer = new Answer($name, $correct); $answer->ordering = $i + 1; $identiteit->addAnswer($answer); } $quiz->addQuestion($identiteit); } return $this->quizToXlsx($quiz); } /** @throws SpreadsheetDataException */ public function xlsxToQuiz(Quiz $quiz, File $file): void { if (!$this->isSpreadsheetFile($file)) { throw new \InvalidArgumentException('File must be a valid XLSX spreadsheet'); } $spreadsheet = $this->readSheet($file); $sheet = $spreadsheet->getSheet($spreadsheet->getFirstSheetIndex()); $answerLines = \array_slice($sheet->toArray(formatData: false), 1); $this->fillQuizFromArray($quiz, $answerLines); } private function readSheet(File $file): Spreadsheet { return new Reader\Xlsx()->setReadDataOnly(true)->load($file->getRealPath()); } /** * @param array> $sheet * * @throws SpreadsheetDataException */ private function fillQuizFromArray(Quiz $quiz, array $sheet): void { $errors = []; $questionCounter = 1; foreach ($sheet as $questionArr) { if (null === $questionArr[0]) { break; } $question = new Question(); $question->question = (string) $questionArr[0]; $question->ordering = $questionCounter++; $answerCounter = 1; $arrCounter = 1; while (\array_key_exists($arrCounter, $questionArr) && null !== $questionArr[$arrCounter]) { $answer = new Answer((string) $questionArr[$arrCounter++], (bool) $questionArr[$arrCounter++]); $answer->ordering = $answerCounter++; $question->addAnswer($answer); } if (1 === $answerCounter) { $errors[] = \sprintf('Question %d has no answers', $question->ordering); } $quiz->addQuestion($question); } if ([] !== $errors) { throw new SpreadsheetDataException($errors); } } public function quizToXlsx(Quiz $quiz): \Closure { $spreadsheet = new Spreadsheet(); $sheet = $spreadsheet->getActiveSheet(); // Write data rows first so we know the maximum answer count. $maxAnswers = 0; $row = 2; foreach ($quiz->questions as $question) { $sheet->setCellValue('A'.$row, $question->question); $col = 0; foreach ($question->answers as $answer) { $sheet->setCellValue(Coordinate::stringFromColumnIndex(2 + 2 * $col).$row, $answer->text); $sheet->setCellValue(Coordinate::stringFromColumnIndex(3 + 2 * $col).$row, $answer->isRightAnswer); ++$col; } $maxAnswers = max($maxAnswers, $col); ++$row; } // Write headers last, sized to the widest question. $sheet->getStyle('1:1')->getFont()->setBold(true); $sheet->setCellValue('A1', 'Question'); $sheet->getColumnDimension('A')->setWidth(30); $sheet->getStyle('A:A')->getAlignment()->setWrapText(true); for ($i = 0; $i < $maxAnswers; ++$i) { $answerCol = Coordinate::stringFromColumnIndex(2 + 2 * $i); $correctCol = Coordinate::stringFromColumnIndex(3 + 2 * $i); $sheet->setCellValue($answerCol.'1', 'Answer '.($i + 1)); $sheet->getColumnDimension($answerCol)->setWidth(30); $sheet->getStyle($answerCol.':'.$answerCol)->getAlignment()->setWrapText(true); $sheet->setCellValue($correctCol.'1', 'Correct'); $sheet->getColumnDimension($correctCol)->setAutoSize(true); } return $this->toXlsx($spreadsheet); } private function toXlsx(Spreadsheet $spreadsheet): \Closure { $writer = new Writer\Xlsx($spreadsheet); return static fn () => $writer->save('php://output'); } private function isSpreadsheetFile(File $file): bool { return 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' === $file->getMimeType(); } }