From 3a0ce0e0595442f76a6d3dca88937cbbdf2bd463 Mon Sep 17 00:00:00 2001 From: nartzis Date: Mon, 17 Jan 2022 16:35:35 +0300 Subject: [PATCH] Add column width options --- .gitignore | 1 + src/Spout/Writer/Common/Entity/Options.php | 5 + src/Spout/Writer/Common/Entity/Worksheet.php | 20 +++ .../Writer/Common/Manager/ManagesCellSize.php | 63 +++++++++ .../Manager/WorkbookManagerAbstract.php | 45 ++++++ .../Manager/WorkbookManagerInterface.php | 15 ++ .../Manager/WorksheetManagerInterface.php | 23 +++ .../Writer/ODS/Creator/ManagerFactory.php | 2 +- .../Writer/ODS/Manager/OptionsManager.php | 3 + .../Writer/ODS/Manager/Style/StyleManager.php | 77 +++++++++- .../Writer/ODS/Manager/WorksheetManager.php | 37 ++++- .../Writer/WriterMultiSheetsAbstract.php | 51 ++++++- .../Writer/XLSX/Manager/OptionsManager.php | 3 + .../Writer/XLSX/Manager/WorksheetManager.php | 69 ++++++++- tests/Spout/Writer/ODS/SheetTest.php | 133 +++++++++++++++++- tests/Spout/Writer/XLSX/SheetTest.php | 133 ++++++++++++++++++ 16 files changed, 664 insertions(+), 16 deletions(-) create mode 100644 src/Spout/Writer/Common/Manager/ManagesCellSize.php diff --git a/.gitignore b/.gitignore index cd87038..2b5d2f7 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ *.iml /tests/resources/generated +/tests/**/resources/generated /tests/coverage /vendor /composer.lock diff --git a/src/Spout/Writer/Common/Entity/Options.php b/src/Spout/Writer/Common/Entity/Options.php index fbfa709..fcde238 100644 --- a/src/Spout/Writer/Common/Entity/Options.php +++ b/src/Spout/Writer/Common/Entity/Options.php @@ -20,4 +20,9 @@ abstract class Options // XLSX specific options public const SHOULD_USE_INLINE_STRINGS = 'shouldUseInlineStrings'; + + // Cell size options + const DEFAULT_COLUMN_WIDTH = 'defaultColumnWidth'; + const DEFAULT_ROW_HEIGHT = 'defaultRowHeight'; + const COLUMN_WIDTHS = 'columnWidthDefinition'; } diff --git a/src/Spout/Writer/Common/Entity/Worksheet.php b/src/Spout/Writer/Common/Entity/Worksheet.php index 1e496f0..c41120b 100644 --- a/src/Spout/Writer/Common/Entity/Worksheet.php +++ b/src/Spout/Writer/Common/Entity/Worksheet.php @@ -23,6 +23,9 @@ class Worksheet /** @var int Index of the last written row */ private $lastWrittenRowIndex; + /** @var bool has the sheet data header been written */ + private $sheetDataStarted = false; + /** * Worksheet constructor. * @@ -36,6 +39,7 @@ class Worksheet $this->externalSheet = $externalSheet; $this->maxNumColumns = 0; $this->lastWrittenRowIndex = 0; + $this->sheetDataStarted = false; } /** @@ -110,4 +114,20 @@ class Worksheet // sheet index is zero-based, while ID is 1-based return $this->externalSheet->getIndex() + 1; } + + /** + * @return bool + */ + public function getSheetDataStarted() + { + return $this->sheetDataStarted; + } + + /** + * @param bool $sheetDataStarted + */ + public function setSheetDataStarted($sheetDataStarted) + { + $this->sheetDataStarted = $sheetDataStarted; + } } diff --git a/src/Spout/Writer/Common/Manager/ManagesCellSize.php b/src/Spout/Writer/Common/Manager/ManagesCellSize.php new file mode 100644 index 0000000..8a517f0 --- /dev/null +++ b/src/Spout/Writer/Common/Manager/ManagesCellSize.php @@ -0,0 +1,63 @@ +defaultColumnWidth = $width; + } + + /** + * @param float|null $height + */ + public function setDefaultRowHeight($height) + { + $this->defaultRowHeight = $height; + } + + /** + * @param float $width + * @param array $columns One or more columns with this width + */ + public function setColumnWidth(float $width, ...$columns) + { + // Gather sequences + $sequence = []; + foreach ($columns as $i) { + $sequenceLength = count($sequence); + if ($sequenceLength > 0) { + $previousValue = $sequence[$sequenceLength - 1]; + if ($i !== $previousValue + 1) { + $this->setColumnWidthForRange($width, $sequence[0], $previousValue); + $sequence = []; + } + } + $sequence[] = $i; + } + $this->setColumnWidthForRange($width, $sequence[0], $sequence[count($sequence) - 1]); + } + + /** + * @param float $width The width to set + * @param int $start First column index of the range + * @param int $end Last column index of the range + */ + public function setColumnWidthForRange(float $width, int $start, int $end) + { + $this->columnWidths[] = [$start, $end, $width]; + } +} diff --git a/src/Spout/Writer/Common/Manager/WorkbookManagerAbstract.php b/src/Spout/Writer/Common/Manager/WorkbookManagerAbstract.php index 653778c..c187174 100644 --- a/src/Spout/Writer/Common/Manager/WorkbookManagerAbstract.php +++ b/src/Spout/Writer/Common/Manager/WorkbookManagerAbstract.php @@ -157,6 +157,16 @@ abstract class WorkbookManagerAbstract implements WorkbookManagerInterface return $this->currentWorksheet; } + /** + * Starts the current sheet and opens the file pointer + * + * @throws IOException + */ + public function startCurrentSheet() + { + $this->worksheetManager->startSheet($this->getCurrentWorksheet()); + } + /** * Sets the given sheet as the current one. New data will be written to this sheet. * The writing will resume where it stopped (i.e. data won't be truncated). @@ -276,6 +286,41 @@ abstract class WorkbookManagerAbstract implements WorkbookManagerInterface } } + /** + * @param float $width + */ + public function setDefaultColumnWidth(float $width) + { + $this->worksheetManager->setDefaultColumnWidth($width); + } + + /** + * @param float $height + */ + public function setDefaultRowHeight(float $height) + { + $this->worksheetManager->setDefaultRowHeight($height); + } + + /** + * @param float $width + * @param array $columns One or more columns with this width + */ + public function setColumnWidth(float $width, ...$columns) + { + $this->worksheetManager->setColumnWidth($width, ...$columns); + } + + /** + * @param float $width The width to set + * @param int $start First column index of the range + * @param int $end Last column index of the range + */ + public function setColumnWidthForRange(float $width, int $start, int $end) + { + $this->worksheetManager->setColumnWidthForRange($width, $start, $end); + } + /** * Closes the workbook and all its associated sheets. * All the necessary files are written to disk and zipped together to create the final file. diff --git a/src/Spout/Writer/Common/Manager/WorkbookManagerInterface.php b/src/Spout/Writer/Common/Manager/WorkbookManagerInterface.php index aed304a..7bb469e 100644 --- a/src/Spout/Writer/Common/Manager/WorkbookManagerInterface.php +++ b/src/Spout/Writer/Common/Manager/WorkbookManagerInterface.php @@ -42,6 +42,21 @@ interface WorkbookManagerInterface */ public function getCurrentWorksheet(); + /** + * Starts the current sheet and opens its file pointer + */ + public function startCurrentSheet(); + + /** + * @param float $width + */ + public function setDefaultColumnWidth(float $width); + + /** + * @param float $height + */ + public function setDefaultRowHeight(float $height); + /** * Sets the given sheet as the current one. New data will be written to this sheet. * The writing will resume where it stopped (i.e. data won't be truncated). diff --git a/src/Spout/Writer/Common/Manager/WorksheetManagerInterface.php b/src/Spout/Writer/Common/Manager/WorksheetManagerInterface.php index bb54ee6..bb6758a 100644 --- a/src/Spout/Writer/Common/Manager/WorksheetManagerInterface.php +++ b/src/Spout/Writer/Common/Manager/WorksheetManagerInterface.php @@ -11,6 +11,29 @@ use Box\Spout\Writer\Common\Entity\Worksheet; */ interface WorksheetManagerInterface { + /** + * @param float|null $width + */ + public function setDefaultColumnWidth($width); + + /** + * @param float|null $height + */ + public function setDefaultRowHeight($height); + + /** + * @param float $width + * @param array $columns One or more columns with this width + */ + public function setColumnWidth(float $width, ...$columns); + + /** + * @param float $width The width to set + * @param int $start First column index of the range + * @param int $end Last column index of the range + */ + public function setColumnWidthForRange(float $width, int $start, int $end); + /** * Adds a row to the worksheet. * diff --git a/src/Spout/Writer/ODS/Creator/ManagerFactory.php b/src/Spout/Writer/ODS/Creator/ManagerFactory.php index a5b77ee..3605a37 100644 --- a/src/Spout/Writer/ODS/Creator/ManagerFactory.php +++ b/src/Spout/Writer/ODS/Creator/ManagerFactory.php @@ -93,7 +93,7 @@ class ManagerFactory implements ManagerFactoryInterface { $styleRegistry = $this->createStyleRegistry($optionsManager); - return new StyleManager($styleRegistry); + return new StyleManager($styleRegistry, $optionsManager); } /** diff --git a/src/Spout/Writer/ODS/Manager/OptionsManager.php b/src/Spout/Writer/ODS/Manager/OptionsManager.php index a6fb564..698108a 100644 --- a/src/Spout/Writer/ODS/Manager/OptionsManager.php +++ b/src/Spout/Writer/ODS/Manager/OptionsManager.php @@ -34,6 +34,9 @@ class OptionsManager extends OptionsManagerAbstract Options::TEMP_FOLDER, Options::DEFAULT_ROW_STYLE, Options::SHOULD_CREATE_NEW_SHEETS_AUTOMATICALLY, + Options::DEFAULT_COLUMN_WIDTH, + Options::DEFAULT_ROW_HEIGHT, + Options::COLUMN_WIDTHS, ]; } diff --git a/src/Spout/Writer/ODS/Manager/Style/StyleManager.php b/src/Spout/Writer/ODS/Manager/Style/StyleManager.php index 34f75c7..73b8c82 100644 --- a/src/Spout/Writer/ODS/Manager/Style/StyleManager.php +++ b/src/Spout/Writer/ODS/Manager/Style/StyleManager.php @@ -4,7 +4,10 @@ namespace Box\Spout\Writer\ODS\Manager\Style; use Box\Spout\Common\Entity\Style\BorderPart; use Box\Spout\Common\Entity\Style\CellAlignment; +use Box\Spout\Common\Manager\OptionsManagerInterface; +use Box\Spout\Writer\Common\Entity\Options; use Box\Spout\Writer\Common\Entity\Worksheet; +use Box\Spout\Writer\Common\Manager\ManagesCellSize; use Box\Spout\Writer\ODS\Helper\BorderHelper; /** @@ -13,9 +16,22 @@ use Box\Spout\Writer\ODS\Helper\BorderHelper; */ class StyleManager extends \Box\Spout\Writer\Common\Manager\Style\StyleManager { + use ManagesCellSize; + /** @var StyleRegistry */ protected $styleRegistry; + /** + * @param StyleRegistry $styleRegistry + */ + public function __construct(StyleRegistry $styleRegistry, OptionsManagerInterface $optionsManager) + { + parent::__construct($styleRegistry); + $this->setDefaultColumnWidth($optionsManager->getOption(Options::DEFAULT_COLUMN_WIDTH)); + $this->setDefaultRowHeight($optionsManager->getOption(Options::DEFAULT_ROW_HEIGHT)); + $this->columnWidths = $optionsManager->getOption(Options::COLUMN_WIDTHS) ?? []; + } + /** * Returns the content of the "styles.xml" file, given a list of styles. * @@ -162,12 +178,16 @@ EOD; $content .= $this->getStyleSectionContent($style); } - $content .= <<<'EOD' - - + $useOptimalRowHeight = empty($this->defaultRowHeight) ? 'true' : 'false'; + $defaultRowHeight = empty($this->defaultRowHeight) ? '15pt' : "{$this->defaultRowHeight}pt"; + $defaultColumnWidth = empty($this->defaultColumnWidth) ? '' : "style:column-width=\"{$this->defaultColumnWidth}pt\""; + + $content .= << + - + EOD; @@ -182,6 +202,17 @@ EOD; EOD; } + // Sort column widths since ODS cares about order + usort($this->columnWidths, function ($a, $b) { + if ($a[0] === $b[0]) { + return 0; + } + + return ($a[0] < $b[0]) ? -1 : 1; + }); + $content .= $this->getTableColumnStylesXMLContent(); + + $content .= ''; return $content; @@ -381,4 +412,42 @@ EOD; { return \sprintf(' fo:background-color="#%s" ', $style->getBackgroundColor()); } + + public function getTableColumnStylesXMLContent() : string + { + if (empty($this->columnWidths)) { + return ''; + } + + $content = ''; + foreach ($this->columnWidths as $styleIndex => $entry) { + $content .= << + + +EOD; + } + + return $content; + } + + public function getStyledTableColumnXMLContent(int $maxNumColumns) : string + { + if (empty($this->columnWidths)) { + return ''; + } + + $content = ''; + foreach ($this->columnWidths as $styleIndex => $entry) { + $numCols = $entry[1] - $entry[0] + 1; + $content .= << +EOD; + } + // Note: This assumes the column widths are contiguous and default width is + // only applied to columns after the last custom column with a custom width + $content .= ''; + + return $content; + } } diff --git a/src/Spout/Writer/ODS/Manager/WorksheetManager.php b/src/Spout/Writer/ODS/Manager/WorksheetManager.php index e5d51c1..60714f3 100644 --- a/src/Spout/Writer/ODS/Manager/WorksheetManager.php +++ b/src/Spout/Writer/ODS/Manager/WorksheetManager.php @@ -95,7 +95,7 @@ class WorksheetManager implements WorksheetManagerInterface $tableStyleName = 'ta' . ($externalSheet->getIndex() + 1); $tableElement = ''; - $tableElement .= ''; + $tableElement .= $this->styleManager->getStyledTableColumnXMLContent($worksheet->getMaxNumColumns()); return $tableElement; } @@ -265,4 +265,39 @@ class WorksheetManager implements WorksheetManagerInterface \fclose($worksheetFilePointer); } + + /** + * @param float|null $width + */ + public function setDefaultColumnWidth($width) + { + $this->styleManager->setDefaultColumnWidth($width); + } + + /** + * @param float|null $height + */ + public function setDefaultRowHeight($height) + { + $this->styleManager->setDefaultRowHeight($height); + } + + /** + * @param float $width + * @param array $columns One or more columns with this width + */ + public function setColumnWidth(float $width, ...$columns) + { + $this->styleManager->setColumnWidth($width, ...$columns); + } + + /** + * @param float $width The width to set + * @param int $start First column index of the range + * @param int $end Last column index of the range + */ + public function setColumnWidthForRange(float $width, int $start, int $end) + { + $this->styleManager->setColumnWidthForRange($width, $start, $end); + } } diff --git a/src/Spout/Writer/WriterMultiSheetsAbstract.php b/src/Spout/Writer/WriterMultiSheetsAbstract.php index 8170b67..a81b7d8 100644 --- a/src/Spout/Writer/WriterMultiSheetsAbstract.php +++ b/src/Spout/Writer/WriterMultiSheetsAbstract.php @@ -135,6 +135,55 @@ abstract class WriterMultiSheetsAbstract extends WriterAbstract $this->workbookManager->setCurrentSheet($sheet); } + /** + * @param float $width + * @throws WriterAlreadyOpenedException + */ + public function setDefaultColumnWidth(float $width) + { + $this->throwIfWriterAlreadyOpened('Writer must be configured before opening it.'); + $this->optionsManager->setOption( + Options::DEFAULT_COLUMN_WIDTH, + $width + ); + } + + /** + * @param float $height + * @throws WriterAlreadyOpenedException + */ + public function setDefaultRowHeight(float $height) + { + $this->throwIfWriterAlreadyOpened('Writer must be configured before opening it.'); + $this->optionsManager->setOption( + Options::DEFAULT_ROW_HEIGHT, + $height + ); + } + + /** + * @param float|null $width + * @param array $columns One or more columns with this width + * @throws WriterNotOpenedException + */ + public function setColumnWidth($width, ...$columns) + { + $this->throwIfWorkbookIsNotAvailable(); + $this->workbookManager->setColumnWidth($width, ...$columns); + } + + /** + * @param float $width The width to set + * @param int $start First column index of the range + * @param int $end Last column index of the range + * @throws WriterNotOpenedException + */ + public function setColumnWidthForRange(float $width, int $start, int $end) + { + $this->throwIfWorkbookIsNotAvailable(); + $this->workbookManager->setColumnWidthForRange($width, $start, $end); + } + /** * Checks if the workbook has been created. Throws an exception if not created yet. * @@ -143,7 +192,7 @@ abstract class WriterMultiSheetsAbstract extends WriterAbstract */ protected function throwIfWorkbookIsNotAvailable() { - if (!$this->workbookManager->getWorkbook()) { + if (empty($this->workbookManager) || !$this->workbookManager->getWorkbook()) { throw new WriterNotOpenedException('The writer must be opened before performing this action.'); } } diff --git a/src/Spout/Writer/XLSX/Manager/OptionsManager.php b/src/Spout/Writer/XLSX/Manager/OptionsManager.php index 000767f..b6cd29b 100644 --- a/src/Spout/Writer/XLSX/Manager/OptionsManager.php +++ b/src/Spout/Writer/XLSX/Manager/OptionsManager.php @@ -39,6 +39,9 @@ class OptionsManager extends OptionsManagerAbstract Options::DEFAULT_ROW_STYLE, Options::SHOULD_CREATE_NEW_SHEETS_AUTOMATICALLY, Options::SHOULD_USE_INLINE_STRINGS, + Options::DEFAULT_COLUMN_WIDTH, + Options::DEFAULT_ROW_HEIGHT, + Options::COLUMN_WIDTHS, ]; } diff --git a/src/Spout/Writer/XLSX/Manager/WorksheetManager.php b/src/Spout/Writer/XLSX/Manager/WorksheetManager.php index 1d90da5..1a987f3 100644 --- a/src/Spout/Writer/XLSX/Manager/WorksheetManager.php +++ b/src/Spout/Writer/XLSX/Manager/WorksheetManager.php @@ -15,6 +15,7 @@ use Box\Spout\Writer\Common\Entity\Options; use Box\Spout\Writer\Common\Entity\Worksheet; use Box\Spout\Writer\Common\Helper\CellHelper; use Box\Spout\Writer\Common\Manager\RegisteredStyle; +use Box\Spout\Writer\Common\Manager\ManagesCellSize; use Box\Spout\Writer\Common\Manager\RowManager; use Box\Spout\Writer\Common\Manager\Style\StyleMerger; use Box\Spout\Writer\Common\Manager\WorksheetManagerInterface; @@ -26,6 +27,8 @@ use Box\Spout\Writer\XLSX\Manager\Style\StyleManager; */ class WorksheetManager implements WorksheetManagerInterface { + use ManagesCellSize; + /** * Maximum number of characters a cell can contain * @see https://support.office.com/en-us/article/Excel-specifications-and-limits-16c69c74-3d6a-4aaf-ba35-e6eb276e8eaa [Excel 2007] @@ -86,6 +89,9 @@ EOD; InternalEntityFactory $entityFactory ) { $this->shouldUseInlineStrings = $optionsManager->getOption(Options::SHOULD_USE_INLINE_STRINGS); + $this->setDefaultColumnWidth($optionsManager->getOption(Options::DEFAULT_COLUMN_WIDTH)); + $this->setDefaultRowHeight($optionsManager->getOption(Options::DEFAULT_ROW_HEIGHT)); + $this->columnWidths = $optionsManager->getOption(Options::COLUMN_WIDTHS) ?? []; $this->rowManager = $rowManager; $this->styleManager = $styleManager; $this->styleMerger = $styleMerger; @@ -114,7 +120,23 @@ EOD; $worksheet->setFilePointer($sheetFilePointer); \fwrite($sheetFilePointer, self::SHEET_XML_FILE_HEADER); - \fwrite($sheetFilePointer, ''); + } + + /** + * Writes the sheet data header + * + * @param Worksheet $worksheet The worksheet to add the row to + * @return void + */ + private function ensureSheetDataStated(Worksheet $worksheet) + { + if (!$worksheet->getSheetDataStarted()) { + $worksheetFilePointer = $worksheet->getFilePointer(); + \fwrite($worksheetFilePointer, $this->getXMLFragmentForDefaultCellSizing()); + \fwrite($worksheetFilePointer, $this->getXMLFragmentForColumnWidths()); + \fwrite($worksheetFilePointer, ''); + $worksheet->setSheetDataStarted(true); + } } /** @@ -154,11 +176,14 @@ EOD; */ private function addNonEmptyRow(Worksheet $worksheet, Row $row) { + $this->ensureSheetDataStated($worksheet); + $sheetFilePointer = $worksheet->getFilePointer(); $rowStyle = $row->getStyle(); $rowIndexOneBased = $worksheet->getLastWrittenRowIndex() + 1; $numCells = $row->getNumCells(); - $rowXML = ''; + $hasCustomHeight = $this->defaultRowHeight > 0 ? '1' : '0'; + $rowXML = ""; foreach ($row->getCells() as $columnIndexZeroBased => $cell) { $registeredStyle = $this->applyStyleAndRegister($cell, $rowStyle); @@ -171,7 +196,7 @@ EOD; $rowXML .= ''; - $wasWriteSuccessful = \fwrite($worksheet->getFilePointer(), $rowXML); + $wasWriteSuccessful = \fwrite($sheetFilePointer, $rowXML); if ($wasWriteSuccessful === false) { throw new IOException("Unable to write data in {$worksheet->getFilePath()}"); } @@ -283,6 +308,43 @@ EOD; return $cellXMLFragment; } + /** + * Construct column width references xml to inject into worksheet xml file + * + * @return string + */ + public function getXMLFragmentForColumnWidths() + { + if (empty($this->columnWidths)) { + return ''; + } + $xml = ''; + foreach ($this->columnWidths as $entry) { + $xml .= ''; + } + $xml .= ''; + + return $xml; + } + + /** + * Constructs default row height and width xml to inject into worksheet xml file + * + * @return string + */ + public function getXMLFragmentForDefaultCellSizing() + { + $rowHeightXml = empty($this->defaultRowHeight) ? '' : " defaultRowHeight=\"{$this->defaultRowHeight}\""; + $colWidthXml = empty($this->defaultColumnWidth) ? '' : " defaultColWidth=\"{$this->defaultColumnWidth}\""; + if (empty($colWidthXml) && empty($rowHeightXml)) { + return ''; + } + // Ensure that the required defaultRowHeight is set + $rowHeightXml = empty($rowHeightXml) ? ' defaultRowHeight="0"' : $rowHeightXml; + + return ""; + } + /** * {@inheritdoc} */ @@ -294,6 +356,7 @@ EOD; return; } + $this->ensureSheetDataStated($worksheet); \fwrite($worksheetFilePointer, ''); \fwrite($worksheetFilePointer, ''); \fclose($worksheetFilePointer); diff --git a/tests/Spout/Writer/ODS/SheetTest.php b/tests/Spout/Writer/ODS/SheetTest.php index 4797406..f94f63c 100644 --- a/tests/Spout/Writer/ODS/SheetTest.php +++ b/tests/Spout/Writer/ODS/SheetTest.php @@ -6,6 +6,7 @@ use Box\Spout\TestUsingResource; use Box\Spout\Writer\Common\Creator\WriterEntityFactory; use Box\Spout\Writer\Common\Entity\Sheet; use Box\Spout\Writer\Exception\InvalidSheetNameException; +use Box\Spout\Writer\Exception\WriterNotOpenedException; use Box\Spout\Writer\RowCreationHelper; use PHPUnit\Framework\TestCase; @@ -82,7 +83,7 @@ class SheetTest extends TestCase */ public function testSetSheetVisibilityShouldCreateSheetHidden() { - $fileName = 'test_set_visibility_should_create_sheet_hidden.xlsx'; + $fileName = 'test_set_visibility_should_create_sheet_hidden.ods'; $this->writeDataToHiddenSheet($fileName); $resourcePath = $this->getGeneratedResourcePath($fileName); @@ -92,6 +93,130 @@ class SheetTest extends TestCase $this->assertStringContainsString(' table:display="false"', $xmlContents, 'The sheet visibility should have been changed to "hidden"'); } + public function testThrowsIfWorkbookIsNotInitialized() + { + $this->expectException(WriterNotOpenedException::class); + $writer = WriterEntityFactory::createODSWriter(); + + $writer->addRow($this->createRowFromValues([])); + } + + public function testWritesDefaultCellSizesIfSet() + { + $fileName = 'test_writes_default_cell_sizes_if_set.ods'; + + $this->createGeneratedFolderIfNeeded($fileName); + $resourcePath = $this->getGeneratedResourcePath($fileName); + + $writer = WriterEntityFactory::createODSWriter(); + $writer->setDefaultColumnWidth(100.0); + $writer->setDefaultRowHeight(20.0); + $writer->openToFile($resourcePath); + + $writer->addRow($this->createRowFromValues(['ods--11', 'ods--12'])); + $writer->close(); + + $resourcePath = $this->getGeneratedResourcePath($fileName); + $pathToWorkbookFile = $resourcePath . '#content.xml'; + $xmlContents = file_get_contents('zip://' . $pathToWorkbookFile); + + $this->assertContains(' style:column-width="100pt"', $xmlContents, 'No default col width found in sheet'); + $this->assertContains(' style:row-height="20pt"', $xmlContents, 'No default row height found in sheet'); + $this->assertContains(' style:use-optimal-row-height="false', $xmlContents, 'No optimal row height override found in sheet'); + } + + public function testWritesColumnWidths() + { + $fileName = 'test_column_widths.ods'; + $writer = $this->writerForFile($fileName); + + $writer->setColumnWidth(100.0, 1); + $writer->addRow($this->createRowFromValues(['ods--11', 'ods--12'])); + $writer->close(); + + $resourcePath = $this->getGeneratedResourcePath($fileName); + $pathToWorkbookFile = $resourcePath . '#content.xml'; + $xmlContents = file_get_contents('zip://' . $pathToWorkbookFile); + + $this->assertContains('', $xmlContents, 'No matching custom col style definition found in sheet'); + $this->assertContains('', $xmlContents, 'No matching table-column-properties found in sheet'); + $this->assertContains('table:style-name="co0"', $xmlContents, 'No matching table:style-name found in sheet'); + $this->assertContains('table:number-columns-repeated="1"', $xmlContents, 'No matching table:number-columns-repeated count found in sheet'); + } + + public function testWritesMultipleColumnWidths() + { + $fileName = 'test_multiple_column_widths.ods'; + $writer = $this->writerForFile($fileName); + + $writer->setColumnWidth(100.0, 1, 2, 3); + $writer->addRow($this->createRowFromValues(['ods--11', 'ods--12', 'ods--13'])); + $writer->close(); + + $resourcePath = $this->getGeneratedResourcePath($fileName); + $pathToWorkbookFile = $resourcePath . '#content.xml'; + $xmlContents = file_get_contents('zip://' . $pathToWorkbookFile); + + $this->assertContains('', $xmlContents, 'No matching custom col style definition found in sheet'); + $this->assertContains('', $xmlContents, 'No matching table-column-properties found in sheet'); + $this->assertContains('table:style-name="co0"', $xmlContents, 'No matching table:style-name found in sheet'); + $this->assertContains('table:number-columns-repeated="3"', $xmlContents, 'No matching table:number-columns-repeated count found in sheet'); + } + + public function testWritesMultipleColumnWidthsInRanges() + { + $fileName = 'test_multiple_column_widths_in_ranges.ods'; + $writer = $this->writerForFile($fileName); + + $writer->setColumnWidth(50.0, 1, 3, 4, 6); + $writer->setColumnWidth(100.0, 2, 5); + $writer->addRow($this->createRowFromValues(['ods--11', 'ods--12', 'ods--13', 'ods--14', 'ods--15', 'ods--16'])); + $writer->close(); + + $resourcePath = $this->getGeneratedResourcePath($fileName); + $pathToWorkbookFile = $resourcePath . '#content.xml'; + $xmlContents = file_get_contents('zip://' . $pathToWorkbookFile); + + $this->assertContains('', $xmlContents, 'No matching custom col style 0 definition found in sheet'); + $this->assertContains('', $xmlContents, 'No matching custom col style 1 definition found in sheet'); + $this->assertContains('', $xmlContents, 'No matching custom col style 2 definition found in sheet'); + $this->assertContains('', $xmlContents, 'No matching custom col style 3 definition found in sheet'); + $this->assertContains('', $xmlContents, 'No matching custom col style 4 definition found in sheet'); + $this->assertContains('', $xmlContents, 'No matching table-column-properties found in sheet'); + $this->assertContains('', $xmlContents, 'No matching table-column-properties found in sheet'); + $this->assertContains('', $xmlContents, 'No matching table:number-columns-repeated count found in sheet'); + } + + public function testCanTakeColumnWidthsAsRange() + { + $fileName = 'test_column_widths_as_ranges.ods'; + $writer = $this->writerForFile($fileName); + + $writer->setColumnWidthForRange(150.0, 1, 3); + $writer->addRow($this->createRowFromValues(['ods--11', 'ods--12', 'ods--13'])); + $writer->close(); + + $resourcePath = $this->getGeneratedResourcePath($fileName); + $pathToWorkbookFile = $resourcePath . '#content.xml'; + $xmlContents = file_get_contents('zip://' . $pathToWorkbookFile); + + $this->assertContains('', $xmlContents, 'No matching custom col style 0 definition found in sheet'); + $this->assertContains('style:column-width="150pt"/>', $xmlContents, 'No matching table-column-properties found in sheet'); + $this->assertContains('table:style-name="co0"', $xmlContents, 'No matching table:style-name found in sheet'); + $this->assertContains('table:number-columns-repeated="3"', $xmlContents, 'No matching table:number-columns-repeated count found in sheet'); + } + + private function writerForFile($fileName) + { + $this->createGeneratedFolderIfNeeded($fileName); + $resourcePath = $this->getGeneratedResourcePath($fileName); + + $writer = WriterEntityFactory::createODSWriter(); + $writer->openToFile($resourcePath); + + return $writer; + } + /** * @param string $fileName * @param string $sheetName @@ -99,11 +224,7 @@ class SheetTest extends TestCase */ private function writeDataAndReturnSheetWithCustomName($fileName, $sheetName) { - $this->createGeneratedFolderIfNeeded($fileName); - $resourcePath = $this->getGeneratedResourcePath($fileName); - - $writer = WriterEntityFactory::createODSWriter(); - $writer->openToFile($resourcePath); + $writer = $this->writerForFile($fileName); $sheet = $writer->getCurrentSheet(); $sheet->setName($sheetName); diff --git a/tests/Spout/Writer/XLSX/SheetTest.php b/tests/Spout/Writer/XLSX/SheetTest.php index a243161..79033c2 100644 --- a/tests/Spout/Writer/XLSX/SheetTest.php +++ b/tests/Spout/Writer/XLSX/SheetTest.php @@ -6,6 +6,7 @@ use Box\Spout\TestUsingResource; use Box\Spout\Writer\Common\Creator\WriterEntityFactory; use Box\Spout\Writer\Common\Entity\Sheet; use Box\Spout\Writer\Exception\InvalidSheetNameException; +use Box\Spout\Writer\Exception\WriterNotOpenedException; use Box\Spout\Writer\RowCreationHelper; use PHPUnit\Framework\TestCase; @@ -92,6 +93,138 @@ class SheetTest extends TestCase $this->assertStringContainsString(' state="hidden"', $xmlContents, 'The sheet visibility should have been changed to "hidden"'); } + public function testThrowsIfWorkbookIsNotInitialized() + { + $this->expectException(WriterNotOpenedException::class); + $writer = WriterEntityFactory::createXLSXWriter(); + + $writer->addRow($this->createRowFromValues([])); + } + + public function testWritesDefaultCellSizesIfSet() + { + $fileName = 'test_writes_default_cell_sizes_if_set.xlsx'; + $this->createGeneratedFolderIfNeeded($fileName); + $resourcePath = $this->getGeneratedResourcePath($fileName); + + $writer = WriterEntityFactory::createXLSXWriter(); + $writer->setDefaultColumnWidth(10.0); + $writer->setDefaultRowHeight(20.0); + $writer->openToFile($resourcePath); + $writer->addRow($this->createRowFromValues(['xlsx--11', 'xlsx--12'])); + $writer->close(); + + $pathToWorkbookFile = $resourcePath . '#xl/worksheets/sheet1.xml'; + $xmlContents = file_get_contents('zip://' . $pathToWorkbookFile); + + $this->assertContains('assertContains(' defaultColWidth="10', $xmlContents, 'No default column width found in sheet'); + $this->assertContains(' defaultRowHeight="20', $xmlContents, 'No default row height found in sheet'); + $this->assertContains(' customHeight="1"', $xmlContents, 'No row height override flag found in row'); + } + + public function testWritesDefaultRequiredRowHeightIfOmitted() + { + $fileName = 'test_writes_default_required_row_height_if_omitted.xlsx'; + $this->createGeneratedFolderIfNeeded($fileName); + $resourcePath = $this->getGeneratedResourcePath($fileName); + + $writer = WriterEntityFactory::createXLSXWriter(); + $writer->setDefaultColumnWidth(10.0); + $writer->openToFile($resourcePath); + + $writer->addRow($this->createRowFromValues(['xlsx--11', 'xlsx--12'])); + $writer->close(); + + $pathToWorkbookFile = $resourcePath . '#xl/worksheets/sheet1.xml'; + $xmlContents = file_get_contents('zip://' . $pathToWorkbookFile); + + $this->assertContains('assertContains(' defaultColWidth="10', $xmlContents, 'No default column width found in sheet'); + $this->assertContains(' defaultRowHeight="0', $xmlContents, 'No default row height found in sheet'); + } + + public function testWritesColumnWidths() + { + $fileName = 'test_column_widths.xlsx'; + $this->createGeneratedFolderIfNeeded($fileName); + $resourcePath = $this->getGeneratedResourcePath($fileName); + + $writer = WriterEntityFactory::createXLSXWriter(); + $writer->openToFile($resourcePath); + $writer->setColumnWidth(100.0, 1); + $writer->addRow($this->createRowFromValues(['xlsx--11', 'xlsx--12'])); + $writer->close(); + + $pathToWorkbookFile = $resourcePath . '#xl/worksheets/sheet1.xml'; + $xmlContents = file_get_contents('zip://' . $pathToWorkbookFile); + + $this->assertContains('assertContains('createGeneratedFolderIfNeeded($fileName); + $resourcePath = $this->getGeneratedResourcePath($fileName); + + $writer = WriterEntityFactory::createXLSXWriter(); + $writer->openToFile($resourcePath); + $writer->setColumnWidth(100.0, 1, 2, 3); + $writer->addRow($this->createRowFromValues(['xlsx--11', 'xlsx--12', 'xlsx--13'])); + $writer->close(); + + $pathToWorkbookFile = $resourcePath . '#xl/worksheets/sheet1.xml'; + $xmlContents = file_get_contents('zip://' . $pathToWorkbookFile); + + $this->assertContains('assertContains('createGeneratedFolderIfNeeded($fileName); + $resourcePath = $this->getGeneratedResourcePath($fileName); + + $writer = WriterEntityFactory::createXLSXWriter(); + $writer->openToFile($resourcePath); + $writer->setColumnWidth(50.0, 1, 3, 4, 6); + $writer->setColumnWidth(100.0, 2, 5); + $writer->addRow($this->createRowFromValues(['xlsx--11', 'xlsx--12', 'xlsx--13', 'xlsx--14', 'xlsx--15', 'xlsx--16'])); + $writer->close(); + + $pathToWorkbookFile = $resourcePath . '#xl/worksheets/sheet1.xml'; + $xmlContents = file_get_contents('zip://' . $pathToWorkbookFile); + + $this->assertContains('assertContains('assertContains('assertContains('assertContains('assertContains('createGeneratedFolderIfNeeded($fileName); + $resourcePath = $this->getGeneratedResourcePath($fileName); + + $writer = WriterEntityFactory::createXLSXWriter(); + $writer->openToFile($resourcePath); + $writer->setColumnWidthForRange(50.0, 1, 3); + $writer->addRow($this->createRowFromValues(['xlsx--11', 'xlsx--12', 'xlsx--13'])); + $writer->close(); + + $pathToWorkbookFile = $resourcePath . '#xl/worksheets/sheet1.xml'; + $xmlContents = file_get_contents('zip://' . $pathToWorkbookFile); + + $this->assertContains('assertContains('