From 3fae29d6134f42b9b555e6b7ccf17a6eed370532 Mon Sep 17 00:00:00 2001 From: MarkBaker Date: Mon, 23 May 2022 15:30:45 +0200 Subject: [PATCH] Add support for reading Worksheet Visibility for Ods --- CHANGELOG.md | 2 + phpstan-baseline.neon | 25 -------- src/PhpSpreadsheet/Reader/Ods.php | 1 + .../Reader/Ods/PageSettings.php | 47 +++++++++++++++ .../Reader/Ods/HiddenWorksheetTest.php | 57 ++++++++++++++++++ tests/data/Reader/Ods/HiddenSheet.ods | Bin 0 -> 2821 bytes 6 files changed, 107 insertions(+), 25 deletions(-) create mode 100644 tests/PhpSpreadsheetTests/Reader/Ods/HiddenWorksheetTest.php create mode 100644 tests/data/Reader/Ods/HiddenSheet.ods diff --git a/CHANGELOG.md b/CHANGELOG.md index a53df5cf..779f435f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,8 @@ and this project adheres to [Semantic Versioning](https://semver.org). Note that a ChartSheet is still only written as a normal Worksheet containing a single chart, not as an actual ChartSheet. +- Added Worksheet visibility in Ods Reader [PR #2851](https://github.com/PHPOffice/PhpSpreadsheet/pull/2851) + ### Changed - Memory and speed improvements, particularly for the Cell Collection, and the Writers. diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index eabedcc8..ad2777a0 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1945,36 +1945,11 @@ parameters: count: 6 path: src/PhpSpreadsheet/Reader/Ods/PageSettings.php - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Ods\\\\PageSettings\\:\\:\\$masterPrintStylesCrossReference has no type specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Ods/PageSettings.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Ods\\\\PageSettings\\:\\:\\$masterStylesCrossReference has no type specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Ods/PageSettings.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Ods\\\\PageSettings\\:\\:\\$officeNs has no type specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Ods/PageSettings.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Ods\\\\PageSettings\\:\\:\\$pageLayoutStyles has no type specified\\.$#" count: 1 path: src/PhpSpreadsheet/Reader/Ods/PageSettings.php - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Ods\\\\PageSettings\\:\\:\\$stylesFo has no type specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Ods/PageSettings.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Ods\\\\PageSettings\\:\\:\\$stylesNs has no type specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Ods/PageSettings.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Ods\\\\Properties\\:\\:load\\(\\) has parameter \\$namespacesMeta with no type specified\\.$#" count: 1 diff --git a/src/PhpSpreadsheet/Reader/Ods.php b/src/PhpSpreadsheet/Reader/Ods.php index 27c58edb..7e776ab7 100644 --- a/src/PhpSpreadsheet/Reader/Ods.php +++ b/src/PhpSpreadsheet/Reader/Ods.php @@ -588,6 +588,7 @@ class Ods extends BaseReader break; } } + $pageSettings->setVisibilityForWorksheet($spreadsheet->getActiveSheet(), $worksheetStyleName); $pageSettings->setPrintSettingsForWorksheet($spreadsheet->getActiveSheet(), $worksheetStyleName); ++$worksheetID; } diff --git a/src/PhpSpreadsheet/Reader/Ods/PageSettings.php b/src/PhpSpreadsheet/Reader/Ods/PageSettings.php index 8d24fd0c..4d2fd992 100644 --- a/src/PhpSpreadsheet/Reader/Ods/PageSettings.php +++ b/src/PhpSpreadsheet/Reader/Ods/PageSettings.php @@ -8,16 +8,41 @@ use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; class PageSettings { + /** + * @var string + */ private $officeNs; + /** + * @var string + */ private $stylesNs; + /** + * @var string + */ private $stylesFo; + /** + * @var string + */ + private $tableNs; + + /** + * @var string[] + */ + private $tableStylesCrossReference = []; + private $pageLayoutStyles = []; + /** + * @var string[] + */ private $masterStylesCrossReference = []; + /** + * @var string[] + */ private $masterPrintStylesCrossReference = []; public function __construct(DOMDocument $styleDom) @@ -32,6 +57,7 @@ class PageSettings $this->officeNs = $styleDom->lookupNamespaceUri('office'); $this->stylesNs = $styleDom->lookupNamespaceUri('style'); $this->stylesFo = $styleDom->lookupNamespaceUri('fo'); + $this->tableNs = $styleDom->lookupNamespaceUri('table'); } private function readPageSettingStyles(DOMDocument $styleDom): void @@ -98,12 +124,33 @@ class PageSettings foreach ($styleXReferences as $styleXreferenceSet) { $styleXRefName = $styleXreferenceSet->getAttributeNS($this->stylesNs, 'name'); $stylePageLayoutName = $styleXreferenceSet->getAttributeNS($this->stylesNs, 'master-page-name'); + $styleFamilyName = $styleXreferenceSet->getAttributeNS($this->stylesNs, 'family'); + if (!empty($styleFamilyName) && $styleFamilyName === 'table') { + $styleVisibility = 'true'; + foreach ($styleXreferenceSet->getElementsByTagNameNS($this->stylesNs, 'table-properties') as $tableProperties) { + $styleVisibility = $tableProperties->getAttributeNS($this->tableNs, 'display'); + } + $this->tableStylesCrossReference[$styleXRefName] = $styleVisibility; + } if (!empty($stylePageLayoutName)) { $this->masterStylesCrossReference[$styleXRefName] = $stylePageLayoutName; } } } + public function setVisibilityForWorksheet(Worksheet $worksheet, string $styleName): void + { + if (!array_key_exists($styleName, $this->tableStylesCrossReference)) { + return; + } + + $worksheet->setSheetState( + $this->tableStylesCrossReference[$styleName] === 'false' + ? Worksheet::SHEETSTATE_HIDDEN + : Worksheet::SHEETSTATE_VISIBLE + ); + } + public function setPrintSettingsForWorksheet(Worksheet $worksheet, string $styleName): void { if (!array_key_exists($styleName, $this->masterStylesCrossReference)) { diff --git a/tests/PhpSpreadsheetTests/Reader/Ods/HiddenWorksheetTest.php b/tests/PhpSpreadsheetTests/Reader/Ods/HiddenWorksheetTest.php new file mode 100644 index 00000000..9edaa9b7 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Reader/Ods/HiddenWorksheetTest.php @@ -0,0 +1,57 @@ +spreadsheet = $reader->load($filename); + } + + public function testPageSetup(): void + { + $assertions = $this->worksheetAssertions(); + + foreach ($this->spreadsheet->getAllSheets() as $worksheet) { + if (!array_key_exists($worksheet->getTitle(), $assertions)) { + continue; + } + + $sheetAssertions = $assertions[$worksheet->getTitle()]; + foreach ($sheetAssertions as $test => $expectedResult) { + $testMethodName = 'get' . ucfirst($test); + $actualResult = $worksheet->getSheetState(); + self::assertSame( + $expectedResult, + $actualResult, + "Failed asserting sheet state {$expectedResult} for Worksheet '{$worksheet->getTitle()}' {$test}" + ); + } + } + } + + private function worksheetAssertions(): array + { + return [ + 'Sheet1' => [ + 'sheetState' => Worksheet::SHEETSTATE_VISIBLE, + ], + 'Sheet2' => [ + 'sheetState' => Worksheet::SHEETSTATE_HIDDEN, + ], + ]; + } +} diff --git a/tests/data/Reader/Ods/HiddenSheet.ods b/tests/data/Reader/Ods/HiddenSheet.ods new file mode 100644 index 0000000000000000000000000000000000000000..9b1d01a69cfd9833776b874d4ecb1d669a344d79 GIT binary patch literal 2821 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