Enable est column width calculation
This commit is contained in:
parent
550a6831f3
commit
4f0e72c4e4
@ -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
|
||||
|
@ -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 @@ class Worksheet
|
||||
$this->externalSheet = $externalSheet;
|
||||
$this->maxNumColumns = 0;
|
||||
$this->lastWrittenRowIndex = 0;
|
||||
$this->columnWidths = [];
|
||||
$this->widthCalcuationStyle = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -78,6 +95,86 @@ class Worksheet
|
||||
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 @@ class Worksheet
|
||||
$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
|
||||
*/
|
||||
|
31
src/Spout/Writer/Common/Helper/AppendHelper.php
Normal file
31
src/Spout/Writer/Common/Helper/AppendHelper.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Box\Spout\Writer\Common\Helper;
|
||||
|
||||
class AppendHelper {
|
||||
|
||||
/**
|
||||
* Instead of seeking and re-writing from position, a better hack might be to write dummy empty data
|
||||
* Enough to take care of any length, then carefully overwrite
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* This function will truncate from specified position
|
||||
* Write data to be inserted and re-append the truncated data
|
||||
*
|
||||
* @param $fp Pointer to file only
|
||||
* @param $pos Position to insert
|
||||
* @param $content Content to insert
|
||||
*/
|
||||
public static function insertToFile($fp, $pos, $content)
|
||||
{
|
||||
fseek($fp, $pos);
|
||||
$trailer = stream_get_contents($fp);
|
||||
ftruncate($fp, $pos);
|
||||
fseek($fp, $pos);
|
||||
fwrite($fp, $content);
|
||||
fwrite($fp, $trailer);
|
||||
return $fp;
|
||||
}
|
||||
}
|
@ -48,7 +48,7 @@ class ManagerFactory implements ManagerFactoryInterface
|
||||
|
||||
$styleMerger = $this->createStyleMerger();
|
||||
$styleManager = $this->createStyleManager($optionsManager);
|
||||
$worksheetManager = $this->createWorksheetManager($styleManager, $styleMerger);
|
||||
$worksheetManager = $this->createWorksheetManager($optionsManager, $styleManager, $styleMerger);
|
||||
|
||||
return new WorkbookManager(
|
||||
$workbook,
|
||||
@ -63,16 +63,17 @@ class ManagerFactory implements ManagerFactoryInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -202,7 +202,7 @@ EOD;
|
||||
EOD;
|
||||
|
||||
$contentXmlFileContents .= $styleManager->getContentXmlFontFaceSectionContent();
|
||||
$contentXmlFileContents .= $styleManager->getContentXmlAutomaticStylesSectionContent($worksheets);
|
||||
$contentXmlFileContents .= $styleManager->getContentXmlAutomaticStylesSectionContent($worksheetManager, $worksheets);
|
||||
|
||||
$contentXmlFileContents .= '<office:body><office:spreadsheet>';
|
||||
|
||||
|
@ -33,6 +33,7 @@ class OptionsManager extends OptionsManagerAbstract
|
||||
return [
|
||||
Options::TEMP_FOLDER,
|
||||
Options::DEFAULT_ROW_STYLE,
|
||||
Options::ROWWIDTH_CALC_STYLE,
|
||||
Options::SHOULD_CREATE_NEW_SHEETS_AUTOMATICALLY,
|
||||
];
|
||||
}
|
||||
@ -45,5 +46,6 @@ class OptionsManager extends OptionsManagerAbstract
|
||||
$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);
|
||||
}
|
||||
}
|
||||
|
@ -151,17 +151,21 @@ EOD;
|
||||
/**
|
||||
* Returns the contents of the "<office:automatic-styles>" section, inside "content.xml" file.
|
||||
*
|
||||
* @param WorksheetManager $manager
|
||||
* @param Worksheet[] $worksheets
|
||||
* @return string
|
||||
*/
|
||||
public function getContentXmlAutomaticStylesSectionContent($worksheets)
|
||||
public function getContentXmlAutomaticStylesSectionContent($manager, $worksheets)
|
||||
{
|
||||
$content = '<office:automatic-styles>';
|
||||
|
||||
$content .= $manager->getWidthStylesContent($worksheets[0]);
|
||||
|
||||
foreach ($this->styleRegistry->getRegisteredStyles() as $style) {
|
||||
$content .= $this->getStyleSectionContent($style);
|
||||
}
|
||||
|
||||
|
||||
$content .= <<<'EOD'
|
||||
<style:style style:family="table-column" style:name="co1">
|
||||
<style:table-column-properties fo:break-before="auto"/>
|
||||
|
@ -9,6 +9,9 @@ use Box\Spout\Common\Exception\InvalidArgumentException;
|
||||
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 @@ class WorksheetManager implements WorksheetManagerInterface
|
||||
*/
|
||||
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 @@ class WorksheetManager implements WorksheetManagerInterface
|
||||
$tableStyleName = 'ta' . ($externalSheet->getIndex() + 1);
|
||||
|
||||
$tableElement = '<table:table table:style-name="' . $tableStyleName . '" table:name="' . $escapedSheetName . '">';
|
||||
$tableElement .= '<table:table-column table:default-cell-style-name="ce1" table:style-name="co1" table:number-columns-repeated="' . $worksheet->getMaxNumColumns() . '"/>';
|
||||
|
||||
if ($worksheet->getWidthCalculation() != Worksheet::W_NONE) {
|
||||
foreach ($worksheet->getColumnWidths() as $i => $w){
|
||||
$colNo = $i + 1;
|
||||
$tableElement .= '<table:table-column table:default-cell-style-name="ce1" table:style-name="co'.$colNo.'"/>';
|
||||
}
|
||||
} else {
|
||||
$tableElement .= '<table:table-column table:default-cell-style-name="ce1" table:style-name="co1" table:number-columns-repeated="' . $worksheet->getMaxNumColumns() . '"/>';
|
||||
}
|
||||
|
||||
return $tableElement;
|
||||
}
|
||||
@ -125,6 +150,10 @@ class WorksheetManager implements WorksheetManagerInterface
|
||||
/** @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 @@ class WorksheetManager implements WorksheetManagerInterface
|
||||
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 .= '<style:style style:name="co'.$colNo.
|
||||
'" style:family="table-column"><style:table-column-properties fo:break-before="auto" style:column-width="'.
|
||||
$win.
|
||||
'in"/></style:style>';
|
||||
}
|
||||
return $style;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the worksheet
|
||||
*
|
||||
|
@ -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 @@ abstract class WriterMultiSheetsAbstract extends WriterAbstract
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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}
|
||||
*/
|
||||
|
@ -37,6 +37,7 @@ class OptionsManager extends OptionsManagerAbstract
|
||||
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 @@ 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::ROWWIDTH_CALC_STYLE, 0);
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ use Box\Spout\Common\Exception\InvalidArgumentException;
|
||||
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'
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
|
||||
<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
|
||||
xmlns:xdr="http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing" xmlns:x14="http://schemas.microsoft.com/office/spreadsheetml/2009/9/main" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006">
|
||||
EOD;
|
||||
|
||||
/** @var bool Whether inline or shared strings should be used */
|
||||
@ -59,6 +61,12 @@ EOD;
|
||||
/** @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 @@ EOD;
|
||||
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 @@ EOD;
|
||||
*/
|
||||
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, '<sheetData>');
|
||||
}
|
||||
|
||||
@ -159,6 +172,12 @@ EOD;
|
||||
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 @@ EOD;
|
||||
}
|
||||
|
||||
\fwrite($worksheetFilePointer, '</sheetData>');
|
||||
|
||||
if ($worksheet->getWidthCalculation() != Worksheet::W_NONE) {
|
||||
$colNode ='<cols>';
|
||||
$widths = $worksheet->getColumnWidths();
|
||||
foreach ($widths as $i => $width){
|
||||
$colAffect = $i + 1;
|
||||
$colNode .= '<col hidden="false" collapsed="false" min="'.$colAffect.'" max="'.$colAffect.'" width="'.$width.'" customWidth="true"/>';
|
||||
}
|
||||
$colNode .= '</cols>';
|
||||
$worksheetFilePointer = AppendHelper::insertToFile($worksheetFilePointer, $this->headWritePosition, $colNode);
|
||||
}
|
||||
|
||||
\fwrite($worksheetFilePointer, '</worksheet>');
|
||||
\fclose($worksheetFilePointer);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user