From 34dd0a929e5546ced2cadeb4745018be291fb9aa Mon Sep 17 00:00:00 2001 From: MarkBaker Date: Sun, 15 May 2022 13:40:46 +0200 Subject: [PATCH 1/7] Read ChartSheets with the Xlsx Reader if includeCharts is enabled; although we're reading it as a normal worksheet that simply contains a chart at cell A1, xOffset 0, yOffset 0, with no data And Handle ChartSheets in the Xlsx Writer --- src/PhpSpreadsheet/Chart/Chart.php | 4 +- src/PhpSpreadsheet/Reader/Xlsx.php | 51 +++++++++++++++++-- src/PhpSpreadsheet/Reader/Xlsx/Namespaces.php | 2 + src/PhpSpreadsheet/Writer/Xlsx/Drawing.php | 42 ++++++++++----- 4 files changed, 79 insertions(+), 20 deletions(-) diff --git a/src/PhpSpreadsheet/Chart/Chart.php b/src/PhpSpreadsheet/Chart/Chart.php index bed89464..5982548e 100644 --- a/src/PhpSpreadsheet/Chart/Chart.php +++ b/src/PhpSpreadsheet/Chart/Chart.php @@ -124,7 +124,7 @@ class Chart * * @var string */ - private $bottomRightCellRef = 'A1'; + private $bottomRightCellRef = ''; /** * Bottom-Right X-Offset. @@ -524,7 +524,7 @@ class Chart * * @return $this */ - public function setBottomRightPosition($cell, $xOffset = null, $yOffset = null) + public function setBottomRightPosition($cell = '', $xOffset = null, $yOffset = null) { $this->bottomRightCellRef = $cell; if ($xOffset !== null) { diff --git a/src/PhpSpreadsheet/Reader/Xlsx.php b/src/PhpSpreadsheet/Reader/Xlsx.php index a6e7fe03..2068e950 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx.php +++ b/src/PhpSpreadsheet/Reader/Xlsx.php @@ -512,6 +512,12 @@ class Xlsx extends BaseReader case Namespaces::PURL_WORKSHEET: $worksheets[(string) $ele['Id']] = $ele['Target']; + break; + case Namespaces::CHARTSHEET: + if ($this->includeCharts === true) { + $worksheets[(string) $ele['Id']] = $ele['Target']; + } + break; // a vbaProject ? (: some macros) case Namespaces::VBA: @@ -690,6 +696,13 @@ class Xlsx extends BaseReader continue; } + $sheetReferenceId = (string) self::getArrayItem(self::getAttributes($eleSheet, $xmlNamespaceBase), 'id'); + if (isset($worksheets[$sheetReferenceId]) === false) { + ++$countSkippedSheets; + $mapSheetId[$oldSheetId] = null; + + continue; + } // Map old sheet id in original workbook to new sheet id. // They will differ if loadSheetsOnly() is being used $mapSheetId[$oldSheetId] = $oldSheetId - $countSkippedSheets; @@ -701,7 +714,8 @@ class Xlsx extends BaseReader // and we're simply bringing the worksheet name in line with the formula, not the // reverse $docSheet->setTitle((string) $eleSheetAttr['name'], false, false); - $fileWorksheet = (string) $worksheets[(string) self::getArrayItem(self::getAttributes($eleSheet, $xmlNamespaceBase), 'id')]; + + $fileWorksheet = (string) $worksheets[$sheetReferenceId]; $xmlSheet = $this->loadZipNoNamespace("$dir/$fileWorksheet", $mainNS); $xmlSheetNS = $this->loadZip("$dir/$fileWorksheet", $mainNS); @@ -1195,6 +1209,7 @@ class Xlsx extends BaseReader $drawings[(string) $ele['Id']] = self::dirAdd("$dir/$fileWorksheet", $ele['Target']); } } + if ($xmlSheet->drawing && !$this->readDataOnly) { $unparsedDrawings = []; $fileDrawing = null; @@ -1203,6 +1218,7 @@ class Xlsx extends BaseReader $fileDrawing = $drawings[$drawingRelId]; $drawingFilename = dirname($fileDrawing) . '/_rels/' . basename($fileDrawing) . '.rels'; $relsDrawing = $this->loadZipNoNamespace($drawingFilename, $xmlNamespaceBase); + $images = []; $hyperlinks = []; if ($relsDrawing && $relsDrawing->Relationship) { @@ -1223,6 +1239,7 @@ class Xlsx extends BaseReader } } } + $xmlDrawing = $this->loadZipNoNamespace($fileDrawing, ''); $xmlDrawingChildren = $xmlDrawing->children(Namespaces::SPREADSHEET_DRAWING); @@ -1401,6 +1418,27 @@ class Xlsx extends BaseReader } } } + if ($xmlDrawingChildren->absoluteAnchor) { + foreach ($xmlDrawingChildren->absoluteAnchor as $absoluteAnchor) { + if (($this->includeCharts) && ($absoluteAnchor->graphicFrame)) { + $graphic = $absoluteAnchor->graphicFrame->children(Namespaces::DRAWINGML)->graphic; + /** @var SimpleXMLElement $chartRef */ + $chartRef = $graphic->graphicData->children(Namespaces::CHART)->chart; + $thisChart = (string) self::getAttributes($chartRef, $xmlNamespaceBase); + $width = Drawing::EMUToPixels((int) self::getArrayItem(self::getAttributes($absoluteAnchor->ext), 'cx')[0]); + $height = Drawing::EMUToPixels((int) self::getArrayItem(self::getAttributes($absoluteAnchor->ext), 'cy')[0]); + + $chartDetails[$docSheet->getTitle() . '!' . $thisChart] = [ + 'fromCoordinate' => 'A1', + 'fromOffsetX' => 0, + 'fromOffsetY' => 0, + 'width' => $width, + 'height' => $height, + 'worksheetTitle' => $docSheet->getTitle(), + ]; + } + } + } if (empty($relsDrawing) && $xmlDrawing->count() == 0) { // Save Drawing without rels and children as unparsed $unparsedDrawings[$drawingRelId] = $xmlDrawing->asXML(); @@ -1600,16 +1638,21 @@ class Xlsx extends BaseReader $chartEntryRef = ltrim((string) $contentType['PartName'], '/'); $chartElements = $this->loadZip($chartEntryRef); $objChart = Chart::readChart($chartElements, basename($chartEntryRef, '.xml')); - if (isset($charts[$chartEntryRef])) { $chartPositionRef = $charts[$chartEntryRef]['sheet'] . '!' . $charts[$chartEntryRef]['id']; if (isset($chartDetails[$chartPositionRef])) { $excel->getSheetByName($charts[$chartEntryRef]['sheet'])->addChart($objChart); $objChart->setWorksheet($excel->getSheetByName($charts[$chartEntryRef]['sheet'])); - $objChart->setTopLeftPosition($chartDetails[$chartPositionRef]['fromCoordinate'], $chartDetails[$chartPositionRef]['fromOffsetX'], $chartDetails[$chartPositionRef]['fromOffsetY']); + // For oneCellAnchor or absoluteAnchor positioned charts, + // toCoordinate is not in the data. Does it need to be calculated? if (array_key_exists('toCoordinate', $chartDetails[$chartPositionRef])) { - // For oneCellAnchor positioned charts, toCoordinate is not in the data. Does it need to be calculated? + // twoCellAnchor + $objChart->setTopLeftPosition($chartDetails[$chartPositionRef]['fromCoordinate'], $chartDetails[$chartPositionRef]['fromOffsetX'], $chartDetails[$chartPositionRef]['fromOffsetY']); $objChart->setBottomRightPosition($chartDetails[$chartPositionRef]['toCoordinate'], $chartDetails[$chartPositionRef]['toOffsetX'], $chartDetails[$chartPositionRef]['toOffsetY']); + } else { + // oneCellAnchor or absoluteAnchor (e.g. Chart sheet) + $objChart->setTopLeftPosition($chartDetails[$chartPositionRef]['fromCoordinate'], $chartDetails[$chartPositionRef]['fromOffsetX'], $chartDetails[$chartPositionRef]['fromOffsetY']); + $objChart->setBottomRightPosition('', $chartDetails[$chartPositionRef]['width'], $chartDetails[$chartPositionRef]['height']); } } } diff --git a/src/PhpSpreadsheet/Reader/Xlsx/Namespaces.php b/src/PhpSpreadsheet/Reader/Xlsx/Namespaces.php index c0713ae4..eb768d09 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx/Namespaces.php +++ b/src/PhpSpreadsheet/Reader/Xlsx/Namespaces.php @@ -50,6 +50,8 @@ class Namespaces const WORKSHEET = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet'; + const CHARTSHEET = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/chartsheet'; + const SCHEMA_MICROSOFT = 'http://schemas.microsoft.com/office/2006/relationships'; const EXTENSIBILITY = 'http://schemas.microsoft.com/office/2006/relationships/ui/extensibility'; diff --git a/src/PhpSpreadsheet/Writer/Xlsx/Drawing.php b/src/PhpSpreadsheet/Writer/Xlsx/Drawing.php index 816bb9d4..33eee1e0 100644 --- a/src/PhpSpreadsheet/Writer/Xlsx/Drawing.php +++ b/src/PhpSpreadsheet/Writer/Xlsx/Drawing.php @@ -89,22 +89,36 @@ class Drawing extends WriterPart $tl = $chart->getTopLeftPosition(); $tlColRow = Coordinate::indexesFromString($tl['cell']); $br = $chart->getBottomRightPosition(); - $brColRow = Coordinate::indexesFromString($br['cell']); - $objWriter->startElement('xdr:twoCellAnchor'); + $isTwoCellAnchor = $br['cell'] !== ''; + if ($isTwoCellAnchor) { + $brColRow = Coordinate::indexesFromString($br['cell']); - $objWriter->startElement('xdr:from'); - $objWriter->writeElement('xdr:col', (string) ($tlColRow[0] - 1)); - $objWriter->writeElement('xdr:colOff', self::stringEmu($tl['xOffset'])); - $objWriter->writeElement('xdr:row', (string) ($tlColRow[1] - 1)); - $objWriter->writeElement('xdr:rowOff', self::stringEmu($tl['yOffset'])); - $objWriter->endElement(); - $objWriter->startElement('xdr:to'); - $objWriter->writeElement('xdr:col', (string) ($brColRow[0] - 1)); - $objWriter->writeElement('xdr:colOff', self::stringEmu($br['xOffset'])); - $objWriter->writeElement('xdr:row', (string) ($brColRow[1] - 1)); - $objWriter->writeElement('xdr:rowOff', self::stringEmu($br['yOffset'])); - $objWriter->endElement(); + $objWriter->startElement('xdr:twoCellAnchor'); + + $objWriter->startElement('xdr:from'); + $objWriter->writeElement('xdr:col', (string) ($tlColRow[0] - 1)); + $objWriter->writeElement('xdr:colOff', self::stringEmu($tl['xOffset'])); + $objWriter->writeElement('xdr:row', (string) ($tlColRow[1] - 1)); + $objWriter->writeElement('xdr:rowOff', self::stringEmu($tl['yOffset'])); + $objWriter->endElement(); + $objWriter->startElement('xdr:to'); + $objWriter->writeElement('xdr:col', (string) ($brColRow[0] - 1)); + $objWriter->writeElement('xdr:colOff', self::stringEmu($br['xOffset'])); + $objWriter->writeElement('xdr:row', (string) ($brColRow[1] - 1)); + $objWriter->writeElement('xdr:rowOff', self::stringEmu($br['yOffset'])); + $objWriter->endElement(); + } else { + $objWriter->startElement('xdr:absoluteAnchor'); + $objWriter->startElement('xdr:pos'); + $objWriter->writeAttribute('x', '0'); + $objWriter->writeAttribute('y', '0'); + $objWriter->endElement(); + $objWriter->startElement('xdr:ext'); + $objWriter->writeAttribute('cx', self::stringEmu($br['xOffset'])); + $objWriter->writeAttribute('cy', self::stringEmu($br['yOffset'])); + $objWriter->endElement(); + } $objWriter->startElement('xdr:graphicFrame'); $objWriter->writeAttribute('macro', ''); From 198878b34741853fe6d9f49dca5cb1a6046f7a4d Mon Sep 17 00:00:00 2001 From: MarkBaker Date: Mon, 16 May 2022 11:25:28 +0200 Subject: [PATCH 2/7] Add unit tests for ChartSheet reading --- .../Reader/Xlsx/ChartSheetTest.php | 35 ++++++++++++++++++ tests/data/Reader/XLSX/ChartSheet.xlsx | Bin 0 -> 18017 bytes 2 files changed, 35 insertions(+) create mode 100644 tests/PhpSpreadsheetTests/Reader/Xlsx/ChartSheetTest.php create mode 100644 tests/data/Reader/XLSX/ChartSheet.xlsx diff --git a/tests/PhpSpreadsheetTests/Reader/Xlsx/ChartSheetTest.php b/tests/PhpSpreadsheetTests/Reader/Xlsx/ChartSheetTest.php new file mode 100644 index 00000000..0f1605ff --- /dev/null +++ b/tests/PhpSpreadsheetTests/Reader/Xlsx/ChartSheetTest.php @@ -0,0 +1,35 @@ +setIncludeCharts(true); + $spreadsheet = $reader->load($filename); + + self::assertCount(2, $spreadsheet->getAllSheets()); + $chartSheet = $spreadsheet->getSheetByName('Chart1'); + self::assertInstanceOf(Worksheet::class, $chartSheet); + self::assertSame(1, $chartSheet->getChartCount()); + } + + public function testLoadChartSheetWithoutCharts(): void + { + $filename = 'tests/data/Reader/XLSX/ChartSheet.xlsx'; + $reader = new Xlsx(); + $reader->setIncludeCharts(false); + $spreadsheet = $reader->load($filename); + + self::assertCount(1, $spreadsheet->getAllSheets()); + $chartSheet = $spreadsheet->getSheetByName('Chart1'); + self::assertNull($chartSheet); + } +} diff --git a/tests/data/Reader/XLSX/ChartSheet.xlsx b/tests/data/Reader/XLSX/ChartSheet.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..861bdeeb3bceb619fcda438868e7d39a1c33cbfd GIT binary patch literal 18017 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%0DYP$nPZ;6WPvU9sG(z+8UuqY7l87FSf0JZR2 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 JHu(Rz`hQFE%}oFR literal 0 HcmV?d00001 From 94963f4b97350d11923989a242625864d884f5d1 Mon Sep 17 00:00:00 2001 From: MarkBaker Date: Mon, 16 May 2022 15:49:02 +0200 Subject: [PATCH 3/7] Type and return tpe cleanups --- phpstan-baseline.neon | 70 ------------------------------ src/PhpSpreadsheet/Chart/Chart.php | 59 +++++++++++++++++-------- 2 files changed, 41 insertions(+), 88 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 74087f44..664306fd 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1160,76 +1160,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Chart/Chart.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:getBottomRightXOffset\\(\\) has no return type specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Chart/Chart.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:getBottomRightYOffset\\(\\) has no return type specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Chart/Chart.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:getTopLeftXOffset\\(\\) has no return type specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Chart/Chart.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:getTopLeftYOffset\\(\\) has no return type specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Chart/Chart.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:setBottomRightCell\\(\\) has no return type specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Chart/Chart.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:setBottomRightCell\\(\\) has parameter \\$cell with no type specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Chart/Chart.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:setBottomRightXOffset\\(\\) has no return type specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Chart/Chart.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:setBottomRightXOffset\\(\\) has parameter \\$xOffset with no type specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Chart/Chart.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:setBottomRightYOffset\\(\\) has no return type specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Chart/Chart.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:setBottomRightYOffset\\(\\) has parameter \\$yOffset with no type specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Chart/Chart.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:setTopLeftXOffset\\(\\) has no return type specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Chart/Chart.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:setTopLeftXOffset\\(\\) has parameter \\$xOffset with no type specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Chart/Chart.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:setTopLeftYOffset\\(\\) has no return type specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Chart/Chart.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:setTopLeftYOffset\\(\\) has parameter \\$yOffset with no type specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Chart/Chart.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:\\$legend \\(PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Legend\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Legend\\|null\\.$#" count: 1 diff --git a/src/PhpSpreadsheet/Chart/Chart.php b/src/PhpSpreadsheet/Chart/Chart.php index 5982548e..2efec5bb 100644 --- a/src/PhpSpreadsheet/Chart/Chart.php +++ b/src/PhpSpreadsheet/Chart/Chart.php @@ -400,15 +400,15 @@ class Chart /** * Set the Top Left position for the chart. * - * @param string $cell + * @param string $cellAddress * @param int $xOffset * @param int $yOffset * * @return $this */ - public function setTopLeftPosition($cell, $xOffset = null, $yOffset = null) + public function setTopLeftPosition($cellAddress, $xOffset = null, $yOffset = null) { - $this->topLeftCellRef = $cell; + $this->topLeftCellRef = $cellAddress; if ($xOffset !== null) { $this->setTopLeftXOffset($xOffset); } @@ -446,13 +446,13 @@ class Chart /** * Set the Top Left cell position for the chart. * - * @param string $cell + * @param string $cellAddress * * @return $this */ - public function setTopLeftCell($cell) + public function setTopLeftCell($cellAddress) { - $this->topLeftCellRef = $cell; + $this->topLeftCellRef = $cellAddress; return $this; } @@ -491,6 +491,11 @@ class Chart ]; } + /** + * @param int $xOffset + * + * @return $this + */ public function setTopLeftXOffset($xOffset) { $this->topLeftXOffset = $xOffset; @@ -498,11 +503,16 @@ class Chart return $this; } - public function getTopLeftXOffset() + public function getTopLeftXOffset(): int { return $this->topLeftXOffset; } + /** + * @param int $yOffset + * + * @return $this + */ public function setTopLeftYOffset($yOffset) { $this->topLeftYOffset = $yOffset; @@ -510,7 +520,7 @@ class Chart return $this; } - public function getTopLeftYOffset() + public function getTopLeftYOffset(): int { return $this->topLeftYOffset; } @@ -518,15 +528,15 @@ class Chart /** * Set the Bottom Right position of the chart. * - * @param string $cell + * @param string $cellAddress * @param int $xOffset * @param int $yOffset * * @return $this */ - public function setBottomRightPosition($cell = '', $xOffset = null, $yOffset = null) + public function setBottomRightPosition($cellAddress = '', $xOffset = null, $yOffset = null) { - $this->bottomRightCellRef = $cell; + $this->bottomRightCellRef = $cellAddress; if ($xOffset !== null) { $this->setBottomRightXOffset($xOffset); } @@ -551,19 +561,22 @@ class Chart ]; } - public function setBottomRightCell($cell) + /** + * Set the Bottom Right cell for the chart. + * + * @return $this + */ + public function setBottomRightCell(string $cellAddress = '') { - $this->bottomRightCellRef = $cell; + $this->bottomRightCellRef = $cellAddress; return $this; } /** * Get the cell address where the bottom right of the chart is fixed. - * - * @return string */ - public function getBottomRightCell() + public function getBottomRightCell(): string { return $this->bottomRightCellRef; } @@ -602,6 +615,11 @@ class Chart ]; } + /** + * @param int $xOffset + * + * @return $this + */ public function setBottomRightXOffset($xOffset) { $this->bottomRightXOffset = $xOffset; @@ -609,11 +627,16 @@ class Chart return $this; } - public function getBottomRightXOffset() + public function getBottomRightXOffset(): int { return $this->bottomRightXOffset; } + /** + * @param int $yOffset + * + * @return $this + */ public function setBottomRightYOffset($yOffset) { $this->bottomRightYOffset = $yOffset; @@ -621,7 +644,7 @@ class Chart return $this; } - public function getBottomRightYOffset() + public function getBottomRightYOffset(): int { return $this->bottomRightYOffset; } From a33ed026e9aa48e342be14e5dcaa31ab2415bc79 Mon Sep 17 00:00:00 2001 From: MarkBaker Date: Mon, 16 May 2022 16:35:35 +0200 Subject: [PATCH 4/7] Update Change Log --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f60d7425..128e1d68 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,12 +10,13 @@ and this project adheres to [Semantic Versioning](https://semver.org). ### Added - Add point size option for scatter charts +- Basic support for Xlsx reading/writing Chart Sheets [PR #2830](https://github.com/PHPOffice/PhpSpreadsheet/pull/2830) ### Changed - Memory and speed improvements, particularly for the Cell Collection, and the Writers. - See [the Discussion](https://github.com/PHPOffice/PhpSpreadsheet/discussions/2821) for details of performance + See [the Discussion section on github](https://github.com/PHPOffice/PhpSpreadsheet/discussions/2821) for details of performance across versions ### Deprecated From c66baa44ea262af11452fb0bef54bc812edf8202 Mon Sep 17 00:00:00 2001 From: MarkBaker Date: Tue, 17 May 2022 15:31:29 +0200 Subject: [PATCH 5/7] Update Change Log --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 70986645..a53df5cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](https://semver.org). - Add point size option for scatter charts - Basic support for Xlsx reading/writing Chart Sheets [PR #2830](https://github.com/PHPOffice/PhpSpreadsheet/pull/2830) + Note that a ChartSheet is still only written as a normal Worksheet containing a single chart, not as an actual ChartSheet. + ### Changed - Memory and speed improvements, particularly for the Cell Collection, and the Writers. From e02f25bf48eaf9eff4088dc37142326355a81057 Mon Sep 17 00:00:00 2001 From: MarkBaker Date: Tue, 17 May 2022 15:44:24 +0200 Subject: [PATCH 6/7] Update listWorksheetNames() and listWorksheetInfo() to accept ChartSheet information --- src/PhpSpreadsheet/Reader/Xlsx.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/PhpSpreadsheet/Reader/Xlsx.php b/src/PhpSpreadsheet/Reader/Xlsx.php index 2068e950..ecae5ad7 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx.php +++ b/src/PhpSpreadsheet/Reader/Xlsx.php @@ -226,7 +226,10 @@ class Xlsx extends BaseReader $worksheets = []; foreach ($relsWorkbook->Relationship as $elex) { $ele = self::getAttributes($elex); - if ((string) $ele['Type'] === "$namespace/worksheet") { + if ( + ((string) $ele['Type'] === "$namespace/worksheet") || + ((string) $ele['Type'] === "$namespace/chartsheet") + ) { $worksheets[(string) $ele['Id']] = $ele['Target']; } } From b4ba57acaad981c717e028d710e3b96a5d355047 Mon Sep 17 00:00:00 2001 From: MarkBaker Date: Tue, 17 May 2022 15:57:23 +0200 Subject: [PATCH 7/7] Unit tests for listWorksheetNames() and listWorksheetInfo() with a ChartSheet --- .../Reader/Xlsx/WorksheetInfoNamesTest.php | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/PhpSpreadsheetTests/Reader/Xlsx/WorksheetInfoNamesTest.php b/tests/PhpSpreadsheetTests/Reader/Xlsx/WorksheetInfoNamesTest.php index ed01db25..cc2269b2 100644 --- a/tests/PhpSpreadsheetTests/Reader/Xlsx/WorksheetInfoNamesTest.php +++ b/tests/PhpSpreadsheetTests/Reader/Xlsx/WorksheetInfoNamesTest.php @@ -77,4 +77,29 @@ class WorksheetInfoNamesTest extends TestCase self::assertEquals($expected, $actual); } + + public function testListWorksheetNamesChartSheet(): void + { + $filename = 'tests/data/Reader/XLSX/ChartSheet.xlsx'; + $reader = new Xlsx(); + $actual = $reader->listWorksheetNames($filename); + + $expected = ['Sheet1', 'Chart1']; + + self::assertEquals($expected, $actual); + } + + public function testListWorksheetInfoChartSheet(): void + { + $filename = 'tests/data/Reader/XLSX/ChartSheet.xlsx'; + $reader = new Xlsx(); + $actual = $reader->listWorksheetInfo($filename); + + $chartSheetInfo = $actual[1]; + + self::assertSame('Chart1', $chartSheetInfo['worksheetName']); + self::assertSame(-1, $chartSheetInfo['lastColumnIndex']); + self::assertSame(0, $chartSheetInfo['totalRows']); + self::assertSame(0, $chartSheetInfo['totalColumns']); + } }