diff --git a/src/PhpSpreadsheet/Cell/DataValidation.php b/src/PhpSpreadsheet/Cell/DataValidation.php index 79d70a98..7ee53eae 100644 --- a/src/PhpSpreadsheet/Cell/DataValidation.php +++ b/src/PhpSpreadsheet/Cell/DataValidation.php @@ -460,6 +460,7 @@ class DataValidation $this->error . $this->promptTitle . $this->prompt . + $this->sqref . __CLASS__ ); } diff --git a/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php b/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php index 466e8b00..286ebe7e 100644 --- a/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php +++ b/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php @@ -85,6 +85,9 @@ class Worksheet extends WriterPart // conditionalFormatting $this->writeConditionalFormatting($objWriter, $worksheet); + // dataValidations + $this->writeDataValidations($objWriter, $worksheet); + // hyperlinks $this->writeHyperlinks($objWriter, $worksheet); @@ -118,8 +121,6 @@ class Worksheet extends WriterPart // ConditionalFormattingRuleExtensionList // (Must be inserted last. Not insert last, an Excel parse error will occur) $this->writeExtLst($objWriter, $worksheet); - // dataValidations - $this->writeDataValidations($objWriter, $worksheet); $objWriter->endElement(); @@ -681,16 +682,11 @@ class Worksheet extends WriterPart // Write data validations? if (!empty($dataValidationCollection)) { $dataValidationCollection = Coordinate::mergeRangesInCollection($dataValidationCollection); - $objWriter->startElement('extLst'); - $objWriter->startElement('ext'); - $objWriter->writeAttribute('uri', '{CCE6A557-97BC-4b89-ADB6-D9C93CAAB3DF}'); - $objWriter->writeAttribute('xmlns:x14', 'http://schemas.microsoft.com/office/spreadsheetml/2009/9/main'); - $objWriter->startElement('x14:dataValidations'); + $objWriter->startElement('dataValidations'); $objWriter->writeAttribute('count', count($dataValidationCollection)); - $objWriter->writeAttribute('xmlns:xm', 'http://schemas.microsoft.com/office/excel/2006/main'); foreach ($dataValidationCollection as $coordinate => $dv) { - $objWriter->startElement('x14:dataValidation'); + $objWriter->startElement('dataValidation'); if ($dv->getType() != '') { $objWriter->writeAttribute('type', $dv->getType()); @@ -705,7 +701,6 @@ class Worksheet extends WriterPart } $objWriter->writeAttribute('allowBlank', ($dv->getAllowBlank() ? '1' : '0')); - // showDropDown is really hideDropDown Excel renders as true = hide, false = show $objWriter->writeAttribute('showDropDown', (!$dv->getShowDropDown() ? '1' : '0')); $objWriter->writeAttribute('showInputMessage', ($dv->getShowInputMessage() ? '1' : '0')); $objWriter->writeAttribute('showErrorMessage', ($dv->getShowErrorMessage() ? '1' : '0')); @@ -723,24 +718,19 @@ class Worksheet extends WriterPart $objWriter->writeAttribute('prompt', $dv->getPrompt()); } + $objWriter->writeAttribute('sqref', $dv->getSqref() ?? $coordinate); + if ($dv->getFormula1() !== '') { - $objWriter->startElement('x14:formula1'); - $objWriter->writeElement('xm:f', $dv->getFormula1()); - $objWriter->endElement(); + $objWriter->writeElement('formula1', $dv->getFormula1()); } if ($dv->getFormula2() !== '') { - $objWriter->startElement('x14:formula2'); - $objWriter->writeElement('xm:f', $dv->getFormula2()); - $objWriter->endElement(); + $objWriter->writeElement('formula2', $dv->getFormula2()); } - $objWriter->writeElement('xm:sqref', $dv->getSqref() ?? $coordinate); $objWriter->endElement(); } - $objWriter->endElement(); // dataValidations - $objWriter->endElement(); // ext - $objWriter->endElement(); // extLst + $objWriter->endElement(); } } diff --git a/tests/PhpSpreadsheetTests/Writer/Xlsx/Issue2368Test.php b/tests/PhpSpreadsheetTests/Writer/Xlsx/Issue2368Test.php new file mode 100644 index 00000000..8915f5df --- /dev/null +++ b/tests/PhpSpreadsheetTests/Writer/Xlsx/Issue2368Test.php @@ -0,0 +1,78 @@ +getActiveSheet(); + $validation = $sheet->getDataValidation('A1:A10'); + $validation->setType(DataValidation::TYPE_LIST); + $validation->setShowDropDown(true); + $validation->setFormula1('"Option 1, Option 2"'); + + $outputFilename = File::temporaryFilename(); + $writer = new Writer($spreadsheet); + $writer->save($outputFilename); + $zipfile = "zip://$outputFilename#xl/worksheets/sheet1.xml"; + $contents = file_get_contents($zipfile); + unlink($outputFilename); + $spreadsheet->disconnectWorksheets(); + if ($contents === false) { + self::fail('Unable to open file'); + } else { + self::assertSame(0, substr_count($contents, '')); + self::assertSame(2, substr_count($contents, 'dataValidations')); // start and end tags + } + } + + public function testMultipleRange(): void + { + // DataValidations which were identical except for sqref were incorrectly merged. + $filename = 'tests/data/Writer/XLSX/issue.2368new.xlsx'; + $reader = IOFactory::createReader('Xlsx'); + $spreadsheet = $reader->load($filename); + $sheet = $spreadsheet->getActiveSheet(); + $validations = $sheet->getDataValidationCollection(); + /** @var string[] */ + $ranges = []; + foreach ($validations as $validation) { + $ranges[] = $validation->getSqref(); + } + self::assertContains('A1:A5', $ranges); + self::assertContains('A10:A14', $ranges); + self::assertContains('A20:A24', $ranges); + self::assertSame('"yes,no"', $sheet->getCell('A3')->getDataValidation()->getFormula1()); + self::assertSame('"yes,no"', $sheet->getCell('A10')->getDataValidation()->getFormula1()); + self::assertSame('"yes,no"', $sheet->getCell('A24')->getDataValidation()->getFormula1()); + + $reloadedSpreadsheet = $this->writeAndReload($spreadsheet, 'Xlsx'); + $spreadsheet->disconnectWorksheets(); + + $sheet2 = $reloadedSpreadsheet->getActiveSheet(); + $validation2 = $sheet2->getDataValidationCollection(); + /** @var string[] */ + $range2 = []; + foreach ($validation2 as $validation) { + $range2[] = $validation->getSqref(); + } + self::assertContains('A1:A5', $range2); + self::assertContains('A10:A14', $range2); + self::assertContains('A20:A24', $range2); + self::assertSame('"yes,no"', $sheet2->getCell('A3')->getDataValidation()->getFormula1()); + self::assertSame('"yes,no"', $sheet2->getCell('A10')->getDataValidation()->getFormula1()); + self::assertSame('"yes,no"', $sheet2->getCell('A24')->getDataValidation()->getFormula1()); + + $reloadedSpreadsheet->disconnectWorksheets(); + } +} diff --git a/tests/data/Writer/XLSX/issue.2368new.xlsx b/tests/data/Writer/XLSX/issue.2368new.xlsx new file mode 100644 index 00000000..dbd693f6 Binary files /dev/null and b/tests/data/Writer/XLSX/issue.2368new.xlsx differ