diff --git a/src/Spout/Common/Entity/Row.php b/src/Spout/Common/Entity/Row.php index 0cc49c7..4fba9b4 100644 --- a/src/Spout/Common/Entity/Row.php +++ b/src/Spout/Common/Entity/Row.php @@ -18,6 +18,12 @@ class Row */ protected $style; + /** + * Row height (default is 15) + * @var string + */ + protected $height = "15"; + /** * Row constructor. * @param Cell[] $cells @@ -126,4 +132,24 @@ class Row return $cell->getValue(); }, $this->cells); } + + /** + * Set row height + * @param String $height + * @return Row + */ + public function setHeight($height) + { + $this->height = $height; + return $this; + } + + /** + * Returns row height + * @return String + */ + public function getHeight() + { + return $this->height; + } } diff --git a/src/Spout/Common/Entity/Style/Style.php b/src/Spout/Common/Entity/Style/Style.php index 7e989a4..40c9f20 100644 --- a/src/Spout/Common/Entity/Style/Style.php +++ b/src/Spout/Common/Entity/Style/Style.php @@ -66,6 +66,9 @@ class Style /** @var bool Whether the wrap text property was set */ private $hasSetWrapText = false; + private $shrinkToFit = false; + private $shouldShrinkToFit = false; + /** @var Border */ private $border; @@ -463,4 +466,24 @@ class Style { return $this->hasSetFormat; } + + /** + * Sets should shrink to fit + * @param bool $shrinkToFit + * @return Style + */ + public function setShouldShrinkToFit($shrinkToFit = true) + { + $this->shrinkToFit = $shrinkToFit; + $this->shouldShrinkToFit = $shrinkToFit; + return $this; + } + + /** + * @return bool Whether format should be applied + */ + public function shouldShrinkToFit() + { + return $this->shouldShrinkToFit; + } } diff --git a/src/Spout/Common/Manager/OptionsManagerAbstract.php b/src/Spout/Common/Manager/OptionsManagerAbstract.php index 5670b95..672f6fd 100644 --- a/src/Spout/Common/Manager/OptionsManagerAbstract.php +++ b/src/Spout/Common/Manager/OptionsManagerAbstract.php @@ -51,6 +51,21 @@ abstract class OptionsManagerAbstract implements OptionsManagerInterface } } + /** + * Add an option to the internal list of options + * Used only for mergeCells() for now + * @return void + */ + public function addOption($optionName, $optionValue) + { + if (\in_array($optionName, $this->supportedOptions)) { + if (!isset($this->options[$optionName])) { + $this->options[$optionName] = []; + } + $this->options[$optionName][] = $optionValue; + } + } + /** * @param string $optionName * @return mixed|null The set option or NULL if no option with given name found diff --git a/src/Spout/Writer/Common/Creator/Style/StyleBuilder.php b/src/Spout/Writer/Common/Creator/Style/StyleBuilder.php index bc2d406..8c48848 100644 --- a/src/Spout/Writer/Common/Creator/Style/StyleBuilder.php +++ b/src/Spout/Writer/Common/Creator/Style/StyleBuilder.php @@ -183,6 +183,17 @@ class StyleBuilder return $this; } + /** + * Set should shrink to fit + * @param boolean $shrinkToFit + * @return void + */ + public function setShouldShrinkToFit($shrinkToFit = true) + { + $this->style->setShouldShrinkToFit($shrinkToFit); + return $this; + } + /** * Returns the configured style. The style is cached and can be reused. * diff --git a/src/Spout/Writer/Common/Entity/Options.php b/src/Spout/Writer/Common/Entity/Options.php index d7152bb..0baa628 100644 --- a/src/Spout/Writer/Common/Entity/Options.php +++ b/src/Spout/Writer/Common/Entity/Options.php @@ -20,4 +20,10 @@ abstract class Options // XLSX specific options const SHOULD_USE_INLINE_STRINGS = 'shouldUseInlineStrings'; + + // XLSX column widths + const COLUMN_WIDTHS = 'columnWidths'; + + // XLSX merge cells + const MERGE_CELLS = 'mergeCells'; } diff --git a/src/Spout/Writer/Common/Entity/Sheet.php b/src/Spout/Writer/Common/Entity/Sheet.php index aabdd91..6391571 100644 --- a/src/Spout/Writer/Common/Entity/Sheet.php +++ b/src/Spout/Writer/Common/Entity/Sheet.php @@ -27,6 +27,9 @@ class Sheet /** @var SheetManager Sheet manager */ private $sheetManager; + /** @var bool Sheet is started */ + private $isSheetStarted = false; + /** * @param int $sheetIndex Index of the sheet, based on order in the workbook (zero-based) * @param string $associatedWorkbookId ID of the sheet's associated workbook @@ -108,4 +111,23 @@ class Sheet return $this; } + + /** + * @return bool isSheetStarted Sheet was started + */ + public function isSheetStarted() + { + return $this->isSheetStarted; + } + + /** + * @param bool $isSheetStarted Set if sheet was started + * @return Sheet + */ + public function setIsSheetStarted($isSheetStarted) + { + $this->isSheetStarted = $isSheetStarted; + + return $this; + } } diff --git a/src/Spout/Writer/WriterMultiSheetsAbstract.php b/src/Spout/Writer/WriterMultiSheetsAbstract.php index 8170b67..ec84e44 100644 --- a/src/Spout/Writer/WriterMultiSheetsAbstract.php +++ b/src/Spout/Writer/WriterMultiSheetsAbstract.php @@ -61,6 +61,29 @@ abstract class WriterMultiSheetsAbstract extends WriterAbstract return $this; } + /** + * Set columns widths as list. If value is null will set column with default width (8.43) + * @param array $columnWidths + * @return WriterMultiSheetsAbstract + */ + public function setColumnWidths(array $columnWidths) + { + $this->optionsManager->setOption(Options::COLUMN_WIDTHS, $columnWidths); + return $this; + } + + /** + * Undocumented function + * + * @param array $range + * @return void + */ + public function mergeCells(array $range1, array $range2) + { + $this->optionsManager->addOption(Options::MERGE_CELLS, [$range1, $range2]); + return $this; + } + /** * {@inheritdoc} */ diff --git a/src/Spout/Writer/XLSX/Manager/OptionsManager.php b/src/Spout/Writer/XLSX/Manager/OptionsManager.php index d3b5cd4..40e299e 100644 --- a/src/Spout/Writer/XLSX/Manager/OptionsManager.php +++ b/src/Spout/Writer/XLSX/Manager/OptionsManager.php @@ -39,6 +39,8 @@ class OptionsManager extends OptionsManagerAbstract Options::DEFAULT_ROW_STYLE, Options::SHOULD_CREATE_NEW_SHEETS_AUTOMATICALLY, Options::SHOULD_USE_INLINE_STRINGS, + Options::COLUMN_WIDTHS, + Options::MERGE_CELLS, ]; } @@ -56,5 +58,7 @@ class OptionsManager extends OptionsManagerAbstract $this->setOption(Options::DEFAULT_ROW_STYLE, $defaultRowStyle); $this->setOption(Options::SHOULD_CREATE_NEW_SHEETS_AUTOMATICALLY, true); $this->setOption(Options::SHOULD_USE_INLINE_STRINGS, true); + $this->setOption(Options::COLUMN_WIDTHS, []); + $this->setOption(Options::MERGE_CELLS, []); } } diff --git a/src/Spout/Writer/XLSX/Manager/Style/StyleManager.php b/src/Spout/Writer/XLSX/Manager/Style/StyleManager.php index f0ca9d9..b79b1da 100644 --- a/src/Spout/Writer/XLSX/Manager/Style/StyleManager.php +++ b/src/Spout/Writer/XLSX/Manager/Style/StyleManager.php @@ -258,6 +258,10 @@ EOD; if ($style->shouldWrapText()) { $content .= ' wrapText="1"'; } + if ($style->shouldShrinkToFit()) { + $content .= ' shrinkToFit="true"'; + } + $content .= '/>'; $content .= ''; } else { diff --git a/src/Spout/Writer/XLSX/Manager/WorksheetManager.php b/src/Spout/Writer/XLSX/Manager/WorksheetManager.php index 741d0aa..2cac24b 100644 --- a/src/Spout/Writer/XLSX/Manager/WorksheetManager.php +++ b/src/Spout/Writer/XLSX/Manager/WorksheetManager.php @@ -37,6 +37,8 @@ class WorksheetManager implements WorksheetManagerInterface EOD; + /** @var OptionsManagerInterface */ + private $optionsManager; /** @var bool Whether inline or shared strings should be used */ protected $shouldUseInlineStrings; @@ -84,6 +86,7 @@ EOD; StringHelper $stringHelper, InternalEntityFactory $entityFactory ) { + $this->optionsManager = $optionsManager; $this->shouldUseInlineStrings = $optionsManager->getOption(Options::SHOULD_USE_INLINE_STRINGS); $this->rowManager = $rowManager; $this->styleManager = $styleManager; @@ -113,7 +116,6 @@ EOD; $worksheet->setFilePointer($sheetFilePointer); \fwrite($sheetFilePointer, self::SHEET_XML_FILE_HEADER); - \fwrite($sheetFilePointer, ''); } /** @@ -153,11 +155,28 @@ EOD; */ private function addNonEmptyRow(Worksheet $worksheet, Row $row) { + if (!$worksheet->getExternalSheet()->isSheetStarted()) { + // create nodes for columns widths + if ($this->optionsManager->getOption(Options::COLUMN_WIDTHS)) { + $colsString = ''; + foreach ($this->optionsManager->getOption(Options::COLUMN_WIDTHS) as $index => $width) { + $index++; + $colsString.= ''; + } + $colsString.=""; + \fwrite($worksheet->getFilePointer(), $colsString); + } + + \fwrite($worksheet->getFilePointer(), ''); + $worksheet->getExternalSheet()->setIsSheetStarted(true); + } + $rowStyle = $row->getStyle(); $rowIndexOneBased = $worksheet->getLastWrittenRowIndex() + 1; $numCells = $row->getNumCells(); + $rowHeight = $row->getHeight(); - $rowXML = ''; + $rowXML = ''; foreach ($row->getCells() as $columnIndexZeroBased => $cell) { $rowXML .= $this->applyStyleAndGetCellXML($cell, $rowStyle, $rowIndexOneBased, $columnIndexZeroBased); @@ -270,7 +289,26 @@ EOD; return; } + if (!$worksheet->getExternalSheet()->isSheetStarted()) { + \fwrite($worksheetFilePointer, ''); + $worksheet->getExternalSheet()->setIsSheetStarted(true); + } + \fwrite($worksheetFilePointer, ''); + + // create nodes for merge cells + if ($this->optionsManager->getOption(Options::MERGE_CELLS)) { + $mergeCellString = ''; + foreach ($this->optionsManager->getOption(Options::MERGE_CELLS) as $values) { + $output = array_map(function($value){ + return CellHelper::getColumnLettersFromColumnIndex($value[0]) . $value[1]; + }, $values); + $mergeCellString.= ''; + } + $mergeCellString.= ''; + \fwrite($worksheet->getFilePointer(), $mergeCellString); + } + \fwrite($worksheetFilePointer, ''); \fclose($worksheetFilePointer); }