From a66233b72f4d4859b3e83dcb6d74a39ba8aa1818 Mon Sep 17 00:00:00 2001 From: oleibman Date: Thu, 28 Jan 2021 03:42:41 -0800 Subject: [PATCH] Fix For #1772 Null Exception on ODS Read (#1776) Fix for #1772. Header and Footer Properties may be omitted in Page Setting Style Set. Code changed to allow for this possibility, and tests added. --- .../Reader/Ods/PageSettings.php | 4 +- .../Reader/Ods/PageSetupBug1772Test.php | 98 ++++++++++++++++++ tests/data/Reader/Ods/bug1772.ods | Bin 0 -> 11652 bytes 3 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 tests/PhpSpreadsheetTests/Reader/Ods/PageSetupBug1772Test.php create mode 100644 tests/data/Reader/Ods/bug1772.ods diff --git a/src/PhpSpreadsheet/Reader/Ods/PageSettings.php b/src/PhpSpreadsheet/Reader/Ods/PageSettings.php index 77341aab85..8d24fd0c24 100644 --- a/src/PhpSpreadsheet/Reader/Ods/PageSettings.php +++ b/src/PhpSpreadsheet/Reader/Ods/PageSettings.php @@ -54,10 +54,10 @@ private function readPageSettingStyles(DOMDocument $styleDom): void $marginBottom = $pageLayoutProperties->getAttributeNS($this->stylesFo, 'margin-bottom'); $header = $styleSet->getElementsByTagNameNS($this->stylesNs, 'header-style')[0]; $headerProperties = $header->getElementsByTagNameNS($this->stylesNs, 'header-footer-properties')[0]; - $marginHeader = $headerProperties->getAttributeNS($this->stylesFo, 'min-height'); + $marginHeader = isset($headerProperties) ? $headerProperties->getAttributeNS($this->stylesFo, 'min-height') : null; $footer = $styleSet->getElementsByTagNameNS($this->stylesNs, 'footer-style')[0]; $footerProperties = $footer->getElementsByTagNameNS($this->stylesNs, 'header-footer-properties')[0]; - $marginFooter = $footerProperties->getAttributeNS($this->stylesFo, 'min-height'); + $marginFooter = isset($footerProperties) ? $footerProperties->getAttributeNS($this->stylesFo, 'min-height') : null; $this->pageLayoutStyles[$styleName] = (object) [ 'orientation' => $styleOrientation ?: PageSetup::ORIENTATION_DEFAULT, diff --git a/tests/PhpSpreadsheetTests/Reader/Ods/PageSetupBug1772Test.php b/tests/PhpSpreadsheetTests/Reader/Ods/PageSetupBug1772Test.php new file mode 100644 index 0000000000..883664fc31 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Reader/Ods/PageSetupBug1772Test.php @@ -0,0 +1,98 @@ +spreadsheet = $reader->load($filename); + } + + public function testPageSetup(): void + { + $assertions = $this->pageSetupAssertions(); + + 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->getPageSetup()->$testMethodName(); + self::assertSame( + $expectedResult, + $actualResult, + "Failed assertion for Worksheet '{$worksheet->getTitle()}' {$test}" + ); + } + } + } + + public function testPageMargins(): void + { + $assertions = $this->pageMarginAssertions(); + + 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->getPageMargins()->$testMethodName(); + self::assertEqualsWithDelta( + $expectedResult, + $actualResult, + self::MARGIN_PRECISION, + "Failed assertion for Worksheet '{$worksheet->getTitle()}' {$test} margin" + ); + } + } + } + + private function pageSetupAssertions(): array + { + return [ + 'Employee update template' => [ + 'orientation' => PageSetup::ORIENTATION_DEFAULT, + 'scale' => 100, + 'horizontalCentered' => false, + 'verticalCentered' => false, + 'pageOrder' => PageSetup::PAGEORDER_DOWN_THEN_OVER, + ], + ]; + } + + private function pageMarginAssertions(): array + { + return [ + 'Employee update template' => [ + // Here the values are in cm + 'top' => 0.0, + 'header' => 0.2953, + 'left' => 0.0, + 'right' => 0.0, + 'bottom' => 0.0, + 'footer' => 0.2953, + ], + ]; + } +} diff --git a/tests/data/Reader/Ods/bug1772.ods b/tests/data/Reader/Ods/bug1772.ods new file mode 100644 index 0000000000000000000000000000000000000000..a4a3c2ac582f2baa8f9d6ee6bb9adeba3d783af1 GIT binary patch literal 11652 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 z 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 literal 0 HcmV?d00001