Merge 0a56c40b715f9d3b05b63e661344fe3c989734a7 into 84596668410bea89d21aa9867b91e1550e359329
This commit is contained in:
commit
93c5bd21af
@ -16,6 +16,8 @@ abstract class Options
|
|||||||
// Multisheets options
|
// Multisheets options
|
||||||
public const TEMP_FOLDER = 'tempFolder';
|
public const TEMP_FOLDER = 'tempFolder';
|
||||||
public const DEFAULT_ROW_STYLE = 'defaultRowStyle';
|
public const DEFAULT_ROW_STYLE = 'defaultRowStyle';
|
||||||
|
public const ROWWIDTH_CALC_STYLE = 'rowCalcMethod';
|
||||||
|
public const ROWWIDTH_FIXED = 'rowFixedWith';
|
||||||
public const SHOULD_CREATE_NEW_SHEETS_AUTOMATICALLY = 'shouldCreateNewSheetsAutomatically';
|
public const SHOULD_CREATE_NEW_SHEETS_AUTOMATICALLY = 'shouldCreateNewSheetsAutomatically';
|
||||||
|
|
||||||
// XLSX specific options
|
// XLSX specific options
|
||||||
|
@ -23,6 +23,22 @@ class Worksheet
|
|||||||
/** @var int Index of the last written row */
|
/** @var int Index of the last written row */
|
||||||
private $lastWrittenRowIndex;
|
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_FULL_ALT = 3;
|
||||||
|
public const W_NONE = 0;
|
||||||
|
public const DEFAULT_COL_WIDTH = 30;
|
||||||
|
public const DEFAULT_FIXED_WIDTH = 320;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Worksheet constructor.
|
* Worksheet constructor.
|
||||||
*
|
*
|
||||||
@ -36,6 +52,8 @@ class Worksheet
|
|||||||
$this->externalSheet = $externalSheet;
|
$this->externalSheet = $externalSheet;
|
||||||
$this->maxNumColumns = 0;
|
$this->maxNumColumns = 0;
|
||||||
$this->lastWrittenRowIndex = 0;
|
$this->lastWrittenRowIndex = 0;
|
||||||
|
$this->columnWidths = [];
|
||||||
|
$this->widthCalcuationStyle = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -78,6 +96,79 @@ class Worksheet
|
|||||||
return $this->maxNumColumns;
|
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 = 1 + mb_strlen($cell->getValue());//ensure we have at least 1 space
|
||||||
|
$size *= $style->isFontBold() ? 1.2 : 1.0;
|
||||||
|
$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
|
* @param int $maxNumColumns
|
||||||
*/
|
*/
|
||||||
@ -86,6 +177,29 @@ class Worksheet
|
|||||||
$this->maxNumColumns = $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
|
* @return int
|
||||||
*/
|
*/
|
||||||
|
48
src/Spout/Writer/Common/Helper/AppendHelper.php
Normal file
48
src/Spout/Writer/Common/Helper/AppendHelper.php
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<?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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -48,7 +48,7 @@ class ManagerFactory implements ManagerFactoryInterface
|
|||||||
|
|
||||||
$styleMerger = $this->createStyleMerger();
|
$styleMerger = $this->createStyleMerger();
|
||||||
$styleManager = $this->createStyleManager($optionsManager);
|
$styleManager = $this->createStyleManager($optionsManager);
|
||||||
$worksheetManager = $this->createWorksheetManager($styleManager, $styleMerger);
|
$worksheetManager = $this->createWorksheetManager($optionsManager, $styleManager, $styleMerger);
|
||||||
|
|
||||||
return new WorkbookManager(
|
return new WorkbookManager(
|
||||||
$workbook,
|
$workbook,
|
||||||
@ -63,16 +63,17 @@ class ManagerFactory implements ManagerFactoryInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param OptionsManagerInterface $optionsManager
|
||||||
* @param StyleManager $styleManager
|
* @param StyleManager $styleManager
|
||||||
* @param StyleMerger $styleMerger
|
* @param StyleMerger $styleMerger
|
||||||
* @return WorksheetManager
|
* @return WorksheetManager
|
||||||
*/
|
*/
|
||||||
private function createWorksheetManager(StyleManager $styleManager, StyleMerger $styleMerger)
|
private function createWorksheetManager(OptionsManagerInterface $optionsManager, StyleManager $styleManager, StyleMerger $styleMerger)
|
||||||
{
|
{
|
||||||
$stringsEscaper = $this->helperFactory->createStringsEscaper();
|
$stringsEscaper = $this->helperFactory->createStringsEscaper();
|
||||||
$stringsHelper = $this->helperFactory->createStringHelper();
|
$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;
|
EOD;
|
||||||
|
|
||||||
$contentXmlFileContents .= $styleManager->getContentXmlFontFaceSectionContent();
|
$contentXmlFileContents .= $styleManager->getContentXmlFontFaceSectionContent();
|
||||||
$contentXmlFileContents .= $styleManager->getContentXmlAutomaticStylesSectionContent($worksheets);
|
$contentXmlFileContents .= $styleManager->getContentXmlAutomaticStylesSectionContent($worksheetManager, $worksheets);
|
||||||
|
|
||||||
$contentXmlFileContents .= '<office:body><office:spreadsheet>';
|
$contentXmlFileContents .= '<office:body><office:spreadsheet>';
|
||||||
|
|
||||||
|
@ -33,6 +33,8 @@ class OptionsManager extends OptionsManagerAbstract
|
|||||||
return [
|
return [
|
||||||
Options::TEMP_FOLDER,
|
Options::TEMP_FOLDER,
|
||||||
Options::DEFAULT_ROW_STYLE,
|
Options::DEFAULT_ROW_STYLE,
|
||||||
|
Options::ROWWIDTH_CALC_STYLE,
|
||||||
|
Options::ROWWIDTH_FIXED,
|
||||||
Options::SHOULD_CREATE_NEW_SHEETS_AUTOMATICALLY,
|
Options::SHOULD_CREATE_NEW_SHEETS_AUTOMATICALLY,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@ -45,5 +47,6 @@ class OptionsManager extends OptionsManagerAbstract
|
|||||||
$this->setOption(Options::TEMP_FOLDER, \sys_get_temp_dir());
|
$this->setOption(Options::TEMP_FOLDER, \sys_get_temp_dir());
|
||||||
$this->setOption(Options::DEFAULT_ROW_STYLE, $this->styleBuilder->build());
|
$this->setOption(Options::DEFAULT_ROW_STYLE, $this->styleBuilder->build());
|
||||||
$this->setOption(Options::SHOULD_CREATE_NEW_SHEETS_AUTOMATICALLY, true);
|
$this->setOption(Options::SHOULD_CREATE_NEW_SHEETS_AUTOMATICALLY, true);
|
||||||
|
$this->setOption(Options::ROWWIDTH_CALC_STYLE, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -151,13 +151,16 @@ EOD;
|
|||||||
/**
|
/**
|
||||||
* Returns the contents of the "<office:automatic-styles>" section, inside "content.xml" file.
|
* Returns the contents of the "<office:automatic-styles>" section, inside "content.xml" file.
|
||||||
*
|
*
|
||||||
|
* @param WorksheetManager $manager
|
||||||
* @param Worksheet[] $worksheets
|
* @param Worksheet[] $worksheets
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getContentXmlAutomaticStylesSectionContent($worksheets)
|
public function getContentXmlAutomaticStylesSectionContent($manager, $worksheets)
|
||||||
{
|
{
|
||||||
$content = '<office:automatic-styles>';
|
$content = '<office:automatic-styles>';
|
||||||
|
|
||||||
|
$content .= $manager->getWidthStylesContent($worksheets[0]);
|
||||||
|
|
||||||
foreach ($this->styleRegistry->getRegisteredStyles() as $style) {
|
foreach ($this->styleRegistry->getRegisteredStyles() as $style) {
|
||||||
$content .= $this->getStyleSectionContent($style);
|
$content .= $this->getStyleSectionContent($style);
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,9 @@ use Box\Spout\Common\Exception\InvalidArgumentException;
|
|||||||
use Box\Spout\Common\Exception\IOException;
|
use Box\Spout\Common\Exception\IOException;
|
||||||
use Box\Spout\Common\Helper\Escaper\ODS as ODSEscaper;
|
use Box\Spout\Common\Helper\Escaper\ODS as ODSEscaper;
|
||||||
use Box\Spout\Common\Helper\StringHelper;
|
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\Entity\Worksheet;
|
||||||
use Box\Spout\Writer\Common\Manager\RegisteredStyle;
|
use Box\Spout\Writer\Common\Manager\RegisteredStyle;
|
||||||
use Box\Spout\Writer\Common\Manager\Style\StyleMerger;
|
use Box\Spout\Writer\Common\Manager\Style\StyleMerger;
|
||||||
@ -33,20 +36,33 @@ class WorksheetManager implements WorksheetManagerInterface
|
|||||||
/** @var StyleMerger Helper to merge styles together */
|
/** @var StyleMerger Helper to merge styles together */
|
||||||
private $styleMerger;
|
private $styleMerger;
|
||||||
|
|
||||||
|
/** $int file pointer head position */
|
||||||
|
private $headWritePosition;
|
||||||
|
|
||||||
|
/** @var int Width calculation style */
|
||||||
|
protected $widthCalcuationStyle;
|
||||||
|
|
||||||
|
/** @var int Fixed Width */
|
||||||
|
protected $fixedWidth;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WorksheetManager constructor.
|
* WorksheetManager constructor.
|
||||||
*
|
*
|
||||||
|
* @param OptionsManagerInterface $optionsManager
|
||||||
* @param StyleManager $styleManager
|
* @param StyleManager $styleManager
|
||||||
* @param StyleMerger $styleMerger
|
* @param StyleMerger $styleMerger
|
||||||
* @param ODSEscaper $stringsEscaper
|
* @param ODSEscaper $stringsEscaper
|
||||||
* @param StringHelper $stringHelper
|
* @param StringHelper $stringHelper
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
|
OptionsManagerInterface $optionsManager,
|
||||||
StyleManager $styleManager,
|
StyleManager $styleManager,
|
||||||
StyleMerger $styleMerger,
|
StyleMerger $styleMerger,
|
||||||
ODSEscaper $stringsEscaper,
|
ODSEscaper $stringsEscaper,
|
||||||
StringHelper $stringHelper
|
StringHelper $stringHelper
|
||||||
) {
|
) {
|
||||||
|
$this->widthCalcuationStyle = $optionsManager->getOption(Options::ROWWIDTH_CALC_STYLE);
|
||||||
|
$this->fixedWidth = $optionsManager->getOption(Options::ROWWIDTH_FIXED);
|
||||||
$this->styleManager = $styleManager;
|
$this->styleManager = $styleManager;
|
||||||
$this->styleMerger = $styleMerger;
|
$this->styleMerger = $styleMerger;
|
||||||
$this->stringsEscaper = $stringsEscaper;
|
$this->stringsEscaper = $stringsEscaper;
|
||||||
@ -62,9 +78,15 @@ class WorksheetManager implements WorksheetManagerInterface
|
|||||||
*/
|
*/
|
||||||
public function startSheet(Worksheet $worksheet)
|
public function startSheet(Worksheet $worksheet)
|
||||||
{
|
{
|
||||||
$sheetFilePointer = \fopen($worksheet->getFilePath(), 'w');
|
$sheetFilePointer = \fopen($worksheet->getFilePath(), 'w+');
|
||||||
$this->throwIfSheetFilePointerIsNotAvailable($sheetFilePointer);
|
$this->throwIfSheetFilePointerIsNotAvailable($sheetFilePointer);
|
||||||
|
|
||||||
|
$worksheet->setWidthCalculation($this->widthCalcuationStyle);
|
||||||
|
$worksheet->setFixedSheetWidth($this->fixedWidth);
|
||||||
|
if ($worksheet->getWidthCalculation() != Worksheet::W_NONE) {
|
||||||
|
$this->headWritePosition = ftell($sheetFilePointer);
|
||||||
|
}
|
||||||
|
|
||||||
$worksheet->setFilePointer($sheetFilePointer);
|
$worksheet->setFilePointer($sheetFilePointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,7 +117,15 @@ class WorksheetManager implements WorksheetManagerInterface
|
|||||||
$tableStyleName = 'ta' . ($externalSheet->getIndex() + 1);
|
$tableStyleName = 'ta' . ($externalSheet->getIndex() + 1);
|
||||||
|
|
||||||
$tableElement = '<table:table table:style-name="' . $tableStyleName . '" table:name="' . $escapedSheetName . '">';
|
$tableElement = '<table:table table:style-name="' . $tableStyleName . '" table:name="' . $escapedSheetName . '">';
|
||||||
|
|
||||||
|
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() . '"/>';
|
$tableElement .= '<table:table-column table:default-cell-style-name="ce1" table:style-name="co1" table:number-columns-repeated="' . $worksheet->getMaxNumColumns() . '"/>';
|
||||||
|
}
|
||||||
|
|
||||||
return $tableElement;
|
return $tableElement;
|
||||||
}
|
}
|
||||||
@ -125,6 +155,10 @@ class WorksheetManager implements WorksheetManagerInterface
|
|||||||
/** @var Cell|null $nextCell */
|
/** @var Cell|null $nextCell */
|
||||||
$nextCell = isset($cells[$nextCellIndex]) ? $cells[$nextCellIndex] : null;
|
$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()) {
|
if ($nextCell === null || $cell->getValue() !== $nextCell->getValue()) {
|
||||||
$registeredStyle = $this->applyStyleAndRegister($cell, $rowStyle);
|
$registeredStyle = $this->applyStyleAndRegister($cell, $rowStyle);
|
||||||
$cellStyle = $registeredStyle->getStyle();
|
$cellStyle = $registeredStyle->getStyle();
|
||||||
@ -249,6 +283,42 @@ class WorksheetManager implements WorksheetManagerInterface
|
|||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate the related column widths style xml to be inserted in content.xml
|
||||||
|
* @param Worksheet $worksheet
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
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
|
||||||
|
|
||||||
|
//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){
|
||||||
|
//this is a rough equivalent based on pixel density,
|
||||||
|
$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
|
* Closes the worksheet
|
||||||
*
|
*
|
||||||
|
@ -27,6 +27,9 @@ abstract class WriterMultiSheetsAbstract extends WriterAbstract
|
|||||||
/** @var WorkbookManagerInterface|null */
|
/** @var WorkbookManagerInterface|null */
|
||||||
private $workbookManager;
|
private $workbookManager;
|
||||||
|
|
||||||
|
/** @var int Width calculation style */
|
||||||
|
protected $widthCalcuationStyle;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param OptionsManagerInterface $optionsManager
|
* @param OptionsManagerInterface $optionsManager
|
||||||
* @param GlobalFunctionsHelper $globalFunctionsHelper
|
* @param GlobalFunctionsHelper $globalFunctionsHelper
|
||||||
@ -146,6 +149,38 @@ 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set fixed sheet width size option
|
||||||
|
*
|
||||||
|
* @param int $option The fixed width
|
||||||
|
* @throws \Box\Spout\Writer\Exception\WriterAlreadyOpenedException If the writer was already opened
|
||||||
|
* @return Writer
|
||||||
|
*/
|
||||||
|
public function setFixedWidth($option)
|
||||||
|
{
|
||||||
|
$this->throwIfWriterAlreadyOpened('Writer must be configured before opening it.');
|
||||||
|
|
||||||
|
$this->optionsManager->setOption(Options::ROWWIDTH_FIXED, $option);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
|
@ -37,6 +37,8 @@ class OptionsManager extends OptionsManagerAbstract
|
|||||||
return [
|
return [
|
||||||
Options::TEMP_FOLDER,
|
Options::TEMP_FOLDER,
|
||||||
Options::DEFAULT_ROW_STYLE,
|
Options::DEFAULT_ROW_STYLE,
|
||||||
|
Options::ROWWIDTH_CALC_STYLE,
|
||||||
|
Options::ROWWIDTH_FIXED,
|
||||||
Options::SHOULD_CREATE_NEW_SHEETS_AUTOMATICALLY,
|
Options::SHOULD_CREATE_NEW_SHEETS_AUTOMATICALLY,
|
||||||
Options::SHOULD_USE_INLINE_STRINGS,
|
Options::SHOULD_USE_INLINE_STRINGS,
|
||||||
];
|
];
|
||||||
@ -56,5 +58,6 @@ class OptionsManager extends OptionsManagerAbstract
|
|||||||
$this->setOption(Options::DEFAULT_ROW_STYLE, $defaultRowStyle);
|
$this->setOption(Options::DEFAULT_ROW_STYLE, $defaultRowStyle);
|
||||||
$this->setOption(Options::SHOULD_CREATE_NEW_SHEETS_AUTOMATICALLY, true);
|
$this->setOption(Options::SHOULD_CREATE_NEW_SHEETS_AUTOMATICALLY, true);
|
||||||
$this->setOption(Options::SHOULD_USE_INLINE_STRINGS, 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\Exception\IOException;
|
||||||
use Box\Spout\Common\Helper\Escaper\XLSX as XLSXEscaper;
|
use Box\Spout\Common\Helper\Escaper\XLSX as XLSXEscaper;
|
||||||
use Box\Spout\Common\Helper\StringHelper;
|
use Box\Spout\Common\Helper\StringHelper;
|
||||||
|
use Box\Spout\Writer\Common\Helper\AppendHelper;
|
||||||
use Box\Spout\Common\Manager\OptionsManagerInterface;
|
use Box\Spout\Common\Manager\OptionsManagerInterface;
|
||||||
use Box\Spout\Writer\Common\Entity\Options;
|
use Box\Spout\Writer\Common\Entity\Options;
|
||||||
use Box\Spout\Writer\Common\Entity\Worksheet;
|
use Box\Spout\Writer\Common\Entity\Worksheet;
|
||||||
@ -35,7 +36,8 @@ class WorksheetManager implements WorksheetManagerInterface
|
|||||||
|
|
||||||
public const SHEET_XML_FILE_HEADER = <<<'EOD'
|
public const SHEET_XML_FILE_HEADER = <<<'EOD'
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
<?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;
|
EOD;
|
||||||
|
|
||||||
/** @var bool Whether inline or shared strings should be used */
|
/** @var bool Whether inline or shared strings should be used */
|
||||||
@ -59,6 +61,15 @@ EOD;
|
|||||||
/** @var StringHelper String helper */
|
/** @var StringHelper String helper */
|
||||||
private $stringHelper;
|
private $stringHelper;
|
||||||
|
|
||||||
|
/** $int file pointer head position */
|
||||||
|
private $headWritePosition;
|
||||||
|
|
||||||
|
/** @var int Width calculation style */
|
||||||
|
protected $widthCalcuationStyle;
|
||||||
|
|
||||||
|
/** @var int Fixed Width */
|
||||||
|
protected $fixedWidth;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WorksheetManager constructor.
|
* WorksheetManager constructor.
|
||||||
*
|
*
|
||||||
@ -80,6 +91,8 @@ EOD;
|
|||||||
StringHelper $stringHelper
|
StringHelper $stringHelper
|
||||||
) {
|
) {
|
||||||
$this->shouldUseInlineStrings = $optionsManager->getOption(Options::SHOULD_USE_INLINE_STRINGS);
|
$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->rowManager = $rowManager;
|
||||||
$this->styleManager = $styleManager;
|
$this->styleManager = $styleManager;
|
||||||
$this->styleMerger = $styleMerger;
|
$this->styleMerger = $styleMerger;
|
||||||
@ -101,12 +114,26 @@ EOD;
|
|||||||
*/
|
*/
|
||||||
public function startSheet(Worksheet $worksheet)
|
public function startSheet(Worksheet $worksheet)
|
||||||
{
|
{
|
||||||
$sheetFilePointer = \fopen($worksheet->getFilePath(), 'w');
|
$sheetFilePointer = \fopen($worksheet->getFilePath(), 'w+');
|
||||||
$this->throwIfSheetFilePointerIsNotAvailable($sheetFilePointer);
|
$this->throwIfSheetFilePointerIsNotAvailable($sheetFilePointer);
|
||||||
|
|
||||||
$worksheet->setFilePointer($sheetFilePointer);
|
$worksheet->setFilePointer($sheetFilePointer);
|
||||||
|
$worksheet->setWidthCalculation($this->widthCalcuationStyle);
|
||||||
|
$worksheet->setFixedSheetWidth($this->fixedWidth);
|
||||||
|
|
||||||
\fwrite($sheetFilePointer, self::SHEET_XML_FILE_HEADER);
|
\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, '<sheetData>');
|
\fwrite($sheetFilePointer, '<sheetData>');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,6 +186,12 @@ EOD;
|
|||||||
if ($registeredStyle->isMatchingRowStyle()) {
|
if ($registeredStyle->isMatchingRowStyle()) {
|
||||||
$rowStyle = $cellStyle; // Replace actual rowStyle (possibly with null id) by registered style (with id)
|
$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());
|
$rowXML .= $this->getCellXML($rowIndexOneBased, $columnIndexZeroBased, $cell, $cellStyle->getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -287,6 +320,32 @@ EOD;
|
|||||||
}
|
}
|
||||||
|
|
||||||
\fwrite($worksheetFilePointer, '</sheetData>');
|
\fwrite($worksheetFilePointer, '</sheetData>');
|
||||||
|
|
||||||
|
if ($worksheet->getWidthCalculation() != Worksheet::W_NONE) {
|
||||||
|
$colNode ='<cols>';
|
||||||
|
$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 .= '<col hidden="false" collapsed="false" min="'.$colAffect.'" max="'.$colAffect.'" width="'.$width.'" customWidth="true"/>';
|
||||||
|
}
|
||||||
|
$colNode .= '</cols>';
|
||||||
|
if ($worksheet->getWidthCalculation() == Worksheet::W_FULL_ALT) {
|
||||||
|
$worksheetFilePointer = AppendHelper::overwriteToFile($worksheetFilePointer, $this->headWritePosition, $colNode);
|
||||||
|
} else {
|
||||||
|
$worksheetFilePointer = AppendHelper::insertToFile($worksheetFilePointer, $this->headWritePosition, $colNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
\fwrite($worksheetFilePointer, '</worksheet>');
|
\fwrite($worksheetFilePointer, '</worksheet>');
|
||||||
\fclose($worksheetFilePointer);
|
\fclose($worksheetFilePointer);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user