diff --git a/docs/_pages/documentation.md b/docs/_pages/documentation.md new file mode 100755 index 00000000..30d9cf52 --- /dev/null +++ b/docs/_pages/documentation.md @@ -0,0 +1,325 @@ +--- +layout: doc +title: Documentation +permalink: /docs/ +--- + +## Configuration for CSV + +It is possible to configure both the CSV reader and writer to adapt them to your requirements: + +```php +use Box\Spout\Reader\Common\Creator\ReaderEntityFactory; + +$reader = ReaderEntityFactory::createReaderFromFile('/path/to/file.csv'); +/** All of these methods have to be called before opening the reader. */ +$reader->setFieldDelimiter('|'); +$reader->setFieldEnclosure('@'); + +``` + +Additionally, if you need to read non UTF-8 files, you can specify the encoding of your file this way: + +```php +$reader->setEncoding('UTF-16LE'); +``` + +By default, the writer generates CSV files encoded in UTF-8, with a BOM. +It is however possible to not include the BOM: + +```php +use Box\Spout\Writer\Common\Creator\WriterEntityFactory; + +$writer = WriterEntityFactory::createWriterFromFile('/path/to/file.csv'); +$writer->setShouldAddBOM(false); +``` + + +## Configuration for XLSX and ODS + +### New sheet creation + +It is possible to change the behavior of the writers when the maximum number of rows (*1,048,576*) has been written in the current sheet. By default, a new sheet is automatically created so that writing can keep going but that may not always be preferable. + +```php + +use Box\Spout\Writer\Common\Creator\WriterEntityFactory; + +$writer = WriterEntityFactory::createODSWriter(); +$writer->setShouldCreateNewSheetsAutomatically(true); // default value +$writer->setShouldCreateNewSheetsAutomatically(false); // will stop writing new data when limit is reached +``` + +### Using a custom temporary folder + +Processing XLSX and ODS files requires temporary files to be created. By default, {{ site.spout_html }} will use the system default temporary folder (as returned by `sys_get_temp_dir()`). It is possible to override this by explicitly setting it on the reader or writer: + +```php +use Box\Spout\Writer\Common\Creator\WriterEntityFactory; + +$writer = WriterEntityFactory::createXLSXWriter(); +$writer->setTempFolder($customTempFolderPath); +``` + +### Strings storage (XLSX writer) + +XLSX files support different ways to store the string values: +* Shared strings are meant to optimize file size by separating strings from the sheet representation and ignoring strings duplicates (if a string is used three times, only one string will be stored) +* Inline strings are less optimized (as duplicate strings are all stored) but is faster to process + +In order to keep the memory usage really low, {{ site.spout_html }} does not de-duplicate strings when using shared strings. It is nevertheless possible to use this mode. + +```php +use Box\Spout\Writer\Common\Creator\WriterEntityFactory; + +$writer = WriterEntityFactory::createXLSXWriter(); +$writer->setShouldUseInlineStrings(true); // default (and recommended) value +$writer->setShouldUseInlineStrings(false); // will use shared strings +``` + +> #### Note on Apple Numbers and iOS support +> +> Apple's products (Numbers and the iOS previewer) don't support inline strings and display empty cells instead. Therefore, if these platforms need to be supported, make sure to use shared strings! + +### Date/Time formatting + +When reading a spreadsheet containing dates or times, {{ site.spout_html }} returns the values by default as `DateTime` objects. +It is possible to change this behavior and have a formatted date returned instead (e.g. "2016-11-29 1:22 AM"). The format of the date corresponds to what is specified in the spreadsheet. + +```php +use Box\Spout\Reader\Common\Creator\ReaderEntityFactory; + +$reader = ReaderEntityFactory::createXLSXReader(); +$reader->setShouldFormatDates(false); // default value +$reader->setShouldFormatDates(true); // will return formatted dates +``` + + +## Empty rows + +By default, when {{ site.spout_html }} reads a spreadsheet it skips empty rows and only return rows containing data. +This behavior can be changed so that {{ site.spout_html }} returns all rows: + +```php +use Box\Spout\Reader\Common\Creator\ReaderEntityFactory; + +$reader = ReaderEntityFactory::createReaderFromFile('/path/to/file.ext'); +$reader->setShouldPreserveEmptyRows(true); +``` + + +## Styling + +### Available styles + +{{ site.spout_html }} supports styling at a row and cell level. It is possible to customize the fonts, backgrounds, alignment as well as borders. + +For fonts and alignments, {{ site.spout_html }} does not support all the possible formatting options yet. But you can find the most important ones: + +| Category | Property | API +|:---------------------|:------------------------|:-------------------------------------- +| Font | Bold | `StyleBuilder::setFontBold()` +| | Italic | `StyleBuilder::setFontItalic()` +| | Underline | `StyleBuilder::setFontUnderline()` +| | Strikethrough | `StyleBuilder::setFontStrikethrough()` +| | Font name | `StyleBuilder::setFontName('Arial')` +| | Font size | `StyleBuilder::setFontSize(14)` +| | Font color | `StyleBuilder::setFontColor(Color::BLUE)`
`StyleBuilder::setFontColor(Color::rgb(0, 128, 255))` +| Alignment | Cell alignment | `StyleBuilder::setCellAlignment(CellAlignment::CENTER)` +| | Cell vertical alignment | `StyleBuilder::setCellVerticalAlignment(CellVerticalAlignment::CENTER)` +| | Wrap text | `StyleBuilder::setShouldWrapText(true)` +| Format _(XLSX only)_ | Number format | `StyleBuilder::setFormat('0.000')` +| | Date format | `StyleBuilder::setFormat('m/d/yy h:mm')` + +### Styling rows + +It is possible to apply some formatting options to a row. In this case, all cells of the row will have the same style: + +```php +use Box\Spout\Writer\Common\Creator\WriterEntityFactory; +use Box\Spout\Writer\Common\Creator\Style\StyleBuilder; +use Box\Spout\Common\Entity\Style\CellAlignment; +use Box\Spout\Common\Entity\Style\Color; + +$writer = WriterEntityFactory::createXLSXWriter(); +$writer->openToFile($filePath); + +/** Create a style with the StyleBuilder */ +$style = (new StyleBuilder()) + ->setFontBold() + ->setFontSize(15) + ->setFontColor(Color::BLUE) + ->setShouldWrapText() + ->setCellAlignment(CellAlignment::RIGHT) + ->setCellVerticalAlignment(CellVerticalAlignment::BOTTOM) + ->setBackgroundColor(Color::YELLOW) + ->build(); + +/** Create a row with cells and apply the style to all cells */ +$row = WriterEntityFactory::createRowFromArray(['Carl', 'is', 'great'], $style); + +/** Add the row to the writer */ +$writer->addRow($row); +$writer->close(); +``` + +Adding borders to a row requires a ```Border``` object. + +```php +use Box\Spout\Common\Entity\Style\Border; +use Box\Spout\Writer\Common\Creator\Style\BorderBuilder; +use Box\Spout\Common\Entity\Style\Color; +use Box\Spout\Writer\Common\Creator\Style\StyleBuilder; +use Box\Spout\Writer\Common\Creator\WriterEntityFactory; + +$border = (new BorderBuilder()) + ->setBorderBottom(Color::GREEN, Border::WIDTH_THIN, Border::STYLE_DASHED) + ->build(); + +$style = (new StyleBuilder()) + ->setBorder($border) + ->build(); + +$writer = WriterEntityFactory::createXLSXWriter(); +$writer->openToFile($filePath); + +$cells = WriterEntityFactory::createCell('Border Bottom Green Thin Dashed'); +$row = WriterEntityFactory::createRow($cells); +$row->setStyle($style); +$writer->addRow($row); + +$writer->close(); +``` + +### Styling cells + +The same styling techniques as described in [Styling rows](#styling-rows) can be applied to individual cells of a row as well. + +Cell styles are inherited from the parent row and the default row style respectively. + +The styles applied to a specific cell will override any parent styles if present. + +Example: + +```php +use Box\Spout\Common\Entity\Style\Color; +use Box\Spout\Writer\Common\Creator\Style\StyleBuilder; +use Box\Spout\Writer\Common\Creator\WriterEntityFactory; + +$defaultStyle = (new StyleBuilder()) + ->setFontSize(8) + ->build(); + +$writer = WriterEntityFactory::createXLSXWriter(); +$writer->setDefaultRowStyle($defaultStyle) + ->openToFile($filePath); + +$zebraBlackStyle = (new StyleBuilder()) + ->setBackgroundColor(Color::BLACK) + ->setFontColor(Color::WHITE) + ->setFontSize(10) + ->build(); + +$zebraWhiteStyle = (new StyleBuilder()) + ->setBackgroundColor(Color::WHITE) + ->setFontColor(Color::BLACK) + ->setFontItalic() + ->build(); + +$cells = [ + WriterEntityFactory::createCell('Ze', $zebraBlackStyle), + WriterEntityFactory::createCell('bra', $zebraWhiteStyle) +]; + +$rowStyle = (new StyleBuilder()) + ->setFontBold() + ->build(); + +$row = WriterEntityFactory::createRow($cells, $rowStyle); + +$writer->addRow($row); +$writer->close(); +``` + +### Default style + +{{ site.spout_html }} will use a default style for all created rows. This style can be overridden this way: + +```php +$defaultStyle = (new StyleBuilder()) + ->setFontName('Arial') + ->setFontSize(11) + ->build(); + +$writer = WriterEntityFactory::createXLSXWriter(); +$writer->setDefaultRowStyle($defaultStyle) + ->openToFile($filePath); +``` + + +## Playing with sheets + +When creating a XLSX or ODS file, it is possible to control which sheet the data will be written into. At any time, you can retrieve or set the current sheet: + +```php +$firstSheet = $writer->getCurrentSheet(); +$writer->addRow($rowForSheet1); // writes the row to the first sheet + +$newSheet = $writer->addNewSheetAndMakeItCurrent(); +$writer->addRow($rowForSheet2); // writes the row to the new sheet + +$writer->setCurrentSheet($firstSheet); +$writer->addRow($anotherRowForSheet1); // append the row to the first sheet +``` + +It is also possible to retrieve all the sheets currently created: +```php +$sheets = $writer->getSheets(); +``` + +It is possible to retrieve some sheet's attributes when reading: +```php +foreach ($reader->getSheetIterator() as $sheet) { + $sheetName = $sheet->getName(); + $isSheetVisible = $sheet->isVisible(); + $isSheetActive = $sheet->isActive(); // active sheet when spreadsheet last saved +} +``` + +If you rely on the sheet's name in your application, you can customize it this way: + +```php +// Accessing the sheet name when writing +$sheet = $writer->getCurrentSheet(); +$sheetName = $sheet->getName(); + +// Customizing the sheet name when writing +$sheet = $writer->getCurrentSheet(); +$sheet->setName('My custom name'); +``` + +> Please note that Excel has some restrictions on the sheet's name: +> * it must not be blank +> * it must not exceed 31 characters +> * it must not contain these characters: \ / ? * : [ or ] +> * it must not start or end with a single quote +> * it must be unique +> +> Handling these restrictions is the developer's responsibility. {{ site.spout_html }} does not try to automatically change the sheet's name, as one may rely on this name to be exactly what was passed in. + + +## Fluent interface + +Because fluent interfaces are great, you can use them with {{ site.spout_html }}: + +```php +use Box\Spout\Writer\WriterEntityFactory; + +$writer = WriterEntityFactory::createWriterFromFile('path/to/file.ext'); +$writer->setTempFolder($customTempFolderPath) + ->setShouldUseInlineStrings(true) + ->openToFile($filePath) + ->addRow($headerRow) + ->addRows($dataRows) + ->close(); +``` diff --git a/src/Common/Entity/Style/CellVerticalAlignment.php b/src/Common/Entity/Style/CellVerticalAlignment.php new file mode 100644 index 00000000..107cab01 --- /dev/null +++ b/src/Common/Entity/Style/CellVerticalAlignment.php @@ -0,0 +1,36 @@ + 1, + self::BASELINE => 1, + self::BOTTOM => 1, + self::CENTER => 1, + self::DISTRIBUTED => 1, + self::JUSTIFY => 1, + self::TOP => 1, + ]; + + /** + * @return bool Whether the given cell vertical alignment is valid + */ + public static function isValid(string $cellVerticalAlignment): bool + { + return isset(self::$VALID_ALIGNMENTS[$cellVerticalAlignment]); + } +} diff --git a/src/Common/Entity/Style/Style.php b/src/Common/Entity/Style/Style.php index 955950c4..e4921dfa 100644 --- a/src/Common/Entity/Style/Style.php +++ b/src/Common/Entity/Style/Style.php @@ -4,6 +4,7 @@ namespace OpenSpout\Common\Entity\Style; +use Box\Spout\Common\Entity\Style\CellVerticalAlignment; use OpenSpout\Common\Exception\InvalidArgumentException; /** @@ -75,6 +76,15 @@ final class Style /** @var bool Whether the cell alignment property was set */ private bool $hasSetCellAlignment = false; + /** @var bool Whether specific cell vertical alignment should be applied */ + private bool $shouldApplyCellVerticalAlignment = false; + + /** @var string Cell vertical alignment */ + private string $cellVerticalAlignment; + + /** @var bool Whether the cell vertical alignment property was set */ + private bool $hasSetCellVerticalAlignment = false; + /** @var bool Whether the text should wrap in the cell (useful for long or multi-lines text) */ private bool $shouldWrapText = false; @@ -290,6 +300,11 @@ public function getCellAlignment(): string return $this->cellAlignment; } + public function getCellVerticalAlignment(): string + { + return $this->cellVerticalAlignment; + } + /** * @param string $cellAlignment The cell alignment */ @@ -307,11 +322,33 @@ public function setCellAlignment(string $cellAlignment): self return $this; } + /** + * @param string $cellVerticalAlignment The cell vertical alignment + */ + public function setCellVerticalAlignment(string $cellVerticalAlignment): self + { + if (!CellVerticalAlignment::isValid($cellVerticalAlignment)) { + throw new InvalidArgumentException('Invalid cell vertical alignment value'); + } + + $this->cellVerticalAlignment = $cellVerticalAlignment; + $this->hasSetCellVerticalAlignment = true; + $this->shouldApplyCellVerticalAlignment = true; + $this->isEmpty = false; + + return $this; + } + public function hasSetCellAlignment(): bool { return $this->hasSetCellAlignment; } + public function hasSetCellVerticalAlignment(): bool + { + return $this->hasSetCellVerticalAlignment; + } + /** * @return bool Whether specific cell alignment should be applied */ @@ -320,6 +357,11 @@ public function shouldApplyCellAlignment(): bool return $this->shouldApplyCellAlignment; } + public function shouldApplyCellVerticalAlignment(): bool + { + return $this->shouldApplyCellVerticalAlignment; + } + public function shouldWrapText(): bool { return $this->shouldWrapText; diff --git a/src/Writer/Common/Manager/Style/StyleMerger.php b/src/Writer/Common/Manager/Style/StyleMerger.php index 726b405c..eb9fe244 100644 --- a/src/Writer/Common/Manager/Style/StyleMerger.php +++ b/src/Writer/Common/Manager/Style/StyleMerger.php @@ -72,8 +72,8 @@ private function mergeOtherFontProperties(Style $styleToUpdate, Style $style, St */ private function mergeCellProperties(Style $styleToUpdate, Style $style, Style $baseStyle): void { - if (!$style->hasSetWrapText() && $baseStyle->shouldWrapText()) { - $styleToUpdate->setShouldWrapText(); + if (!$style->hasSetWrapText() && $baseStyle->hasSetWrapText()) { + $styleToUpdate->setShouldWrapText($baseStyle->shouldWrapText()); } if (!$style->hasSetShrinkToFit() && $baseStyle->shouldShrinkToFit()) { $styleToUpdate->setShouldShrinkToFit(); @@ -81,6 +81,9 @@ private function mergeCellProperties(Style $styleToUpdate, Style $style, Style $ if (!$style->hasSetCellAlignment() && $baseStyle->shouldApplyCellAlignment()) { $styleToUpdate->setCellAlignment($baseStyle->getCellAlignment()); } + if (!$style->hasSetCellVerticalAlignment() && $baseStyle->shouldApplyCellVerticalAlignment()) { + $styleToUpdate->setCellVerticalAlignment($baseStyle->getCellVerticalAlignment()); + } if (null === $style->getBorder() && null !== ($border = $baseStyle->getBorder())) { $styleToUpdate->setBorder($border); } diff --git a/src/Writer/ODS/Manager/Style/StyleManager.php b/src/Writer/ODS/Manager/Style/StyleManager.php index 6b5545e2..795c2897 100644 --- a/src/Writer/ODS/Manager/Style/StyleManager.php +++ b/src/Writer/ODS/Manager/Style/StyleManager.php @@ -4,6 +4,7 @@ namespace OpenSpout\Writer\ODS\Manager\Style; +use Box\Spout\Common\Entity\Style\CellVerticalAlignment; use OpenSpout\Common\Entity\Style\Border; use OpenSpout\Common\Entity\Style\BorderPart; use OpenSpout\Common\Entity\Style\CellAlignment; @@ -316,12 +317,13 @@ private function getFontSectionContent(Style $style): string */ private function getParagraphPropertiesSectionContent(Style $style): string { - if (!$style->shouldApplyCellAlignment()) { + if (!$style->shouldApplyCellAlignment() && !$style->shouldApplyCellVerticalAlignment()) { return ''; } return 'getCellAlignmentSectionContent($style) + . $this->getCellVerticalAlignmentSectionContent($style) .'/>'; } @@ -335,6 +337,16 @@ private function getCellAlignmentSectionContent(Style $style): string $this->transformCellAlignment($style->getCellAlignment()) ); } + /** + * Returns the contents of the cell vertical alignment definition for the "" section + */ + private function getCellVerticalAlignmentSectionContent(Style $style): string + { + return \sprintf( + ' fo:vertical-align="%s" ', + $this->transformCellVerticalAlignment($style->getCellVerticalAlignment()) + ); + } /** * Even though "left" and "right" alignments are part of the spec, and interpreted @@ -349,6 +361,17 @@ private function transformCellAlignment(string $cellAlignment): string default => $cellAlignment, }; } + + /** + * Spec uses 'middle' rather than 'center' + * http://docs.oasis-open.org/office/v1.2/os/OpenDocument-v1.2-os-part1.html#__RefHeading__1420236_253892949 + */ + private function transformCellVerticalAlignment(string $cellVerticalAlignment): string + { + return ($cellVerticalAlignment === CellVerticalAlignment::CENTER) + ? 'middle' + : $cellVerticalAlignment; + } /** * Returns the contents of the "" section, inside "" section. @@ -357,8 +380,8 @@ private function getTableCellPropertiesSectionContent(Style $style): string { $content = 'shouldWrapText()) { - $content .= $this->getWrapTextXMLContent(); + if ($style->hasSetWrapText()) { + $content .= $this->getWrapTextXMLContent($style->shouldWrapText()); } if (null !== ($border = $style->getBorder())) { @@ -377,9 +400,9 @@ private function getTableCellPropertiesSectionContent(Style $style): string /** * Returns the contents of the wrap text definition for the "" section. */ - private function getWrapTextXMLContent(): string + private function getWrapTextXMLContent(bool $shouldWrapText): string { - return ' fo:wrap-option="wrap" style:vertical-align="automatic" '; + return ' fo:wrap-option="' . ($shouldWrapText ? '' : 'no-') . 'wrap" style:vertical-align="automatic" '; } /** diff --git a/src/Writer/XLSX/Manager/Style/StyleManager.php b/src/Writer/XLSX/Manager/Style/StyleManager.php index ab4d656c..ea83d506 100644 --- a/src/Writer/XLSX/Manager/Style/StyleManager.php +++ b/src/Writer/XLSX/Manager/Style/StyleManager.php @@ -238,14 +238,17 @@ private function getCellXfsSectionContent(): string $content .= sprintf(' applyBorder="%d"', (bool) $style->getBorder()); - if ($style->shouldApplyCellAlignment() || $style->shouldWrapText() || $style->shouldShrinkToFit()) { + if ($style->shouldApplyCellAlignment() || $style->shouldApplyCellVerticalAlignment() || $style->hasSetWrapText() || $style->shouldShrinkToFit()) { $content .= ' applyAlignment="1">'; $content .= 'shouldApplyCellAlignment()) { $content .= sprintf(' horizontal="%s"', $style->getCellAlignment()); } - if ($style->shouldWrapText()) { - $content .= ' wrapText="1"'; + if ($style->shouldApplyCellVerticalAlignment()) { + $content .= \sprintf(' vertical="%s"', $style->getCellVerticalAlignment()); + } + if ($style->hasSetWrapText()) { + $content .= ' wrapText="' . ($style->shouldWrapText() ? '1' : '0') . '"'; } if ($style->shouldShrinkToFit()) { $content .= ' shrinkToFit="true"'; diff --git a/tests/Writer/Common/Creator/StyleTest.php b/tests/Writer/Common/Creator/StyleTest.php index dc932844..fc2a7453 100644 --- a/tests/Writer/Common/Creator/StyleTest.php +++ b/tests/Writer/Common/Creator/StyleTest.php @@ -4,6 +4,7 @@ namespace OpenSpout\Writer\Common\Creator\Style; +use Box\Spout\Common\Entity\Style\CellVerticalAlignment; use OpenSpout\Common\Entity\Style\Border; use OpenSpout\Common\Entity\Style\BorderPart; use OpenSpout\Common\Entity\Style\CellAlignment; @@ -46,9 +47,21 @@ public function testStyleBuilderShouldApplyCellAlignment(): void self::assertTrue($style->shouldApplyCellAlignment()); } + public function testStyleBuilderShouldApplyCellVerticalAlignment(): void + { + $style = (new Style())->setCellVerticalAlignment(CellVerticalAlignment::CENTER); + $this->assertTrue($style->shouldApplyCellVerticalAlignment()); + } + public function testStyleBuilderShouldThrowOnInvalidCellAlignment(): void { $this->expectException(InvalidArgumentException::class); (new Style())->setCellAlignment('invalid_cell_alignment'); } + + public function testStyleBuilderShouldThrowOnInvalidCellVerticalAlignment(): void + { + $this->expectException(InvalidArgumentException::class); + (new Style())->setCellVerticalAlignment('invalid_cell_alignment'); + } } diff --git a/tests/Writer/ODS/WriterWithStyleTest.php b/tests/Writer/ODS/WriterWithStyleTest.php index 87e7e4e3..5a2990b3 100644 --- a/tests/Writer/ODS/WriterWithStyleTest.php +++ b/tests/Writer/ODS/WriterWithStyleTest.php @@ -168,6 +168,24 @@ public function testAddRowShouldAddWrapTextAlignmentInfoInStylesXmlFileIfSpecifi $this->assertFirstChildHasAttributeEquals('wrap', $customStyleElement, 'table-cell-properties', 'fo:wrap-option'); } + public function testAddRowShouldAddNegatedWrapTextAlignmentInfoInStylesXmlFileIfSpecified(): void + { + $fileName = 'test_add_row_should_add_negated_wrap_text_alignment.ods'; + + $style = (new Style())->setShouldWrapText(false); + $dataRows = $this->createStyledRowsFromValues([ + ['ods--11', 'ods--12'], + ], $style); + + $this->writeToODSFile($dataRows, $fileName); + + $styleElements = $this->getCellStyleElementsFromContentXmlFile($fileName); + $this->assertCount(2, $styleElements, 'There should be 2 styles (default and custom)'); + + $customStyleElement = $styleElements[1]; + $this->assertFirstChildHasAttributeEquals('no-wrap', $customStyleElement, 'table-cell-properties', 'fo:wrap-option'); + } + public function testAddRowShouldApplyWrapTextIfCellContainsNewLine(): void { $fileName = 'test_add_row_should_apply_wrap_text_if_new_lines.ods'; diff --git a/tests/Writer/XLSX/WriterWithStyleTest.php b/tests/Writer/XLSX/WriterWithStyleTest.php index e14ca248..181bfd0c 100644 --- a/tests/Writer/XLSX/WriterWithStyleTest.php +++ b/tests/Writer/XLSX/WriterWithStyleTest.php @@ -248,6 +248,23 @@ public function testAddRowShouldAddWrapTextAlignmentInfoInStylesXmlFileIfSpecifi $this->assertFirstChildHasAttributeEquals('1', $xfElement, 'alignment', 'wrapText'); } + public function testAddRowShouldAddNegatedWrapTextAlignmentInfoInStylesXmlFileIfSpecified(): void + { + $fileName = 'test_add_row_should_add_negated_wrap_text_alignment.xlsx'; + + $style = (new Style())->setShouldWrapText(false)->; + $dataRows = $this->createStyledRowsFromValues([ + ['xlsx--11', 'xlsx--12'], + ], $style); + + $this->writeToXLSXFile($dataRows, $fileName); + + $cellXfsDomElement = $this->getXmlSectionFromStylesXmlFile($fileName, 'cellXfs'); + $xfElement = $cellXfsDomElement->getElementsByTagName('xf')->item(1); + $this->assertEquals(1, $xfElement->getAttribute('applyAlignment')); + $this->assertFirstChildHasAttributeEquals('0', $xfElement, 'alignment', 'wrapText'); + } + public function testAddRowShouldApplyWrapTextIfCellContainsNewLine(): void { $fileName = 'test_add_row_should_apply_wrap_text_if_new_lines.xlsx';