From 4f0e72c4e4925fe98649f704b2b522ff616eaf5c Mon Sep 17 00:00:00 2001 From: Xwiz Date: Fri, 4 Feb 2022 23:30:37 +0100 Subject: [PATCH 1/6] Enable est column width calculation --- src/Spout/Writer/Common/Entity/Options.php | 1 + src/Spout/Writer/Common/Entity/Worksheet.php | 120 ++++++++++++++++++ .../Writer/Common/Helper/AppendHelper.php | 31 +++++ .../Writer/ODS/Creator/ManagerFactory.php | 7 +- .../Writer/ODS/Helper/FileSystemHelper.php | 2 +- .../Writer/ODS/Manager/OptionsManager.php | 2 + .../Writer/ODS/Manager/Style/StyleManager.php | 6 +- .../Writer/ODS/Manager/WorksheetManager.php | 53 +++++++- .../Writer/WriterMultiSheetsAbstract.php | 19 +++ .../Writer/XLSX/Manager/OptionsManager.php | 2 + .../Writer/XLSX/Manager/WorksheetManager.php | 35 ++++- 11 files changed, 269 insertions(+), 9 deletions(-) create mode 100644 src/Spout/Writer/Common/Helper/AppendHelper.php diff --git a/src/Spout/Writer/Common/Entity/Options.php b/src/Spout/Writer/Common/Entity/Options.php index fbfa70930..c655699d5 100644 --- a/src/Spout/Writer/Common/Entity/Options.php +++ b/src/Spout/Writer/Common/Entity/Options.php @@ -16,6 +16,7 @@ abstract class Options // Multisheets options public const TEMP_FOLDER = 'tempFolder'; public const DEFAULT_ROW_STYLE = 'defaultRowStyle'; + public const ROWWIDTH_CALC_STYLE = 'rowCalcMethod'; public const SHOULD_CREATE_NEW_SHEETS_AUTOMATICALLY = 'shouldCreateNewSheetsAutomatically'; // XLSX specific options diff --git a/src/Spout/Writer/Common/Entity/Worksheet.php b/src/Spout/Writer/Common/Entity/Worksheet.php index 1e496f012..1a3e1af87 100644 --- a/src/Spout/Writer/Common/Entity/Worksheet.php +++ b/src/Spout/Writer/Common/Entity/Worksheet.php @@ -22,6 +22,21 @@ class Worksheet /** @var int Index of the last written row */ private $lastWrittenRowIndex; + + /** @var array Array of the column widths */ + protected $columnWidths; + + /** @var int Width calculation style */ + protected $widthCalcuationStyle; + + /** @var int Fixed sheet width for fixed width calculation style */ + protected $fixedSheetWidth; + + public const W_FULL = 1; + public const W_FIXED = 2; + public const W_NONE = 0; + public const DEFAULT_COL_WIDTH = 30; + public const DEFAULT_FIXED_WIDTH = 1068; /** * Worksheet constructor. @@ -36,6 +51,8 @@ public function __construct($worksheetFilePath, Sheet $externalSheet) $this->externalSheet = $externalSheet; $this->maxNumColumns = 0; $this->lastWrittenRowIndex = 0; + $this->columnWidths = []; + $this->widthCalcuationStyle = 0; } /** @@ -78,6 +95,86 @@ public function getMaxNumColumns() return $this->maxNumColumns; } + /** + * @return array + */ + public function getColumnWidths() + { + return $this->columnWidths; + } + + /** + * Gets the calculated max column width for the specified index + * @param int $zeroBasedIndex + * @return int + */ + public function getMaxColumnWidth($zeroBasedIndex) + { + if (isset($this->columnWidths[$zeroBasedIndex])) { + return $this->columnWidths[$zeroBasedIndex]; + } + + $this->columnWidths[$zeroBasedIndex] = self::DEFAULT_COL_WIDTH; + return $this->columnWidths[$zeroBasedIndex]; + } + + /** + * Sets the calculated max column width for the specified index + * @param int $zeroBasedIndex + * @param int $value Value to set to + * @return void + */ + public function setMaxColumnWidth($zeroBasedIndex, $value) + { + $curSize = $this->columnWidths[$zeroBasedIndex] ?? 0; + if ($curSize < $value) { + $this->columnWidths[$zeroBasedIndex] = $value; + } + } + + /** + * Automatically calculates and sets the max column width for the specified cell + * @param Cell $cell The cell + * @param Style $style Row/Cell style + * @param int $zeroBasedIndex of cell + * @return void + */ + public function autoSetWidth($cell, $style, $zeroBasedIndex) + { + $size = strlen($cell->getValue()) ?? 1;//use 1 as length if cell empty + $size *= (float)($style->getFontSize() ?? 10); + $size *= $style->isFontBold() ? 1.2 : 1.0; + if ($this->getWidthCalculation() == Worksheet::W_FIXED) { + $total = array_sum($this->getColumnWidths()); + $total = $total ?: $size; + $size = ($size / $total) * $this->getFixedSheetWidth(); + } + $size /= 10; + $this->setMaxColumnWidth($zeroBasedIndex, $size); + } + + /** + * Gets the fixed sheet width or returns the default if not available + * @return int + */ + public function getFixedSheetWidth() + { + if (!$this->fixedSheetWidth) { + return Worksheet::DEFAULT_FIXED_WIDTH; + } + return $this->fixedSheetWidth; + } + + /** + * Sets the fixed sheet width + * @param int $width + * @return void + */ + public function setFixedSheetWidth($width) + { + $this->fixedSheetWidth = $width; + } + /** * @param int $maxNumColumns */ @@ -86,6 +183,29 @@ public function setMaxNumColumns($maxNumColumns) $this->maxNumColumns = $maxNumColumns; } + /** + * Set the with calculation style for this sheet. + * 1=FullExpand,2=FixedWidth,0=None + * + * @return Worksheet Enable method chaining for easy set width + */ + public function setWidthCalculation($widthStyle) + { + $this->widthCalcuationStyle = $widthStyle; + return $this; + } + + /** + * Get the with calculation style for this sheet. + * 1=FullExpand,2=FixedWidth,0=None + * + * @return void + */ + public function getWidthCalculation() + { + return $this->widthCalcuationStyle; + } + /** * @return int */ diff --git a/src/Spout/Writer/Common/Helper/AppendHelper.php b/src/Spout/Writer/Common/Helper/AppendHelper.php new file mode 100644 index 000000000..74cbf73e0 --- /dev/null +++ b/src/Spout/Writer/Common/Helper/AppendHelper.php @@ -0,0 +1,31 @@ +createStyleMerger(); $styleManager = $this->createStyleManager($optionsManager); - $worksheetManager = $this->createWorksheetManager($styleManager, $styleMerger); + $worksheetManager = $this->createWorksheetManager($optionsManager, $styleManager, $styleMerger); return new WorkbookManager( $workbook, @@ -63,16 +63,17 @@ public function createWorkbookManager(OptionsManagerInterface $optionsManager) } /** + * @param OptionsManagerInterface $optionsManager * @param StyleManager $styleManager * @param StyleMerger $styleMerger * @return WorksheetManager */ - private function createWorksheetManager(StyleManager $styleManager, StyleMerger $styleMerger) + private function createWorksheetManager(OptionsManagerInterface $optionsManager, StyleManager $styleManager, StyleMerger $styleMerger) { $stringsEscaper = $this->helperFactory->createStringsEscaper(); $stringsHelper = $this->helperFactory->createStringHelper(); - return new WorksheetManager($styleManager, $styleMerger, $stringsEscaper, $stringsHelper); + return new WorksheetManager($optionsManager, $styleManager, $styleMerger, $stringsEscaper, $stringsHelper); } /** diff --git a/src/Spout/Writer/ODS/Helper/FileSystemHelper.php b/src/Spout/Writer/ODS/Helper/FileSystemHelper.php index 0e593e606..e8735ddcf 100644 --- a/src/Spout/Writer/ODS/Helper/FileSystemHelper.php +++ b/src/Spout/Writer/ODS/Helper/FileSystemHelper.php @@ -202,7 +202,7 @@ public function createContentFile($worksheetManager, $styleManager, $worksheets) EOD; $contentXmlFileContents .= $styleManager->getContentXmlFontFaceSectionContent(); - $contentXmlFileContents .= $styleManager->getContentXmlAutomaticStylesSectionContent($worksheets); + $contentXmlFileContents .= $styleManager->getContentXmlAutomaticStylesSectionContent($worksheetManager, $worksheets); $contentXmlFileContents .= ''; diff --git a/src/Spout/Writer/ODS/Manager/OptionsManager.php b/src/Spout/Writer/ODS/Manager/OptionsManager.php index a6fb564ef..da909bc28 100644 --- a/src/Spout/Writer/ODS/Manager/OptionsManager.php +++ b/src/Spout/Writer/ODS/Manager/OptionsManager.php @@ -33,6 +33,7 @@ protected function getSupportedOptions() return [ Options::TEMP_FOLDER, Options::DEFAULT_ROW_STYLE, + Options::ROWWIDTH_CALC_STYLE, Options::SHOULD_CREATE_NEW_SHEETS_AUTOMATICALLY, ]; } @@ -45,5 +46,6 @@ protected function setDefaultOptions() $this->setOption(Options::TEMP_FOLDER, \sys_get_temp_dir()); $this->setOption(Options::DEFAULT_ROW_STYLE, $this->styleBuilder->build()); $this->setOption(Options::SHOULD_CREATE_NEW_SHEETS_AUTOMATICALLY, true); + $this->setOption(Options::ROWWIDTH_CALC_STYLE, 0); } } diff --git a/src/Spout/Writer/ODS/Manager/Style/StyleManager.php b/src/Spout/Writer/ODS/Manager/Style/StyleManager.php index 34f75c78d..cd2614363 100644 --- a/src/Spout/Writer/ODS/Manager/Style/StyleManager.php +++ b/src/Spout/Writer/ODS/Manager/Style/StyleManager.php @@ -151,17 +151,21 @@ public function getContentXmlFontFaceSectionContent() /** * Returns the contents of the "" section, inside "content.xml" file. * + * @param WorksheetManager $manager * @param Worksheet[] $worksheets * @return string */ - public function getContentXmlAutomaticStylesSectionContent($worksheets) + public function getContentXmlAutomaticStylesSectionContent($manager, $worksheets) { $content = ''; + $content .= $manager->getWidthStylesContent($worksheets[0]); + foreach ($this->styleRegistry->getRegisteredStyles() as $style) { $content .= $this->getStyleSectionContent($style); } + $content .= <<<'EOD' diff --git a/src/Spout/Writer/ODS/Manager/WorksheetManager.php b/src/Spout/Writer/ODS/Manager/WorksheetManager.php index e5d51c10b..3d10d794e 100644 --- a/src/Spout/Writer/ODS/Manager/WorksheetManager.php +++ b/src/Spout/Writer/ODS/Manager/WorksheetManager.php @@ -9,6 +9,9 @@ use Box\Spout\Common\Exception\IOException; use Box\Spout\Common\Helper\Escaper\ODS as ODSEscaper; use Box\Spout\Common\Helper\StringHelper; +use Box\Spout\Common\Manager\OptionsManagerInterface; +use Box\Spout\Writer\Common\Helper\AppendHelper; +use Box\Spout\Writer\Common\Entity\Options; use Box\Spout\Writer\Common\Entity\Worksheet; use Box\Spout\Writer\Common\Manager\RegisteredStyle; use Box\Spout\Writer\Common\Manager\Style\StyleMerger; @@ -33,20 +36,29 @@ class WorksheetManager implements WorksheetManagerInterface /** @var StyleMerger Helper to merge styles together */ private $styleMerger; + /** $int file pointer head position */ + private $headWritePosition; + + /** @var int Width calculation style */ + protected $widthCalcuationStyle; + /** * WorksheetManager constructor. * + * @param OptionsManagerInterface $optionsManager * @param StyleManager $styleManager * @param StyleMerger $styleMerger * @param ODSEscaper $stringsEscaper * @param StringHelper $stringHelper */ public function __construct( + OptionsManagerInterface $optionsManager, StyleManager $styleManager, StyleMerger $styleMerger, ODSEscaper $stringsEscaper, StringHelper $stringHelper ) { + $this->widthCalcuationStyle = $optionsManager->getOption(Options::ROWWIDTH_CALC_STYLE); $this->styleManager = $styleManager; $this->styleMerger = $styleMerger; $this->stringsEscaper = $stringsEscaper; @@ -62,9 +74,14 @@ public function __construct( */ public function startSheet(Worksheet $worksheet) { - $sheetFilePointer = \fopen($worksheet->getFilePath(), 'w'); + $sheetFilePointer = \fopen($worksheet->getFilePath(), 'w+'); $this->throwIfSheetFilePointerIsNotAvailable($sheetFilePointer); + $worksheet->setWidthCalculation($this->widthCalcuationStyle); + if ($worksheet->getWidthCalculation() != Worksheet::W_NONE) { + $this->headWritePosition = ftell($sheetFilePointer); + } + $worksheet->setFilePointer($sheetFilePointer); } @@ -95,7 +112,15 @@ public function getTableElementStartAsString(Worksheet $worksheet) $tableStyleName = 'ta' . ($externalSheet->getIndex() + 1); $tableElement = ''; - $tableElement .= ''; + + if ($worksheet->getWidthCalculation() != Worksheet::W_NONE) { + foreach ($worksheet->getColumnWidths() as $i => $w){ + $colNo = $i + 1; + $tableElement .= ''; + } + } else { + $tableElement .= ''; + } return $tableElement; } @@ -125,6 +150,10 @@ public function addRow(Worksheet $worksheet, Row $row) /** @var Cell|null $nextCell */ $nextCell = isset($cells[$nextCellIndex]) ? $cells[$nextCellIndex] : null; + if ($worksheet->getWidthCalculation() != Worksheet::W_NONE) { + $worksheet->autoSetWidth($cell, $rowStyle, $i); + } + if ($nextCell === null || $cell->getValue() !== $nextCell->getValue()) { $registeredStyle = $this->applyStyleAndRegister($cell, $rowStyle); $cellStyle = $registeredStyle->getStyle(); @@ -249,6 +278,26 @@ private function getCellXML(Cell $cell, $styleIndex, $numTimesValueRepeated) return $data; } + public function getWidthStylesContent($worksheet) + { + if ($worksheet->getWidthCalculation() != Worksheet::W_NONE) { + //create the col styles + $style = ''; + $widths = $worksheet->getColumnWidths(); + //todo: this may not be adequate for multiple worksheets + foreach ($widths as $i => $width){ + $win = round($width / 9.6, 2);//convert to inches + $colNo = $i + 1; + $style .= ''; + } + return $style; + } + return ""; + } + /** * Closes the worksheet * diff --git a/src/Spout/Writer/WriterMultiSheetsAbstract.php b/src/Spout/Writer/WriterMultiSheetsAbstract.php index 18b40bd42..f30577427 100644 --- a/src/Spout/Writer/WriterMultiSheetsAbstract.php +++ b/src/Spout/Writer/WriterMultiSheetsAbstract.php @@ -26,6 +26,9 @@ abstract class WriterMultiSheetsAbstract extends WriterAbstract /** @var WorkbookManagerInterface|null */ private $workbookManager; + + /** @var int Width calculation style */ + protected $widthCalcuationStyle; /** * @param OptionsManagerInterface $optionsManager @@ -146,6 +149,22 @@ protected function throwIfWorkbookIsNotAvailable() } } + /** + * Set default sheet width calculation option + * + * @param int $option The width calculation style + * @throws \Box\Spout\Writer\Exception\WriterAlreadyOpenedException If the writer was already opened + * @return Writer + */ + public function setWidthCalculation($option) + { + $this->throwIfWriterAlreadyOpened('Writer must be configured before opening it.'); + + $this->optionsManager->setOption(Options::ROWWIDTH_CALC_STYLE, $option); + + return $this; + } + /** * {@inheritdoc} */ diff --git a/src/Spout/Writer/XLSX/Manager/OptionsManager.php b/src/Spout/Writer/XLSX/Manager/OptionsManager.php index 000767ffc..5efa2dbab 100644 --- a/src/Spout/Writer/XLSX/Manager/OptionsManager.php +++ b/src/Spout/Writer/XLSX/Manager/OptionsManager.php @@ -37,6 +37,7 @@ protected function getSupportedOptions() return [ Options::TEMP_FOLDER, Options::DEFAULT_ROW_STYLE, + Options::ROWWIDTH_CALC_STYLE, Options::SHOULD_CREATE_NEW_SHEETS_AUTOMATICALLY, Options::SHOULD_USE_INLINE_STRINGS, ]; @@ -56,5 +57,6 @@ protected function setDefaultOptions() $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::ROWWIDTH_CALC_STYLE, 0); } } diff --git a/src/Spout/Writer/XLSX/Manager/WorksheetManager.php b/src/Spout/Writer/XLSX/Manager/WorksheetManager.php index 602544295..2830614c9 100644 --- a/src/Spout/Writer/XLSX/Manager/WorksheetManager.php +++ b/src/Spout/Writer/XLSX/Manager/WorksheetManager.php @@ -9,6 +9,7 @@ use Box\Spout\Common\Exception\IOException; use Box\Spout\Common\Helper\Escaper\XLSX as XLSXEscaper; use Box\Spout\Common\Helper\StringHelper; +use Box\Spout\Writer\Common\Helper\AppendHelper; use Box\Spout\Common\Manager\OptionsManagerInterface; use Box\Spout\Writer\Common\Entity\Options; use Box\Spout\Writer\Common\Entity\Worksheet; @@ -35,7 +36,8 @@ class WorksheetManager implements WorksheetManagerInterface public const SHEET_XML_FILE_HEADER = <<<'EOD' - + EOD; /** @var bool Whether inline or shared strings should be used */ @@ -59,6 +61,12 @@ class WorksheetManager implements WorksheetManagerInterface /** @var StringHelper String helper */ private $stringHelper; + /** $int file pointer head position */ + private $headWritePosition; + + /** @var int Width calculation style */ + protected $widthCalcuationStyle; + /** * WorksheetManager constructor. * @@ -80,6 +88,7 @@ public function __construct( StringHelper $stringHelper ) { $this->shouldUseInlineStrings = $optionsManager->getOption(Options::SHOULD_USE_INLINE_STRINGS); + $this->widthCalcuationStyle = $optionsManager->getOption(Options::ROWWIDTH_CALC_STYLE); $this->rowManager = $rowManager; $this->styleManager = $styleManager; $this->styleMerger = $styleMerger; @@ -101,12 +110,16 @@ public function getSharedStringsManager() */ public function startSheet(Worksheet $worksheet) { - $sheetFilePointer = \fopen($worksheet->getFilePath(), 'w'); + $sheetFilePointer = \fopen($worksheet->getFilePath(), 'w+'); $this->throwIfSheetFilePointerIsNotAvailable($sheetFilePointer); $worksheet->setFilePointer($sheetFilePointer); + $worksheet->setWidthCalculation($this->widthCalcuationStyle); \fwrite($sheetFilePointer, self::SHEET_XML_FILE_HEADER); + if ($worksheet->getWidthCalculation() != Worksheet::W_NONE) { + $this->headWritePosition = ftell($sheetFilePointer); + } \fwrite($sheetFilePointer, ''); } @@ -159,6 +172,12 @@ private function addNonEmptyRow(Worksheet $worksheet, Row $row) if ($registeredStyle->isMatchingRowStyle()) { $rowStyle = $cellStyle; // Replace actual rowStyle (possibly with null id) by registered style (with id) } + + if ($worksheet->getWidthCalculation() != Worksheet::W_NONE) { + //use row style to maintain a fair average based width computation for now + $worksheet->autoSetWidth($cell, $rowStyle, $columnIndexZeroBased); + } + $rowXML .= $this->getCellXML($rowIndexOneBased, $columnIndexZeroBased, $cell, $cellStyle->getId()); } @@ -287,6 +306,18 @@ public function close(Worksheet $worksheet) } \fwrite($worksheetFilePointer, ''); + + if ($worksheet->getWidthCalculation() != Worksheet::W_NONE) { + $colNode =''; + $widths = $worksheet->getColumnWidths(); + foreach ($widths as $i => $width){ + $colAffect = $i + 1; + $colNode .= ''; + } + $colNode .= ''; + $worksheetFilePointer = AppendHelper::insertToFile($worksheetFilePointer, $this->headWritePosition, $colNode); + } + \fwrite($worksheetFilePointer, ''); \fclose($worksheetFilePointer); } From d53be7bd2bc754d77d40ef5e8f66aff429eb4b8a Mon Sep 17 00:00:00 2001 From: Xwiz Date: Fri, 4 Feb 2022 23:44:49 +0100 Subject: [PATCH 2/6] Improve logic --- src/Spout/Writer/Common/Entity/Worksheet.php | 4 +--- src/Spout/Writer/ODS/Manager/WorksheetManager.php | 1 + 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Spout/Writer/Common/Entity/Worksheet.php b/src/Spout/Writer/Common/Entity/Worksheet.php index 1a3e1af87..ffdd1d27b 100644 --- a/src/Spout/Writer/Common/Entity/Worksheet.php +++ b/src/Spout/Writer/Common/Entity/Worksheet.php @@ -141,15 +141,13 @@ public function setMaxColumnWidth($zeroBasedIndex, $value) */ public function autoSetWidth($cell, $style, $zeroBasedIndex) { - $size = strlen($cell->getValue()) ?? 1;//use 1 as length if cell empty - $size *= (float)($style->getFontSize() ?? 10); + $size = 1 + strlen($cell->getValue());//ensure we have at least 1 space $size *= $style->isFontBold() ? 1.2 : 1.0; if ($this->getWidthCalculation() == Worksheet::W_FIXED) { $total = array_sum($this->getColumnWidths()); $total = $total ?: $size; $size = ($size / $total) * $this->getFixedSheetWidth(); } - $size /= 10; $this->setMaxColumnWidth($zeroBasedIndex, $size); } diff --git a/src/Spout/Writer/ODS/Manager/WorksheetManager.php b/src/Spout/Writer/ODS/Manager/WorksheetManager.php index 3d10d794e..388a7477b 100644 --- a/src/Spout/Writer/ODS/Manager/WorksheetManager.php +++ b/src/Spout/Writer/ODS/Manager/WorksheetManager.php @@ -286,6 +286,7 @@ public function getWidthStylesContent($worksheet) $widths = $worksheet->getColumnWidths(); //todo: this may not be adequate for multiple worksheets foreach ($widths as $i => $width){ + //this is a rough equivalent based on pixel density $win = round($width / 9.6, 2);//convert to inches $colNo = $i + 1; $style .= 'throwIfWriterAlreadyOpened('Writer must be configured before opening it.'); + + $this->optionsManager->setOption(Options::ROWWIDTH_FIXED, $option); + + return $this; + } + /** * {@inheritdoc} */ diff --git a/src/Spout/Writer/XLSX/Manager/WorksheetManager.php b/src/Spout/Writer/XLSX/Manager/WorksheetManager.php index 2830614c9..294ebca43 100644 --- a/src/Spout/Writer/XLSX/Manager/WorksheetManager.php +++ b/src/Spout/Writer/XLSX/Manager/WorksheetManager.php @@ -67,6 +67,9 @@ class WorksheetManager implements WorksheetManagerInterface /** @var int Width calculation style */ protected $widthCalcuationStyle; + /** @var int Fixed Width */ + protected $fixedWidth; + /** * WorksheetManager constructor. * @@ -89,6 +92,7 @@ public function __construct( ) { $this->shouldUseInlineStrings = $optionsManager->getOption(Options::SHOULD_USE_INLINE_STRINGS); $this->widthCalcuationStyle = $optionsManager->getOption(Options::ROWWIDTH_CALC_STYLE); + $this->fixedWidth = $optionsManager->getOption(Options::ROWWIDTH_FIXED); $this->rowManager = $rowManager; $this->styleManager = $styleManager; $this->styleMerger = $styleMerger; @@ -115,6 +119,7 @@ public function startSheet(Worksheet $worksheet) $worksheet->setFilePointer($sheetFilePointer); $worksheet->setWidthCalculation($this->widthCalcuationStyle); + $worksheet->setFixedSheetWidth($this->fixedWidth); \fwrite($sheetFilePointer, self::SHEET_XML_FILE_HEADER); if ($worksheet->getWidthCalculation() != Worksheet::W_NONE) { @@ -310,6 +315,16 @@ public function close(Worksheet $worksheet) if ($worksheet->getWidthCalculation() != Worksheet::W_NONE) { $colNode =''; $widths = $worksheet->getColumnWidths(); + + //re-calculate width for fixed sets + if ($worksheet->getWidthCalculation() == Worksheet::W_FIXED) { + $total = array_sum($widths); + foreach($widths as $i => $w) { + $wr = ($w / $total) * $worksheet->getFixedSheetWidth(); + $widths[$i] = $wr; + } + } + foreach ($widths as $i => $width){ $colAffect = $i + 1; $colNode .= ''; From a41040db71dc914df729f9a2700708ec3a8de862 Mon Sep 17 00:00:00 2001 From: Xwiz Date: Sat, 5 Feb 2022 11:22:49 +0100 Subject: [PATCH 4/6] Minor fixes --- src/Spout/Writer/ODS/Manager/OptionsManager.php | 1 + src/Spout/Writer/ODS/Manager/Style/StyleManager.php | 1 - src/Spout/Writer/XLSX/Manager/OptionsManager.php | 1 + 3 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Spout/Writer/ODS/Manager/OptionsManager.php b/src/Spout/Writer/ODS/Manager/OptionsManager.php index da909bc28..8ad486988 100644 --- a/src/Spout/Writer/ODS/Manager/OptionsManager.php +++ b/src/Spout/Writer/ODS/Manager/OptionsManager.php @@ -34,6 +34,7 @@ protected function getSupportedOptions() Options::TEMP_FOLDER, Options::DEFAULT_ROW_STYLE, Options::ROWWIDTH_CALC_STYLE, + Options::ROWWIDTH_FIXED, Options::SHOULD_CREATE_NEW_SHEETS_AUTOMATICALLY, ]; } diff --git a/src/Spout/Writer/ODS/Manager/Style/StyleManager.php b/src/Spout/Writer/ODS/Manager/Style/StyleManager.php index cd2614363..9430f247a 100644 --- a/src/Spout/Writer/ODS/Manager/Style/StyleManager.php +++ b/src/Spout/Writer/ODS/Manager/Style/StyleManager.php @@ -165,7 +165,6 @@ public function getContentXmlAutomaticStylesSectionContent($manager, $worksheets $content .= $this->getStyleSectionContent($style); } - $content .= <<<'EOD' diff --git a/src/Spout/Writer/XLSX/Manager/OptionsManager.php b/src/Spout/Writer/XLSX/Manager/OptionsManager.php index 5efa2dbab..7be77be3b 100644 --- a/src/Spout/Writer/XLSX/Manager/OptionsManager.php +++ b/src/Spout/Writer/XLSX/Manager/OptionsManager.php @@ -38,6 +38,7 @@ protected function getSupportedOptions() Options::TEMP_FOLDER, Options::DEFAULT_ROW_STYLE, Options::ROWWIDTH_CALC_STYLE, + Options::ROWWIDTH_FIXED, Options::SHOULD_CREATE_NEW_SHEETS_AUTOMATICALLY, Options::SHOULD_USE_INLINE_STRINGS, ]; From 1b45affd3b11cf897b809d8ca1dd8defb0d24214 Mon Sep 17 00:00:00 2001 From: Xwiz Date: Sat, 12 Feb 2022 17:03:52 +0100 Subject: [PATCH 5/6] Change to mb_strlen --- src/Spout/Writer/Common/Entity/Worksheet.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Spout/Writer/Common/Entity/Worksheet.php b/src/Spout/Writer/Common/Entity/Worksheet.php index aa0b97f98..f572d4640 100644 --- a/src/Spout/Writer/Common/Entity/Worksheet.php +++ b/src/Spout/Writer/Common/Entity/Worksheet.php @@ -141,7 +141,7 @@ public function setMaxColumnWidth($zeroBasedIndex, $value) */ public function autoSetWidth($cell, $style, $zeroBasedIndex) { - $size = 1 + strlen($cell->getValue());//ensure we have at least 1 space + $size = 1 + mb_strlen($cell->getValue());//ensure we have at least 1 space $size *= $style->isFontBold() ? 1.2 : 1.0; $this->setMaxColumnWidth($zeroBasedIndex, $size); } From 0a56c40b715f9d3b05b63e661344fe3c989734a7 Mon Sep 17 00:00:00 2001 From: Xwiz Date: Sat, 12 Feb 2022 17:39:40 +0100 Subject: [PATCH 6/6] Add alternative width calculation option with empty space --- src/Spout/Writer/Common/Entity/Worksheet.php | 1 + src/Spout/Writer/Common/Helper/AppendHelper.php | 17 +++++++++++++++++ .../Writer/XLSX/Manager/WorksheetManager.php | 17 +++++++++++++++-- 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/Spout/Writer/Common/Entity/Worksheet.php b/src/Spout/Writer/Common/Entity/Worksheet.php index f572d4640..b1a5d0715 100644 --- a/src/Spout/Writer/Common/Entity/Worksheet.php +++ b/src/Spout/Writer/Common/Entity/Worksheet.php @@ -34,6 +34,7 @@ class Worksheet public const W_FULL = 1; public const W_FIXED = 2; + public const W_FULL_ALT = 3; public const W_NONE = 0; public const DEFAULT_COL_WIDTH = 30; public const DEFAULT_FIXED_WIDTH = 320; diff --git a/src/Spout/Writer/Common/Helper/AppendHelper.php b/src/Spout/Writer/Common/Helper/AppendHelper.php index 74cbf73e0..473df9623 100644 --- a/src/Spout/Writer/Common/Helper/AppendHelper.php +++ b/src/Spout/Writer/Common/Helper/AppendHelper.php @@ -28,4 +28,21 @@ public static function insertToFile($fp, $pos, $content) fwrite($fp, $trailer); return $fp; } + + /** + * This function overwrite data in pointer from specified position + * + * @param $fp Pointer to file only + * @param $pos Position to insert + * @param $content Content to insert + */ + public static function overwriteToFile($fp, $pos, $content) + { + $cur = ftell($fp); + fseek($fp, $pos); + fwrite($fp, $content); + fseek($fp, $cur); + return $fp; + } + } diff --git a/src/Spout/Writer/XLSX/Manager/WorksheetManager.php b/src/Spout/Writer/XLSX/Manager/WorksheetManager.php index 294ebca43..537c2ce82 100644 --- a/src/Spout/Writer/XLSX/Manager/WorksheetManager.php +++ b/src/Spout/Writer/XLSX/Manager/WorksheetManager.php @@ -120,11 +120,20 @@ public function startSheet(Worksheet $worksheet) $worksheet->setFilePointer($sheetFilePointer); $worksheet->setWidthCalculation($this->widthCalcuationStyle); $worksheet->setFixedSheetWidth($this->fixedWidth); - + \fwrite($sheetFilePointer, self::SHEET_XML_FILE_HEADER); if ($worksheet->getWidthCalculation() != Worksheet::W_NONE) { $this->headWritePosition = ftell($sheetFilePointer); } + //width calculation style 3 with empty spaces.. not suitable if column sizes more than 40 + if ($worksheet->getWidthCalculation() == Worksheet::W_FULL_ALT) { + //insert dummy nodes for up to 40 columns + for ($i = 0; $i < 40; $i++) { + $dummy = " "; + \fwrite($sheetFilePointer, $dummy); + } + } + \fwrite($sheetFilePointer, ''); } @@ -330,7 +339,11 @@ public function close(Worksheet $worksheet) $colNode .= ''; } $colNode .= ''; - $worksheetFilePointer = AppendHelper::insertToFile($worksheetFilePointer, $this->headWritePosition, $colNode); + if ($worksheet->getWidthCalculation() == Worksheet::W_FULL_ALT) { + $worksheetFilePointer = AppendHelper::overwriteToFile($worksheetFilePointer, $this->headWritePosition, $colNode); + } else { + $worksheetFilePointer = AppendHelper::insertToFile($worksheetFilePointer, $this->headWritePosition, $colNode); + } } \fwrite($worksheetFilePointer, '');