From 5cf5b391b648290996beb3548d3cb9e0cef151c9 Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Wed, 15 Mar 2023 21:23:05 -0700 Subject: [PATCH] Xlsx Writer Honor Alignment in Default Font Fix #3443. A mysterious implementation by Excel. The style tags have an attribute applyAlignment, which nominally says whether or not the style should use its own Alignment. Except ... Excel ignores that attribute and uses the alignment tag if it is supplied ... and, another mystery, uses not the default style for the spreadsheet if not supplied, but rather uses the default alignment style for all spreadsheets even if the spreadsheet's default style uses a non-default alignment. I am changing Xlsx Writer to generate alignment tag unless the alignment matches both the default alignment for the spreadsheet and the default alignment for all spreadsheets (which I expect to happen most of the time). --- src/PhpSpreadsheet/Writer/Xlsx/Style.php | 14 ++- .../Writer/Xlsx/Issue3443Test.php | 98 +++++++++++++++++++ 2 files changed, 109 insertions(+), 3 deletions(-) create mode 100644 tests/PhpSpreadsheetTests/Writer/Xlsx/Issue3443Test.php diff --git a/src/PhpSpreadsheet/Writer/Xlsx/Style.php b/src/PhpSpreadsheet/Writer/Xlsx/Style.php index 0261f22e56..cbc2773a8d 100644 --- a/src/PhpSpreadsheet/Writer/Xlsx/Style.php +++ b/src/PhpSpreadsheet/Writer/Xlsx/Style.php @@ -112,8 +112,10 @@ public function writeStyles(Spreadsheet $spreadsheet) $objWriter->writeAttribute('count', (string) count($spreadsheet->getCellXfCollection())); // xf + $alignment = new Alignment(); + $defaultAlignHash = $alignment->getHashCode(); foreach ($spreadsheet->getCellXfCollection() as $cellXf) { - $this->writeCellStyleXf($objWriter, $cellXf, $spreadsheet); + $this->writeCellStyleXf($objWriter, $cellXf, $spreadsheet, $defaultAlignHash); } $objWriter->endElement(); @@ -400,7 +402,7 @@ private function writeBorder(XMLWriter $objWriter, Borders $borders): void /** * Write Cell Style Xf. */ - private function writeCellStyleXf(XMLWriter $objWriter, \PhpOffice\PhpSpreadsheet\Style\Style $style, Spreadsheet $spreadsheet): void + private function writeCellStyleXf(XMLWriter $objWriter, \PhpOffice\PhpSpreadsheet\Style\Style $style, Spreadsheet $spreadsheet, string $defaultAlignHash): void { // xf $objWriter->startElement('xf'); @@ -424,7 +426,13 @@ private function writeCellStyleXf(XMLWriter $objWriter, \PhpOffice\PhpSpreadshee $objWriter->writeAttribute('applyNumberFormat', ($spreadsheet->getDefaultStyle()->getNumberFormat()->getHashCode() != $style->getNumberFormat()->getHashCode()) ? '1' : '0'); $objWriter->writeAttribute('applyFill', ($spreadsheet->getDefaultStyle()->getFill()->getHashCode() != $style->getFill()->getHashCode()) ? '1' : '0'); $objWriter->writeAttribute('applyBorder', ($spreadsheet->getDefaultStyle()->getBorders()->getHashCode() != $style->getBorders()->getHashCode()) ? '1' : '0'); - $applyAlignment = ($spreadsheet->getDefaultStyle()->getAlignment()->getHashCode() != $style->getAlignment()->getHashCode()) ? '1' : '0'; + $applyAlignment = '1'; + $defaultStyleAlignHash = $spreadsheet->getDefaultStyle()->getAlignment()->getHashCode(); + if ($defaultStyleAlignHash === $style->getAlignment()->getHashCode()) { + if ($defaultStyleAlignHash === $defaultAlignHash) { + $applyAlignment = '0'; + } + } $objWriter->writeAttribute('applyAlignment', $applyAlignment); if ($style->getProtection()->getLocked() != Protection::PROTECTION_INHERIT || $style->getProtection()->getHidden() != Protection::PROTECTION_INHERIT) { $objWriter->writeAttribute('applyProtection', 'true'); diff --git a/tests/PhpSpreadsheetTests/Writer/Xlsx/Issue3443Test.php b/tests/PhpSpreadsheetTests/Writer/Xlsx/Issue3443Test.php new file mode 100644 index 0000000000..471c9ab384 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Writer/Xlsx/Issue3443Test.php @@ -0,0 +1,98 @@ + [ + 'horizontal' => Alignment::HORIZONTAL_CENTER, + 'vertical' => Alignment::VERTICAL_CENTER, + 'wrapText' => true, + ], + 'font' => [ + 'name' => 'Courier New', + ], + ]; + $spreadsheet->getDefaultStyle()->applyFromArray($styleArray); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->getCell('A1')->setValue(1); + $sheet->getCell('A2')->setValue(2); + $sheet->getCell('A3')->setValue(3); + $sheet->getStyle('A2')->getAlignment()->setHorizontal(Alignment::HORIZONTAL_LEFT); + $sheet->getStyle('A3')->getFont()->setName('Tahoma'); + + $reloadedSpreadsheet = $this->writeAndReload($spreadsheet, 'Xlsx'); + $spreadsheet->disconnectWorksheets(); + $rsheet = $reloadedSpreadsheet->getActiveSheet(); + $expected1 = [ + 'horizontal' => 'center', + 'indent' => 0, + 'readOrder' => 0, + 'shrinkToFit' => false, + 'textRotation' => 0, + 'vertical' => 'center', + 'wrapText' => true, + ]; + self::assertSame($expected1, $rsheet->getStyle('A1')->getAlignment()->exportArray()); + $expected2 = $expected1; + $expected2['horizontal'] = 'left'; + self::assertSame($expected2, $rsheet->getStyle('A2')->getAlignment()->exportArray()); + self::assertSame($expected1, $rsheet->getStyle('A3')->getAlignment()->exportArray()); + self::assertSame('Courier New', $rsheet->getStyle('A1')->getFont()->getName()); + self::assertSame('Courier New', $rsheet->getStyle('A2')->getFont()->getName()); + self::assertSame('Tahoma', $rsheet->getStyle('A3')->getFont()->getName()); + + $reloadedSpreadsheet->disconnectWorksheets(); + } + + public function testDefaultAlign(): void + { + // Issue 3443 - default alignment not honored. + $spreadsheet = new Spreadsheet(); + $styleArray = [ + 'font' => [ + 'name' => 'Courier New', + ], + ]; + $spreadsheet->getDefaultStyle()->applyFromArray($styleArray); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->getCell('A1')->setValue(1); + $sheet->getCell('A2')->setValue(2); + $sheet->getCell('A3')->setValue(3); + $sheet->getStyle('A2')->getAlignment()->setHorizontal(Alignment::HORIZONTAL_LEFT); + $sheet->getStyle('A3')->getFont()->setName('Tahoma'); + + $reloadedSpreadsheet = $this->writeAndReload($spreadsheet, 'Xlsx'); + $spreadsheet->disconnectWorksheets(); + $rsheet = $reloadedSpreadsheet->getActiveSheet(); + $expected1 = [ + 'horizontal' => '', + 'indent' => 0, + 'readOrder' => 0, + 'shrinkToFit' => false, + 'textRotation' => 0, + 'vertical' => '', + 'wrapText' => false, + ]; + self::assertSame($expected1, $rsheet->getStyle('A1')->getAlignment()->exportArray()); + $expected2 = $expected1; + $expected2['horizontal'] = 'left'; + $expected2['vertical'] = 'bottom'; + self::assertSame($expected2, $rsheet->getStyle('A2')->getAlignment()->exportArray()); + self::assertSame($expected1, $rsheet->getStyle('A3')->getAlignment()->exportArray()); + self::assertSame('Courier New', $rsheet->getStyle('A1')->getFont()->getName()); + self::assertSame('Courier New', $rsheet->getStyle('A2')->getFont()->getName()); + self::assertSame('Tahoma', $rsheet->getStyle('A3')->getFont()->getName()); + + $reloadedSpreadsheet->disconnectWorksheets(); + } +}