Refactory Writer Styles to match new code organization (#433)

Decomposed old StyleHelper into StyleManager, StyleRegistry and StyleMerger.
This commit is contained in:
Adrien Loison 2017-05-30 13:05:18 +02:00 committed by GitHub
parent 238756ab6e
commit cc9a0b526b
34 changed files with 1005 additions and 762 deletions

View File

@ -1,147 +0,0 @@
<?php
namespace Box\Spout\Writer\Common\Helper;
use Box\Spout\Writer\Common\Entity\Style\Style;
use Box\Spout\Writer\Common\Manager\StyleManager;
/**
* Class StyleHelperAbstract
* This class provides helper functions to manage styles
*
* @package Box\Spout\Writer\Common\Helper
*/
abstract class StyleHelperAbstract implements StyleHelperInterface
{
/** @var StyleManager Style manager */
private $styleManager;
/** @var array [SERIALIZED_STYLE] => [STYLE_ID] mapping table, keeping track of the registered styles */
protected $serializedStyleToStyleIdMappingTable = [];
/** @var array [STYLE_ID] => [STYLE] mapping table, keeping track of the registered styles */
protected $styleIdToStyleMappingTable = [];
/**
* @param Style $defaultStyle
* @param StyleManager $styleManager
*/
public function __construct(Style $defaultStyle, StyleManager $styleManager)
{
$this->styleManager = $styleManager;
// This ensures that the default style is the first one to be registered
$this->registerStyle($defaultStyle);
}
/**
* Registers the given style as a used style.
* Duplicate styles won't be registered more than once.
*
* @param Style $style The style to be registered
* @return Style The registered style, updated with an internal ID.
*/
public function registerStyle($style)
{
$serializedStyle = $this->styleManager->serialize($style);
if (!$this->hasStyleAlreadyBeenRegistered($style)) {
$nextStyleId = count($this->serializedStyleToStyleIdMappingTable);
$style->setId($nextStyleId);
$this->serializedStyleToStyleIdMappingTable[$serializedStyle] = $nextStyleId;
$this->styleIdToStyleMappingTable[$nextStyleId] = $style;
}
return $this->getStyleFromSerializedStyle($serializedStyle);
}
/**
* Returns whether the given style has already been registered.
*
* @param Style $style
* @return bool
*/
protected function hasStyleAlreadyBeenRegistered($style)
{
$serializedStyle = $this->styleManager->serialize($style);
// Using isset here because it is way faster than array_key_exists...
return isset($this->serializedStyleToStyleIdMappingTable[$serializedStyle]);
}
/**
* Returns the registered style associated to the given serialization.
*
* @param string $serializedStyle The serialized style from which the actual style should be fetched from
* @return Style
*/
protected function getStyleFromSerializedStyle($serializedStyle)
{
$styleId = $this->serializedStyleToStyleIdMappingTable[$serializedStyle];
return $this->styleIdToStyleMappingTable[$styleId];
}
/**
* @return Style[] List of registered styles
*/
protected function getRegisteredStyles()
{
return array_values($this->styleIdToStyleMappingTable);
}
/**
* Returns the default style
*
* @return Style Default style
*/
protected function getDefaultStyle()
{
// By construction, the default style has ID 0
return $this->styleIdToStyleMappingTable[0];
}
/**
* Apply additional styles if the given row needs it.
* Typically, set "wrap text" if a cell contains a new line.
*
* @param Style $style The original style
* @param array $dataRow The row the style will be applied to
* @return Style The updated style
*/
public function applyExtraStylesIfNeeded($style, $dataRow)
{
$updatedStyle = $this->applyWrapTextIfCellContainsNewLine($style, $dataRow);
return $updatedStyle;
}
/**
* Set the "wrap text" option if a cell of the given row contains a new line.
*
* @NOTE: There is a bug on the Mac version of Excel (2011 and below) where new lines
* are ignored even when the "wrap text" option is set. This only occurs with
* inline strings (shared strings do work fine).
* A workaround would be to encode "\n" as "_x000D_" but it does not work
* on the Windows version of Excel...
*
* @param Style $style The original style
* @param array $dataRow The row the style will be applied to
* @return Style The eventually updated style
*/
protected function applyWrapTextIfCellContainsNewLine($style, $dataRow)
{
// if the "wrap text" option is already set, no-op
if ($style->hasSetWrapText()) {
return $style;
}
foreach ($dataRow as $cell) {
if (is_string($cell) && strpos($cell, "\n") !== false) {
$style->setShouldWrapText();
break;
}
}
return $style;
}
}

View File

@ -1,30 +0,0 @@
<?php
namespace Box\Spout\Writer\Common\Helper;
/**
* Interface StyleHelperInterface
*
* @package Box\Spout\Writer\Common\Helper
*/
interface StyleHelperInterface
{
/**
* Registers the given style as a used style.
* Duplicate styles won't be registered more than once.
*
* @param \Box\Spout\Writer\Common\Entity\Style\Style $style The style to be registered
* @return \Box\Spout\Writer\Common\Entity\Style\Style The registered style, updated with an internal ID.
*/
public function registerStyle($style);
/**
* Apply additional styles if the given row needs it.
* Typically, set "wrap text" if a cell contains a new line.
*
* @param \Box\Spout\Writer\Common\Entity\Style\Style $style The original style
* @param array $dataRow The row the style will be applied to
* @return \Box\Spout\Writer\Common\Entity\Style\Style The updated style
*/
public function applyExtraStylesIfNeeded($style, $dataRow);
}

View File

@ -0,0 +1,92 @@
<?php
namespace Box\Spout\Writer\Common\Manager\Style;
use Box\Spout\Writer\Common\Entity\Style\Style;
/**
* Class StyleManager
* Manages styles to be applied to a cell
*
* @package Box\Spout\Writer\Common\Manager\Style
*/
class StyleManager implements StyleManagerInterface
{
/** @var StyleRegistry Registry for all used styles */
protected $styleRegistry;
/**
* @param StyleRegistry $styleRegistry
*/
public function __construct(StyleRegistry $styleRegistry)
{
$this->styleRegistry = $styleRegistry;
}
/**
* Returns the default style
*
* @return Style Default style
*/
protected function getDefaultStyle()
{
// By construction, the default style has ID 0
return $this->styleRegistry->getRegisteredStyles()[0];
}
/**
* Registers the given style as a used style.
* Duplicate styles won't be registered more than once.
*
* @param Style $style The style to be registered
* @return Style The registered style, updated with an internal ID.
*/
public function registerStyle($style)
{
return $this->styleRegistry->registerStyle($style);
}
/**
* Apply additional styles if the given row needs it.
* Typically, set "wrap text" if a cell contains a new line.
*
* @param Style $style The original style
* @param array $dataRow The row the style will be applied to
* @return Style The updated style
*/
public function applyExtraStylesIfNeeded($style, $dataRow)
{
$updatedStyle = $this->applyWrapTextIfCellContainsNewLine($style, $dataRow);
return $updatedStyle;
}
/**
* Set the "wrap text" option if a cell of the given row contains a new line.
*
* @NOTE: There is a bug on the Mac version of Excel (2011 and below) where new lines
* are ignored even when the "wrap text" option is set. This only occurs with
* inline strings (shared strings do work fine).
* A workaround would be to encode "\n" as "_x000D_" but it does not work
* on the Windows version of Excel...
*
* @param Style $style The original style
* @param array $dataRow The row the style will be applied to
* @return Style The eventually updated style
*/
protected function applyWrapTextIfCellContainsNewLine($style, $dataRow)
{
// if the "wrap text" option is already set, no-op
if ($style->hasSetWrapText()) {
return $style;
}
foreach ($dataRow as $cell) {
if (is_string($cell) && strpos($cell, "\n") !== false) {
$style->setShouldWrapText();
break;
}
}
return $style;
}
}

View File

@ -0,0 +1,32 @@
<?php
namespace Box\Spout\Writer\Common\Manager\Style;
use Box\Spout\Writer\Common\Entity\Style\Style;
/**
* Interface StyleHManagernterface
*
* @package Box\Spout\Writer\Common\Manager\Style
*/
interface StyleManagerInterface
{
/**
* Registers the given style as a used style.
* Duplicate styles won't be registered more than once.
*
* @param Style $style The style to be registered
* @return Style The registered style, updated with an internal ID.
*/
public function registerStyle($style);
/**
* Apply additional styles if the given row needs it.
* Typically, set "wrap text" if a cell contains a new line.
*
* @param Style $style The original style
* @param array $dataRow The row the style will be applied to
* @return Style The updated style
*/
public function applyExtraStylesIfNeeded($style, $dataRow);
}

View File

@ -1,38 +1,19 @@
<?php <?php
namespace Box\Spout\Writer\Common\Manager; namespace Box\Spout\Writer\Common\Manager\Style;
use Box\Spout\Writer\Common\Entity\Style\Color;
use Box\Spout\Writer\Common\Entity\Style\Style; use Box\Spout\Writer\Common\Entity\Style\Style;
use Box\Spout\Writer\XLSX\Helper\BorderHelper;
/** /**
* Class StyleManager * Class StyleMerger
* Manages styles to be applied to a cell * Takes care of merging styles together
* *
* @package Box\Spout\Writer\Common\Manager\Style * @package Box\Spout\Writer\Common\Manager\Style
*/ */
class StyleManager class StyleMerger
{ {
/**
* Serializes the style for future comparison with other styles.
* The ID is excluded from the comparison, as we only care about
* actual style properties.
*
* @param Style $style
* @return string The serialized style
*/
public function serialize(Style $style)
{
// In order to be able to properly compare style, set static ID value
$currentId = $style->getId();
$style->setId(0);
$serializedStyle = serialize($style);
$style->setId($currentId);
return $serializedStyle;
}
/** /**
* Merges the current style with the given style, using the given style as a base. This means that: * Merges the current style with the given style, using the given style as a base. This means that:
* - if current style and base style both have property A set, use current style property's value * - if current style and base style both have property A set, use current style property's value

View File

@ -0,0 +1,115 @@
<?php
namespace Box\Spout\Writer\Common\Manager\Style;
use Box\Spout\Writer\Common\Entity\Style\Style;
/**
* Class StyleRegistry
* Registry for all used styles
*
* @package Box\Spout\Writer\Common\Manager\Style
*/
class StyleRegistry
{
/** @var array [SERIALIZED_STYLE] => [STYLE_ID] mapping table, keeping track of the registered styles */
protected $serializedStyleToStyleIdMappingTable = [];
/** @var array [STYLE_ID] => [STYLE] mapping table, keeping track of the registered styles */
protected $styleIdToStyleMappingTable = [];
/**
* @param Style $defaultStyle
*/
public function __construct(Style $defaultStyle)
{
// This ensures that the default style is the first one to be registered
$this->registerStyle($defaultStyle);
}
/**
* Registers the given style as a used style.
* Duplicate styles won't be registered more than once.
*
* @param Style $style The style to be registered
* @return Style The registered style, updated with an internal ID.
*/
public function registerStyle(Style $style)
{
$serializedStyle = $this->serialize($style);
if (!$this->hasStyleAlreadyBeenRegistered($style)) {
$nextStyleId = count($this->serializedStyleToStyleIdMappingTable);
$style->setId($nextStyleId);
$this->serializedStyleToStyleIdMappingTable[$serializedStyle] = $nextStyleId;
$this->styleIdToStyleMappingTable[$nextStyleId] = $style;
}
return $this->getStyleFromSerializedStyle($serializedStyle);
}
/**
* Returns whether the given style has already been registered.
*
* @param Style $style
* @return bool
*/
protected function hasStyleAlreadyBeenRegistered(Style $style)
{
$serializedStyle = $this->serialize($style);
// Using isset here because it is way faster than array_key_exists...
return isset($this->serializedStyleToStyleIdMappingTable[$serializedStyle]);
}
/**
* Returns the registered style associated to the given serialization.
*
* @param string $serializedStyle The serialized style from which the actual style should be fetched from
* @return Style
*/
protected function getStyleFromSerializedStyle($serializedStyle)
{
$styleId = $this->serializedStyleToStyleIdMappingTable[$serializedStyle];
return $this->styleIdToStyleMappingTable[$styleId];
}
/**
* @return Style[] List of registered styles
*/
public function getRegisteredStyles()
{
return array_values($this->styleIdToStyleMappingTable);
}
/**
* @param int $styleId
* @return Style
*/
public function getStyleFromStyleId($styleId)
{
return $this->styleIdToStyleMappingTable[$styleId];
}
/**
* Serializes the style for future comparison with other styles.
* The ID is excluded from the comparison, as we only care about
* actual style properties.
*
* @param Style $style
* @return string The serialized style
*/
public function serialize(Style $style)
{
// In order to be able to properly compare style, set static ID value
$currentId = $style->getId();
$style->setId(0);
$serializedStyle = serialize($style);
$style->setId($currentId);
return $serializedStyle;
}
}

View File

@ -4,8 +4,8 @@ namespace Box\Spout\Writer\Common\Manager;
use Box\Spout\Common\Exception\IOException; use Box\Spout\Common\Exception\IOException;
use Box\Spout\Writer\Common\Helper\FileSystemWithRootFolderHelperInterface; use Box\Spout\Writer\Common\Helper\FileSystemWithRootFolderHelperInterface;
use Box\Spout\Writer\Common\Helper\StyleHelperInterface;
use Box\Spout\Writer\Common\Entity\Options; use Box\Spout\Writer\Common\Entity\Options;
use Box\Spout\Writer\Common\Manager\Style\StyleManagerInterface;
use Box\Spout\Writer\Common\Sheet; use Box\Spout\Writer\Common\Sheet;
use Box\Spout\Writer\Common\Entity\Workbook; use Box\Spout\Writer\Common\Entity\Workbook;
use Box\Spout\Writer\Common\Entity\Worksheet; use Box\Spout\Writer\Common\Entity\Worksheet;
@ -31,14 +31,14 @@ abstract class WorkbookManagerAbstract implements WorkbookManagerInterface
/** @var WorksheetManagerInterface */ /** @var WorksheetManagerInterface */
protected $worksheetManager; protected $worksheetManager;
/** @var StyleHelperInterface */ /** @var StyleManagerInterface Manages styles */
protected $styleHelper; protected $styleManager;
/** @var FileSystemWithRootFolderHelperInterface Helper to perform file system operations */ /** @var FileSystemWithRootFolderHelperInterface Helper to perform file system operations */
protected $fileSystemHelper; protected $fileSystemHelper;
/** @var EntityFactory Factory to create entities */ /** @var EntityFactory Factory to create entities */
private $entityFactory; protected $entityFactory;
/** @var Worksheet The worksheet where data will be written to */ /** @var Worksheet The worksheet where data will be written to */
protected $currentWorksheet; protected $currentWorksheet;
@ -48,7 +48,7 @@ abstract class WorkbookManagerAbstract implements WorkbookManagerInterface
* @param Workbook $workbook * @param Workbook $workbook
* @param OptionsManagerInterface $optionsManager * @param OptionsManagerInterface $optionsManager
* @param WorksheetManagerInterface $worksheetManager * @param WorksheetManagerInterface $worksheetManager
* @param StyleHelperInterface $styleHelper * @param StyleManagerInterface $styleManager
* @param FileSystemWithRootFolderHelperInterface $fileSystemHelper * @param FileSystemWithRootFolderHelperInterface $fileSystemHelper
* @param EntityFactory $entityFactory * @param EntityFactory $entityFactory
*/ */
@ -56,14 +56,14 @@ abstract class WorkbookManagerAbstract implements WorkbookManagerInterface
Workbook $workbook, Workbook $workbook,
OptionsManagerInterface $optionsManager, OptionsManagerInterface $optionsManager,
WorksheetManagerInterface $worksheetManager, WorksheetManagerInterface $worksheetManager,
StyleHelperInterface $styleHelper, StyleManagerInterface $styleManager,
FileSystemWithRootFolderHelperInterface $fileSystemHelper, FileSystemWithRootFolderHelperInterface $fileSystemHelper,
EntityFactory $entityFactory) EntityFactory $entityFactory)
{ {
$this->workbook = $workbook; $this->workbook = $workbook;
$this->optionManager = $optionsManager; $this->optionManager = $optionsManager;
$this->worksheetManager = $worksheetManager; $this->worksheetManager = $worksheetManager;
$this->styleHelper = $styleHelper; $this->styleManager = $styleManager;
$this->fileSystemHelper = $fileSystemHelper; $this->fileSystemHelper = $fileSystemHelper;
$this->entityFactory = $entityFactory; $this->entityFactory = $entityFactory;
} }
@ -244,8 +244,8 @@ abstract class WorkbookManagerAbstract implements WorkbookManagerInterface
*/ */
private function addRowWithStyleToWorksheet(Worksheet $worksheet, $dataRow, Style $style) private function addRowWithStyleToWorksheet(Worksheet $worksheet, $dataRow, Style $style)
{ {
$updatedStyle = $this->styleHelper->applyExtraStylesIfNeeded($style, $dataRow); $updatedStyle = $this->styleManager->applyExtraStylesIfNeeded($style, $dataRow);
$registeredStyle = $this->styleHelper->registerStyle($updatedStyle); $registeredStyle = $this->styleManager->registerStyle($updatedStyle);
$this->worksheetManager->addRow($worksheet, $dataRow, $registeredStyle); $this->worksheetManager->addRow($worksheet, $dataRow, $registeredStyle);
// update max num columns for the worksheet // update max num columns for the worksheet

View File

@ -7,9 +7,9 @@ use Box\Spout\Writer\Common\Manager\OptionsManagerInterface;
use Box\Spout\Writer\Common\Entity\Options; use Box\Spout\Writer\Common\Entity\Options;
use Box\Spout\Writer\Common\Creator\EntityFactory; use Box\Spout\Writer\Common\Creator\EntityFactory;
use Box\Spout\Writer\Common\Creator\InternalFactoryInterface; use Box\Spout\Writer\Common\Creator\InternalFactoryInterface;
use Box\Spout\Writer\Common\Manager\StyleManager;
use Box\Spout\Writer\ODS\Helper\FileSystemHelper; use Box\Spout\Writer\ODS\Helper\FileSystemHelper;
use Box\Spout\Writer\ODS\Helper\StyleHelper; use Box\Spout\Writer\ODS\Manager\Style\StyleManager;
use Box\Spout\Writer\ODS\Manager\Style\StyleRegistry;
use Box\Spout\Writer\ODS\Manager\WorkbookManager; use Box\Spout\Writer\ODS\Manager\WorkbookManager;
use Box\Spout\Writer\ODS\Manager\WorksheetManager; use Box\Spout\Writer\ODS\Manager\WorksheetManager;
use \Box\Spout\Common\Escaper; use \Box\Spout\Common\Escaper;
@ -46,22 +46,41 @@ class InternalFactory implements InternalFactoryInterface
$fileSystemHelper = $this->createFileSystemHelper($optionsManager); $fileSystemHelper = $this->createFileSystemHelper($optionsManager);
$fileSystemHelper->createBaseFilesAndFolders(); $fileSystemHelper->createBaseFilesAndFolders();
$styleHelper = $this->createStyleHelper($optionsManager); $styleManager = $this->createStyleManager($optionsManager);
$worksheetManager = $this->createWorksheetManager($styleHelper); $worksheetManager = $this->createWorksheetManager();
return new WorkbookManager($workbook, $optionsManager, $worksheetManager, $styleHelper, $fileSystemHelper, $this->entityFactory); return new WorkbookManager($workbook, $optionsManager, $worksheetManager, $styleManager, $fileSystemHelper, $this->entityFactory);
} }
/** /**
* @param StyleHelper $styleHelper
* @return WorksheetManager * @return WorksheetManager
*/ */
private function createWorksheetManager(StyleHelper $styleHelper) private function createWorksheetManager()
{ {
$stringsEscaper = $this->createStringsEscaper(); $stringsEscaper = $this->createStringsEscaper();
$stringsHelper = $this->createStringHelper(); $stringsHelper = $this->createStringHelper();
return new WorksheetManager($styleHelper, $stringsEscaper, $stringsHelper); return new WorksheetManager($stringsEscaper, $stringsHelper);
}
/**
* @param OptionsManagerInterface $optionsManager
* @return StyleManager
*/
private function createStyleManager(OptionsManagerInterface $optionsManager)
{
$styleRegistry = $this->createStyleRegistry($optionsManager);
return new StyleManager($styleRegistry);
}
/**
* @param OptionsManagerInterface $optionsManager
* @return StyleRegistry
*/
private function createStyleRegistry(OptionsManagerInterface $optionsManager)
{
$defaultRowStyle = $optionsManager->getOption(Options::DEFAULT_ROW_STYLE);
return new StyleRegistry($defaultRowStyle);
} }
/** /**
@ -74,26 +93,6 @@ class InternalFactory implements InternalFactoryInterface
return new FileSystemHelper($tempFolder); return new FileSystemHelper($tempFolder);
} }
/**
* @param OptionsManagerInterface $optionsManager
* @return StyleHelper
*/
private function createStyleHelper(OptionsManagerInterface $optionsManager)
{
$defaultRowStyle = $optionsManager->getOption(Options::DEFAULT_ROW_STYLE);
$styleManager = $this->createStyleManager();
return new StyleHelper($defaultRowStyle, $styleManager);
}
/**
* @return StyleManager
*/
private function createStyleManager()
{
return new StyleManager();
}
/** /**
* @return Escaper\ODS * @return Escaper\ODS
*/ */

View File

@ -5,6 +5,7 @@ namespace Box\Spout\Writer\ODS\Helper;
use Box\Spout\Writer\Common\Helper\FileSystemWithRootFolderHelperInterface; use Box\Spout\Writer\Common\Helper\FileSystemWithRootFolderHelperInterface;
use Box\Spout\Writer\Common\Helper\ZipHelper; use Box\Spout\Writer\Common\Helper\ZipHelper;
use Box\Spout\Writer\Common\Entity\Worksheet; use Box\Spout\Writer\Common\Entity\Worksheet;
use Box\Spout\Writer\ODS\Manager\Style\StyleManager;
use Box\Spout\Writer\ODS\Manager\WorksheetManager; use Box\Spout\Writer\ODS\Manager\WorksheetManager;
/** /**
@ -175,19 +176,19 @@ EOD;
* Creates the "content.xml" file under the root folder * Creates the "content.xml" file under the root folder
* *
* @param WorksheetManager $worksheetManager * @param WorksheetManager $worksheetManager
* @param StyleManager $styleManager
* @param Worksheet[] $worksheets * @param Worksheet[] $worksheets
* @param StyleHelper $styleHelper
* @return FileSystemHelper * @return FileSystemHelper
*/ */
public function createContentFile($worksheetManager, $worksheets, $styleHelper) public function createContentFile($worksheetManager, $styleManager, $worksheets)
{ {
$contentXmlFileContents = <<<EOD $contentXmlFileContents = <<<EOD
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<office:document-content office:version="1.2" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:msoxl="http://schemas.microsoft.com/office/excel/formula" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:xlink="http://www.w3.org/1999/xlink"> <office:document-content office:version="1.2" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:msoxl="http://schemas.microsoft.com/office/excel/formula" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:xlink="http://www.w3.org/1999/xlink">
EOD; EOD;
$contentXmlFileContents .= $styleHelper->getContentXmlFontFaceSectionContent(); $contentXmlFileContents .= $styleManager->getContentXmlFontFaceSectionContent();
$contentXmlFileContents .= $styleHelper->getContentXmlAutomaticStylesSectionContent(count($worksheets)); $contentXmlFileContents .= $styleManager->getContentXmlAutomaticStylesSectionContent(count($worksheets));
$contentXmlFileContents .= '<office:body><office:spreadsheet>'; $contentXmlFileContents .= '<office:body><office:spreadsheet>';
@ -246,13 +247,13 @@ EOD;
/** /**
* Creates the "styles.xml" file under the root folder * Creates the "styles.xml" file under the root folder
* *
* @param StyleHelper $styleHelper * @param StyleManager $styleManager
* @param int $numWorksheets Number of created worksheets * @param int $numWorksheets Number of created worksheets
* @return FileSystemHelper * @return FileSystemHelper
*/ */
public function createStylesFile($styleHelper, $numWorksheets) public function createStylesFile($styleManager, $numWorksheets)
{ {
$stylesXmlFileContents = $styleHelper->getStylesXMLFileContent($numWorksheets); $stylesXmlFileContents = $styleManager->getStylesXMLFileContent($numWorksheets);
$this->createFileWithContents($this->rootFolder, self::STYLES_XML_FILE_NAME, $stylesXmlFileContents); $this->createFileWithContents($this->rootFolder, self::STYLES_XML_FILE_NAME, $stylesXmlFileContents);
return $this; return $this;

View File

@ -1,41 +1,20 @@
<?php <?php
namespace Box\Spout\Writer\ODS\Helper; namespace Box\Spout\Writer\ODS\Manager\Style;
use Box\Spout\Writer\Common\Helper\StyleHelperAbstract;
use Box\Spout\Writer\Common\Entity\Style\BorderPart; use Box\Spout\Writer\Common\Entity\Style\BorderPart;
use Box\Spout\Writer\ODS\Helper\BorderHelper;
/** /**
* Class StyleHelper * Class StyleManager
* This class provides helper functions to manage styles * Manages styles to be applied to a cell
* *
* @package Box\Spout\Writer\ODS\Helper * @package Box\Spout\Writer\ODS\Manager\Style
*/ */
class StyleHelper extends StyleHelperAbstract class StyleManager extends \Box\Spout\Writer\Common\Manager\Style\StyleManager
{ {
/** @var string[] [FONT_NAME] => [] Map whose keys contain all the fonts used */ /** @var StyleRegistry */
protected $usedFontsSet = []; protected $styleRegistry;
/**
* Registers the given style as a used style.
* Duplicate styles won't be registered more than once.
*
* @param \Box\Spout\Writer\Common\Entity\Style\Style $style The style to be registered
* @return \Box\Spout\Writer\Common\Entity\Style\Style The registered style, updated with an internal ID.
*/
public function registerStyle($style)
{
$this->usedFontsSet[$style->getFontName()] = true;
return parent::registerStyle($style);
}
/**
* @return string[] List of used fonts name
*/
protected function getUsedFonts()
{
return array_keys($this->usedFontsSet);
}
/** /**
* Returns the content of the "styles.xml" file, given a list of styles. * Returns the content of the "styles.xml" file, given a list of styles.
@ -70,7 +49,7 @@ EOD;
protected function getFontFaceSectionContent() protected function getFontFaceSectionContent()
{ {
$content = '<office:font-face-decls>'; $content = '<office:font-face-decls>';
foreach ($this->getUsedFonts() as $fontName) { foreach ($this->styleRegistry->getUsedFonts() as $fontName) {
$content .= '<style:font-face style:name="' . $fontName . '" svg:font-family="' . $fontName . '"/>'; $content .= '<style:font-face style:name="' . $fontName . '" svg:font-family="' . $fontName . '"/>';
} }
$content .= '</office:font-face-decls>'; $content .= '</office:font-face-decls>';
@ -162,7 +141,7 @@ EOD;
public function getContentXmlFontFaceSectionContent() public function getContentXmlFontFaceSectionContent()
{ {
$content = '<office:font-face-decls>'; $content = '<office:font-face-decls>';
foreach ($this->getUsedFonts() as $fontName) { foreach ($this->styleRegistry->getUsedFonts() as $fontName) {
$content .= '<style:font-face style:name="' . $fontName . '" svg:font-family="' . $fontName . '"/>'; $content .= '<style:font-face style:name="' . $fontName . '" svg:font-family="' . $fontName . '"/>';
} }
$content .= '</office:font-face-decls>'; $content .= '</office:font-face-decls>';
@ -180,7 +159,7 @@ EOD;
{ {
$content = '<office:automatic-styles>'; $content = '<office:automatic-styles>';
foreach ($this->getRegisteredStyles() as $style) { foreach ($this->styleRegistry->getRegisteredStyles() as $style) {
$content .= $this->getStyleSectionContent($style); $content .= $this->getStyleSectionContent($style);
} }

View File

@ -0,0 +1,40 @@
<?php
namespace Box\Spout\Writer\ODS\Manager\Style;
use Box\Spout\Writer\Common\Entity\Style\Style;
/**
* Class StyleRegistry
* Registry for all used styles
*
* @package Box\Spout\Writer\ODS\Manager\Style
*/
class StyleRegistry extends \Box\Spout\Writer\Common\Manager\Style\StyleRegistry
{
/** @var array [FONT_NAME] => [] Map whose keys contain all the fonts used */
protected $usedFontsSet = [];
/**
* Registers the given style as a used style.
* Duplicate styles won't be registered more than once.
*
* @param Style $style The style to be registered
* @return Style The registered style, updated with an internal ID.
*/
public function registerStyle(Style $style)
{
$registeredStyle = parent::registerStyle($style);
$this->usedFontsSet[$style->getFontName()] = true;
return $registeredStyle;
}
/**
* @return string[] List of used fonts name
*/
public function getUsedFonts()
{
return array_keys($this->usedFontsSet);
}
}

View File

@ -6,6 +6,7 @@ use Box\Spout\Writer\Common\Sheet;
use Box\Spout\Writer\Common\Manager\WorkbookManagerAbstract; use Box\Spout\Writer\Common\Manager\WorkbookManagerAbstract;
use Box\Spout\Writer\ODS\Helper\FileSystemHelper; use Box\Spout\Writer\ODS\Helper\FileSystemHelper;
use Box\Spout\Writer\ODS\Helper\StyleHelper; use Box\Spout\Writer\ODS\Helper\StyleHelper;
use Box\Spout\Writer\ODS\Manager\Style\StyleManager;
/** /**
* Class WorkbookManager * Class WorkbookManager
@ -27,11 +28,8 @@ class WorkbookManager extends WorkbookManagerAbstract
/** @var FileSystemHelper Helper to perform file system operations */ /** @var FileSystemHelper Helper to perform file system operations */
protected $fileSystemHelper; protected $fileSystemHelper;
/** @var StyleHelper Helper to apply styles */ /** @var StyleManager Manages styles */
protected $styleHelper; protected $styleManager;
/** @var int Maximum number of columns among all the written rows */
protected $maxNumColumns = 1;
/** /**
* @return int Maximum number of rows/columns a sheet can contain * @return int Maximum number of rows/columns a sheet can contain
@ -63,9 +61,9 @@ class WorkbookManager extends WorkbookManagerAbstract
$numWorksheets = count($worksheets); $numWorksheets = count($worksheets);
$this->fileSystemHelper $this->fileSystemHelper
->createContentFile($this->worksheetManager, $worksheets, $this->styleHelper) ->createContentFile($this->worksheetManager, $this->styleManager, $worksheets)
->deleteWorksheetTempFolder() ->deleteWorksheetTempFolder()
->createStylesFile($this->styleHelper, $numWorksheets) ->createStylesFile($this->styleManager, $numWorksheets)
->zipRootFolderAndCopyToStream($finalFilePointer); ->zipRootFolderAndCopyToStream($finalFilePointer);
} }
} }

View File

@ -8,8 +8,8 @@ use Box\Spout\Common\Helper\StringHelper;
use Box\Spout\Writer\Common\Entity\Cell; use Box\Spout\Writer\Common\Entity\Cell;
use Box\Spout\Writer\Common\Entity\Worksheet; use Box\Spout\Writer\Common\Entity\Worksheet;
use Box\Spout\Writer\Common\Manager\WorksheetManagerInterface; use Box\Spout\Writer\Common\Manager\WorksheetManagerInterface;
use Box\Spout\Writer\ODS\Helper\StyleHelper;
use Box\Spout\Writer\Common\Entity\Style\Style; use Box\Spout\Writer\Common\Entity\Style\Style;
use Box\Spout\Writer\ODS\Manager\Style\StyleManager;
/** /**
* Class WorksheetManager * Class WorksheetManager
@ -19,9 +19,6 @@ use Box\Spout\Writer\Common\Entity\Style\Style;
*/ */
class WorksheetManager implements WorksheetManagerInterface class WorksheetManager implements WorksheetManagerInterface
{ {
/** @var StyleHelper Helper to work with styles */
private $styleHelper;
/** @var \Box\Spout\Common\Escaper\ODS Strings escaper */ /** @var \Box\Spout\Common\Escaper\ODS Strings escaper */
private $stringsEscaper; private $stringsEscaper;
@ -31,16 +28,13 @@ class WorksheetManager implements WorksheetManagerInterface
/** /**
* WorksheetManager constructor. * WorksheetManager constructor.
* *
* @param StyleHelper $styleHelper
* @param \Box\Spout\Common\Escaper\ODS $stringsEscaper * @param \Box\Spout\Common\Escaper\ODS $stringsEscaper
* @param StringHelper $stringHelper * @param StringHelper $stringHelper
*/ */
public function __construct( public function __construct(
StyleHelper $styleHelper,
\Box\Spout\Common\Escaper\ODS $stringsEscaper, \Box\Spout\Common\Escaper\ODS $stringsEscaper,
StringHelper $stringHelper) StringHelper $stringHelper)
{ {
$this->styleHelper = $styleHelper;
$this->stringsEscaper = $stringsEscaper; $this->stringsEscaper = $stringsEscaper;
$this->stringHelper = $stringHelper; $this->stringHelper = $stringHelper;
} }

View File

@ -10,7 +10,7 @@ use Box\Spout\Common\Helper\GlobalFunctionsHelper;
use Box\Spout\Writer\Common\Entity\Options; use Box\Spout\Writer\Common\Entity\Options;
use Box\Spout\Writer\Common\Entity\Style\Style; use Box\Spout\Writer\Common\Entity\Style\Style;
use Box\Spout\Writer\Common\Manager\OptionsManagerInterface; use Box\Spout\Writer\Common\Manager\OptionsManagerInterface;
use Box\Spout\Writer\Common\Manager\StyleManager; use Box\Spout\Writer\Common\Manager\Style\StyleMerger;
use Box\Spout\Writer\Exception\WriterAlreadyOpenedException; use Box\Spout\Writer\Exception\WriterAlreadyOpenedException;
use Box\Spout\Writer\Exception\WriterNotOpenedException; use Box\Spout\Writer\Exception\WriterNotOpenedException;
@ -37,8 +37,8 @@ abstract class WriterAbstract implements WriterInterface
/** @var OptionsManagerInterface Writer options manager */ /** @var OptionsManagerInterface Writer options manager */
protected $optionsManager; protected $optionsManager;
/** @var StyleManager Style manager */ /** @var StyleMerger Helps merge styles together */
protected $styleManager; protected $styleMerger;
/** @var Style Style to be applied to the next written row(s) */ /** @var Style Style to be applied to the next written row(s) */
protected $rowStyle; protected $rowStyle;
@ -46,6 +46,17 @@ abstract class WriterAbstract implements WriterInterface
/** @var string Content-Type value for the header - to be defined by child class */ /** @var string Content-Type value for the header - to be defined by child class */
protected static $headerContentType; protected static $headerContentType;
/**
* @param OptionsManagerInterface $optionsManager
* @param StyleMerger $styleMerger
*/
public function __construct(OptionsManagerInterface $optionsManager, StyleMerger $styleMerger)
{
$this->optionsManager = $optionsManager;
$this->styleMerger = $styleMerger;
$this->resetRowStyleToDefault();
}
/** /**
* Opens the streamer and makes it ready to accept data. * Opens the streamer and makes it ready to accept data.
* *
@ -71,17 +82,6 @@ abstract class WriterAbstract implements WriterInterface
*/ */
abstract protected function closeWriter(); abstract protected function closeWriter();
/**
* @param OptionsManagerInterface $optionsManager
* @param StyleManager $styleManager
*/
public function __construct(OptionsManagerInterface $optionsManager, StyleManager $styleManager)
{
$this->optionsManager = $optionsManager;
$this->styleManager = $styleManager;
$this->resetRowStyleToDefault();
}
/** /**
* Sets the default styles for all rows added with "addRow". * Sets the default styles for all rows added with "addRow".
* Overriding the default style instead of using "addRowWithStyle" improves performance by 20%. * Overriding the default style instead of using "addRowWithStyle" improves performance by 20%.
@ -327,7 +327,7 @@ abstract class WriterAbstract implements WriterInterface
{ {
// Merge given style with the default one to inherit custom properties // Merge given style with the default one to inherit custom properties
$defaultRowStyle = $this->optionsManager->getOption(Options::DEFAULT_ROW_STYLE); $defaultRowStyle = $this->optionsManager->getOption(Options::DEFAULT_ROW_STYLE);
$this->rowStyle = $this->styleManager->merge($style, $defaultRowStyle); $this->rowStyle = $this->styleMerger->merge($style, $defaultRowStyle);
} }
/** /**

View File

@ -7,7 +7,7 @@ use Box\Spout\Common\Helper\GlobalFunctionsHelper;
use Box\Spout\Common\Type; use Box\Spout\Common\Type;
use Box\Spout\Writer\Common\Creator\EntityFactory; use Box\Spout\Writer\Common\Creator\EntityFactory;
use Box\Spout\Writer\Common\Creator\Style\StyleBuilder; use Box\Spout\Writer\Common\Creator\Style\StyleBuilder;
use Box\Spout\Writer\Common\Manager\StyleManager; use Box\Spout\Writer\Common\Manager\Style\StyleMerger;
/** /**
* Class WriterFactory * Class WriterFactory
@ -55,9 +55,9 @@ class WriterFactory
private static function getCSVWriter() private static function getCSVWriter()
{ {
$optionsManager = new CSV\Manager\OptionsManager(); $optionsManager = new CSV\Manager\OptionsManager();
$styleManager = new StyleManager(); $styleMerger = new StyleMerger();
return new CSV\Writer($optionsManager, $styleManager); return new CSV\Writer($optionsManager, $styleMerger);
} }
/** /**
@ -67,10 +67,10 @@ class WriterFactory
{ {
$styleBuilder = new StyleBuilder(); $styleBuilder = new StyleBuilder();
$optionsManager = new XLSX\Manager\OptionsManager($styleBuilder); $optionsManager = new XLSX\Manager\OptionsManager($styleBuilder);
$styleManager = new StyleManager(); $styleMerger = new StyleMerger();
$generalFactory = new XLSX\Creator\InternalFactory(new EntityFactory()); $generalFactory = new XLSX\Creator\InternalFactory(new EntityFactory());
return new XLSX\Writer($optionsManager, $styleManager, $generalFactory); return new XLSX\Writer($optionsManager, $styleMerger, $generalFactory);
} }
/** /**
@ -80,9 +80,9 @@ class WriterFactory
{ {
$styleBuilder = new StyleBuilder(); $styleBuilder = new StyleBuilder();
$optionsManager = new ODS\Manager\OptionsManager($styleBuilder); $optionsManager = new ODS\Manager\OptionsManager($styleBuilder);
$styleManager = new StyleManager(); $styleMerger = new StyleMerger();
$generalFactory = new ODS\Creator\InternalFactory(new EntityFactory()); $generalFactory = new ODS\Creator\InternalFactory(new EntityFactory());
return new ODS\Writer($optionsManager, $styleManager, $generalFactory); return new ODS\Writer($optionsManager, $styleMerger, $generalFactory);
} }
} }

View File

@ -5,7 +5,7 @@ namespace Box\Spout\Writer;
use Box\Spout\Writer\Common\Manager\OptionsManagerInterface; use Box\Spout\Writer\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;
use Box\Spout\Writer\Common\Manager\StyleManager; use Box\Spout\Writer\Common\Manager\Style\StyleMerger;
use Box\Spout\Writer\Exception\WriterNotOpenedException; use Box\Spout\Writer\Exception\WriterNotOpenedException;
use Box\Spout\Writer\Common\Creator\InternalFactoryInterface; use Box\Spout\Writer\Common\Creator\InternalFactoryInterface;
use Box\Spout\Writer\Common\Manager\WorkbookManagerInterface; use Box\Spout\Writer\Common\Manager\WorkbookManagerInterface;
@ -27,12 +27,12 @@ abstract class WriterMultiSheetsAbstract extends WriterAbstract
/** /**
* @param OptionsManagerInterface $optionsManager * @param OptionsManagerInterface $optionsManager
* @param StyleManager $styleManager * @param StyleMerger $styleMerger
* @param InternalFactoryInterface $internalFactory * @param InternalFactoryInterface $internalFactory
*/ */
public function __construct(OptionsManagerInterface $optionsManager, StyleManager $styleManager, InternalFactoryInterface $internalFactory) public function __construct(OptionsManagerInterface $optionsManager, StyleMerger $styleMerger, InternalFactoryInterface $internalFactory)
{ {
parent::__construct($optionsManager, $styleManager); parent::__construct($optionsManager, $styleMerger);
$this->internalFactory = $internalFactory; $this->internalFactory = $internalFactory;
} }

View File

@ -4,16 +4,14 @@ namespace Box\Spout\Writer\XLSX\Creator;
use Box\Spout\Common\Escaper; use Box\Spout\Common\Escaper;
use Box\Spout\Common\Helper\StringHelper; use Box\Spout\Common\Helper\StringHelper;
use Box\Spout\Writer\Common\Manager\OptionsManagerInterface;
use Box\Spout\Writer\Common\Entity\Options;
use Box\Spout\Writer\Common\Creator\EntityFactory; use Box\Spout\Writer\Common\Creator\EntityFactory;
use Box\Spout\Writer\Common\Creator\InternalFactoryInterface; use Box\Spout\Writer\Common\Creator\InternalFactoryInterface;
use Box\Spout\Writer\Common\Creator\WorkbookFactory; use Box\Spout\Writer\Common\Entity\Options;
use Box\Spout\Writer\Common\Creator\WorksheetFactory; use Box\Spout\Writer\Common\Manager\OptionsManagerInterface;
use Box\Spout\Writer\Common\Manager\StyleManager;
use Box\Spout\Writer\XLSX\Helper\FileSystemHelper; use Box\Spout\Writer\XLSX\Helper\FileSystemHelper;
use Box\Spout\Writer\XLSX\Helper\SharedStringsHelper; use Box\Spout\Writer\XLSX\Helper\SharedStringsHelper;
use Box\Spout\Writer\XLSX\Helper\StyleHelper; use Box\Spout\Writer\XLSX\Manager\Style\StyleManager;
use Box\Spout\Writer\XLSX\Manager\Style\StyleRegistry;
use Box\Spout\Writer\XLSX\Manager\WorkbookManager; use Box\Spout\Writer\XLSX\Manager\WorkbookManager;
use Box\Spout\Writer\XLSX\Manager\WorksheetManager; use Box\Spout\Writer\XLSX\Manager\WorksheetManager;
@ -52,29 +50,48 @@ class InternalFactory implements InternalFactoryInterface
$xlFolder = $fileSystemHelper->getXlFolder(); $xlFolder = $fileSystemHelper->getXlFolder();
$sharedStringsHelper = $this->createSharedStringsHelper($xlFolder); $sharedStringsHelper = $this->createSharedStringsHelper($xlFolder);
$styleHelper = $this->createStyleHelper($optionsManager); $styleManager = $this->createStyleManager($optionsManager);
$worksheetManager = $this->createWorksheetManager($optionsManager, $styleManager, $sharedStringsHelper);
$worksheetManager = $this->createWorksheetManager($optionsManager, $sharedStringsHelper, $styleHelper); return new WorkbookManager($workbook, $optionsManager, $worksheetManager, $styleManager, $fileSystemHelper, $this->entityFactory);
return new WorkbookManager($workbook, $optionsManager, $worksheetManager, $styleHelper, $fileSystemHelper, $this->entityFactory);
} }
/** /**
* @param OptionsManagerInterface $optionsManager * @param OptionsManagerInterface $optionsManager
* @param StyleManager $styleManager
* @param SharedStringsHelper $sharedStringsHelper * @param SharedStringsHelper $sharedStringsHelper
* @param StyleHelper $styleHelper
* @return WorksheetManager * @return WorksheetManager
*/ */
private function createWorksheetManager( private function createWorksheetManager(
OptionsManagerInterface $optionsManager, OptionsManagerInterface $optionsManager,
SharedStringsHelper $sharedStringsHelper, StyleManager $styleManager,
StyleHelper $styleHelper SharedStringsHelper $sharedStringsHelper
) )
{ {
$stringsEscaper = $this->createStringsEscaper(); $stringsEscaper = $this->createStringsEscaper();
$stringsHelper = $this->createStringHelper(); $stringsHelper = $this->createStringHelper();
return new WorksheetManager($optionsManager, $sharedStringsHelper, $styleHelper, $stringsEscaper, $stringsHelper); return new WorksheetManager($optionsManager, $styleManager, $sharedStringsHelper, $stringsEscaper, $stringsHelper);
}
/**
* @param OptionsManagerInterface $optionsManager
* @return StyleManager
*/
private function createStyleManager(OptionsManagerInterface $optionsManager)
{
$styleRegistry = $this->createStyleRegistry($optionsManager);
return new StyleManager($styleRegistry);
}
/**
* @param OptionsManagerInterface $optionsManager
* @return StyleRegistry
*/
private function createStyleRegistry(OptionsManagerInterface $optionsManager)
{
$defaultRowStyle = $optionsManager->getOption(Options::DEFAULT_ROW_STYLE);
return new StyleRegistry($defaultRowStyle);
} }
/** /**
@ -96,26 +113,6 @@ class InternalFactory implements InternalFactoryInterface
return new FileSystemHelper($tempFolder); return new FileSystemHelper($tempFolder);
} }
/**
* @param OptionsManagerInterface $optionsManager
* @return StyleHelper
*/
private function createStyleHelper(OptionsManagerInterface $optionsManager)
{
$defaultRowStyle = $optionsManager->getOption(Options::DEFAULT_ROW_STYLE);
$styleManager = $this->createStyleManager();
return new StyleHelper($defaultRowStyle, $styleManager);
}
/**
* @return StyleManager
*/
private function createStyleManager()
{
return new StyleManager();
}
/** /**
* @return Escaper\XLSX * @return Escaper\XLSX
*/ */

View File

@ -2,9 +2,10 @@
namespace Box\Spout\Writer\XLSX\Helper; namespace Box\Spout\Writer\XLSX\Helper;
use Box\Spout\Writer\Common\Entity\Worksheet;
use Box\Spout\Writer\Common\Helper\FileSystemWithRootFolderHelperInterface; use Box\Spout\Writer\Common\Helper\FileSystemWithRootFolderHelperInterface;
use Box\Spout\Writer\Common\Helper\ZipHelper; use Box\Spout\Writer\Common\Helper\ZipHelper;
use Box\Spout\Writer\Common\Entity\Worksheet; use Box\Spout\Writer\XLSX\Manager\Style\StyleManager;
/** /**
* Class FileSystemHelper * Class FileSystemHelper
@ -335,12 +336,12 @@ EOD;
/** /**
* Creates the "styles.xml" file under the "xl" folder * Creates the "styles.xml" file under the "xl" folder
* *
* @param StyleHelper $styleHelper * @param StyleManager $styleManager
* @return FileSystemHelper * @return FileSystemHelper
*/ */
public function createStylesFile($styleHelper) public function createStylesFile($styleManager)
{ {
$stylesXmlFileContents = $styleHelper->getStylesXMLFileContent(); $stylesXmlFileContents = $styleManager->getStylesXMLFileContent();
$this->createFileWithContents($this->xlFolder, self::STYLES_XML_FILE_NAME, $stylesXmlFileContents); $this->createFileWithContents($this->xlFolder, self::STYLES_XML_FILE_NAME, $stylesXmlFileContents);
return $this; return $this;

View File

@ -1,124 +1,21 @@
<?php <?php
namespace Box\Spout\Writer\XLSX\Helper; namespace Box\Spout\Writer\XLSX\Manager\Style;
use Box\Spout\Writer\Common\Helper\StyleHelperAbstract;
use Box\Spout\Writer\Common\Entity\Style\Color; use Box\Spout\Writer\Common\Entity\Style\Color;
use Box\Spout\Writer\Common\Entity\Style\Style; use Box\Spout\Writer\Common\Entity\Style\Style;
use Box\Spout\Writer\XLSX\Helper\BorderHelper;
/** /**
* Class StyleHelper * Class StyleManager
* This class provides helper functions to manage styles * Manages styles to be applied to a cell
* *
* @package Box\Spout\Writer\XLSX\Helper * @package Box\Spout\Writer\XLSX\Manager\Style
*/ */
class StyleHelper extends StyleHelperAbstract class StyleManager extends \Box\Spout\Writer\Common\Manager\Style\StyleManager
{ {
/** /** @var StyleRegistry */
* @var array protected $styleRegistry;
*/
protected $registeredFills = [];
/**
* @var array [STYLE_ID] => [FILL_ID] maps a style to a fill declaration
*/
protected $styleIdToFillMappingTable = [];
/**
* Excel preserves two default fills with index 0 and 1
* Since Excel is the dominant vendor - we play along here
*
* @var int The fill index counter for custom fills.
*/
protected $fillIndex = 2;
/**
* @var array
*/
protected $registeredBorders = [];
/**
* @var array [STYLE_ID] => [BORDER_ID] maps a style to a border declaration
*/
protected $styleIdToBorderMappingTable = [];
/**
* XLSX specific operations on the registered styles
*
* @param \Box\Spout\Writer\Common\Entity\Style\Style $style
* @return \Box\Spout\Writer\Common\Entity\Style\Style
*/
public function registerStyle($style)
{
$registeredStyle = parent::registerStyle($style);
$this->registerFill($registeredStyle);
$this->registerBorder($registeredStyle);
return $registeredStyle;
}
/**
* Register a fill definition
*
* @param \Box\Spout\Writer\Common\Entity\Style\Style $style
*/
protected function registerFill($style)
{
$styleId = $style->getId();
// Currently - only solid backgrounds are supported
// so $backgroundColor is a scalar value (RGB Color)
$backgroundColor = $style->getBackgroundColor();
if ($backgroundColor) {
$isBackgroundColorRegistered = isset($this->registeredFills[$backgroundColor]);
// We need to track the already registered background definitions
if ($isBackgroundColorRegistered) {
$registeredStyleId = $this->registeredFills[$backgroundColor];
$registeredFillId = $this->styleIdToFillMappingTable[$registeredStyleId];
$this->styleIdToFillMappingTable[$styleId] = $registeredFillId;
} else {
$this->registeredFills[$backgroundColor] = $styleId;
$this->styleIdToFillMappingTable[$styleId] = $this->fillIndex++;
}
} else {
// The fillId maps a style to a fill declaration
// When there is no background color definition - we default to 0
$this->styleIdToFillMappingTable[$styleId] = 0;
}
}
/**
* Register a border definition
*
* @param \Box\Spout\Writer\Common\Entity\Style\Style $style
*/
protected function registerBorder($style)
{
$styleId = $style->getId();
if ($style->shouldApplyBorder()) {
$border = $style->getBorder();
$serializedBorder = serialize($border);
$isBorderAlreadyRegistered = isset($this->registeredBorders[$serializedBorder]);
if ($isBorderAlreadyRegistered) {
$registeredStyleId = $this->registeredBorders[$serializedBorder];
$registeredBorderId = $this->styleIdToBorderMappingTable[$registeredStyleId];
$this->styleIdToBorderMappingTable[$styleId] = $registeredBorderId;
} else {
$this->registeredBorders[$serializedBorder] = $styleId;
$this->styleIdToBorderMappingTable[$styleId] = count($this->registeredBorders);
}
} else {
// If no border should be applied - the mapping is the default border: 0
$this->styleIdToBorderMappingTable[$styleId] = 0;
}
}
/** /**
* For empty cells, we can specify a style or not. If no style are specified, * For empty cells, we can specify a style or not. If no style are specified,
@ -132,8 +29,11 @@ class StyleHelper extends StyleHelperAbstract
*/ */
public function shouldApplyStyleOnEmptyCell($styleId) public function shouldApplyStyleOnEmptyCell($styleId)
{ {
$hasStyleCustomFill = (isset($this->styleIdToFillMappingTable[$styleId]) && $this->styleIdToFillMappingTable[$styleId] !== 0); $associatedFillId = $this->styleRegistry->getFillIdForStyleId($styleId);
$hasStyleCustomBorders = (isset($this->styleIdToBorderMappingTable[$styleId]) && $this->styleIdToBorderMappingTable[$styleId] !== 0); $hasStyleCustomFill = ($associatedFillId !== null && $associatedFillId !== 0);
$associatedBorderId = $this->styleRegistry->getBorderIdForStyleId($styleId);
$hasStyleCustomBorders = ($associatedBorderId !== null && $associatedBorderId !== 0);
return ($hasStyleCustomFill || $hasStyleCustomBorders); return ($hasStyleCustomFill || $hasStyleCustomBorders);
} }
@ -172,10 +72,12 @@ EOD;
*/ */
protected function getFontsSectionContent() protected function getFontsSectionContent()
{ {
$content = '<fonts count="' . count($this->styleIdToStyleMappingTable) . '">'; $registeredStyles = $this->styleRegistry->getRegisteredStyles();
/** @var \Box\Spout\Writer\Common\Entity\Style\Style $style */ $content = '<fonts count="' . count($registeredStyles) . '">';
foreach ($this->getRegisteredStyles() as $style) {
/** @var Style $style */
foreach ($registeredStyles as $style) {
$content .= '<font>'; $content .= '<font>';
$content .= '<sz val="' . $style->getFontSize() . '"/>'; $content .= '<sz val="' . $style->getFontSize() . '"/>';
@ -210,17 +112,19 @@ EOD;
*/ */
protected function getFillsSectionContent() protected function getFillsSectionContent()
{ {
$registeredFills = $this->styleRegistry->getRegisteredFills();
// Excel reserves two default fills // Excel reserves two default fills
$fillsCount = count($this->registeredFills) + 2; $fillsCount = count($registeredFills) + 2;
$content = sprintf('<fills count="%d">', $fillsCount); $content = sprintf('<fills count="%d">', $fillsCount);
$content .= '<fill><patternFill patternType="none"/></fill>'; $content .= '<fill><patternFill patternType="none"/></fill>';
$content .= '<fill><patternFill patternType="gray125"/></fill>'; $content .= '<fill><patternFill patternType="gray125"/></fill>';
// The other fills are actually registered by setting a background color // The other fills are actually registered by setting a background color
foreach ($this->registeredFills as $styleId) { foreach ($registeredFills as $styleId) {
/** @var Style $style */ /** @var Style $style */
$style = $this->styleIdToStyleMappingTable[$styleId]; $style = $this->styleRegistry->getStyleFromStyleId($styleId);
$backgroundColor = $style->getBackgroundColor(); $backgroundColor = $style->getBackgroundColor();
$content .= sprintf( $content .= sprintf(
@ -241,18 +145,19 @@ EOD;
*/ */
protected function getBordersSectionContent() protected function getBordersSectionContent()
{ {
$registeredBorders = $this->styleRegistry->getRegisteredBorders();
// There is one default border with index 0 // There is one default border with index 0
$borderCount = count($this->registeredBorders) + 1; $borderCount = count($registeredBorders) + 1;
$content = '<borders count="' . $borderCount . '">'; $content = '<borders count="' . $borderCount . '">';
// Default border starting at index 0 // Default border starting at index 0
$content .= '<border><left/><right/><top/><bottom/></border>'; $content .= '<border><left/><right/><top/><bottom/></border>';
foreach ($this->registeredBorders as $styleId) { foreach ($registeredBorders as $styleId) {
/** @var \Box\Spout\Writer\Common\Entity\Style\Style $style */ /** @var \Box\Spout\Writer\Common\Entity\Style\Style $style */
$style = $this->styleIdToStyleMappingTable[$styleId]; $style = $this->styleRegistry->getStyleFromStyleId($styleId);
$border = $style->getBorder(); $border = $style->getBorder();
$content .= '<border>'; $content .= '<border>';
@ -265,7 +170,6 @@ EOD;
$part = $border->getPart($partName); $part = $border->getPart($partName);
$content .= BorderHelper::serializeBorderPart($part); $content .= BorderHelper::serializeBorderPart($part);
} }
} }
$content .= '</border>'; $content .= '</border>';
@ -297,14 +201,14 @@ EOD;
*/ */
protected function getCellXfsSectionContent() protected function getCellXfsSectionContent()
{ {
$registeredStyles = $this->getRegisteredStyles(); $registeredStyles = $this->styleRegistry->getRegisteredStyles();
$content = '<cellXfs count="' . count($registeredStyles) . '">'; $content = '<cellXfs count="' . count($registeredStyles) . '">';
foreach ($registeredStyles as $style) { foreach ($registeredStyles as $style) {
$styleId = $style->getId(); $styleId = $style->getId();
$fillId = $this->styleIdToFillMappingTable[$styleId]; $fillId = $this->styleRegistry->getFillIdForStyleId($styleId);
$borderId = $this->styleIdToBorderMappingTable[$styleId]; $borderId = $this->styleRegistry->getBorderIdForStyleId($styleId);
$content .= '<xf numFmtId="0" fontId="' . $styleId . '" fillId="' . $fillId . '" borderId="' . $borderId . '" xfId="0"'; $content .= '<xf numFmtId="0" fontId="' . $styleId . '" fillId="' . $fillId . '" borderId="' . $borderId . '" xfId="0"';

View File

@ -0,0 +1,158 @@
<?php
namespace Box\Spout\Writer\XLSX\Manager\Style;
use Box\Spout\Writer\Common\Entity\Style\Style;
/**
* Class StyleRegistry
* Registry for all used styles
*
* @package Box\Spout\Writer\XLSX\Manager\Style
*/
class StyleRegistry extends \Box\Spout\Writer\Common\Manager\Style\StyleRegistry
{
/**
* @var array
*/
protected $registeredFills = [];
/**
* @var array [STYLE_ID] => [FILL_ID] maps a style to a fill declaration
*/
protected $styleIdToFillMappingTable = [];
/**
* Excel preserves two default fills with index 0 and 1
* Since Excel is the dominant vendor - we play along here
*
* @var int The fill index counter for custom fills.
*/
protected $fillIndex = 2;
/**
* @var array
*/
protected $registeredBorders = [];
/**
* @var array [STYLE_ID] => [BORDER_ID] maps a style to a border declaration
*/
protected $styleIdToBorderMappingTable = [];
/**
* XLSX specific operations on the registered styles
*
* @param Style $style
* @return Style
*/
public function registerStyle(Style $style)
{
$registeredStyle = parent::registerStyle($style);
$this->registerFill($registeredStyle);
$this->registerBorder($registeredStyle);
return $registeredStyle;
}
/**
* Register a fill definition
*
* @param Style $style
*/
private function registerFill(Style $style)
{
$styleId = $style->getId();
// Currently - only solid backgrounds are supported
// so $backgroundColor is a scalar value (RGB Color)
$backgroundColor = $style->getBackgroundColor();
if ($backgroundColor) {
$isBackgroundColorRegistered = isset($this->registeredFills[$backgroundColor]);
// We need to track the already registered background definitions
if ($isBackgroundColorRegistered) {
$registeredStyleId = $this->registeredFills[$backgroundColor];
$registeredFillId = $this->styleIdToFillMappingTable[$registeredStyleId];
$this->styleIdToFillMappingTable[$styleId] = $registeredFillId;
} else {
$this->registeredFills[$backgroundColor] = $styleId;
$this->styleIdToFillMappingTable[$styleId] = $this->fillIndex++;
}
} else {
// The fillId maps a style to a fill declaration
// When there is no background color definition - we default to 0
$this->styleIdToFillMappingTable[$styleId] = 0;
}
}
/**
* @param int $styleId
* @return int|null Fill ID associated to the given style ID
*/
public function getFillIdForStyleId($styleId)
{
return (isset($this->styleIdToFillMappingTable[$styleId])) ?
$this->styleIdToFillMappingTable[$styleId] :
null;
}
/**
* Register a border definition
*
* @param Style $style
*/
private function registerBorder(Style $style)
{
$styleId = $style->getId();
if ($style->shouldApplyBorder()) {
$border = $style->getBorder();
$serializedBorder = serialize($border);
$isBorderAlreadyRegistered = isset($this->registeredBorders[$serializedBorder]);
if ($isBorderAlreadyRegistered) {
$registeredStyleId = $this->registeredBorders[$serializedBorder];
$registeredBorderId = $this->styleIdToBorderMappingTable[$registeredStyleId];
$this->styleIdToBorderMappingTable[$styleId] = $registeredBorderId;
} else {
$this->registeredBorders[$serializedBorder] = $styleId;
$this->styleIdToBorderMappingTable[$styleId] = count($this->registeredBorders);
}
} else {
// If no border should be applied - the mapping is the default border: 0
$this->styleIdToBorderMappingTable[$styleId] = 0;
}
}
/**
* @param int $styleId
* @return int|null Fill ID associated to the given style ID
*/
public function getBorderIdForStyleId($styleId)
{
return (isset($this->styleIdToBorderMappingTable[$styleId])) ?
$this->styleIdToBorderMappingTable[$styleId] :
null;
}
/**
* @return array
*/
public function getRegisteredFills()
{
return $this->registeredFills;
}
/**
* @return array
*/
public function getRegisteredBorders()
{
return $this->registeredBorders;
}
}

View File

@ -5,7 +5,7 @@ namespace Box\Spout\Writer\XLSX\Manager;
use Box\Spout\Writer\Common\Sheet; use Box\Spout\Writer\Common\Sheet;
use Box\Spout\Writer\Common\Manager\WorkbookManagerAbstract; use Box\Spout\Writer\Common\Manager\WorkbookManagerAbstract;
use Box\Spout\Writer\XLSX\Helper\FileSystemHelper; use Box\Spout\Writer\XLSX\Helper\FileSystemHelper;
use Box\Spout\Writer\XLSX\Helper\StyleHelper; use Box\Spout\Writer\XLSX\Manager\Style\StyleManager;
/** /**
* Class WorkbookManager * Class WorkbookManager
@ -24,12 +24,12 @@ class WorkbookManager extends WorkbookManagerAbstract
/** @var WorksheetManager Object used to manage worksheets */ /** @var WorksheetManager Object used to manage worksheets */
protected $worksheetManager; protected $worksheetManager;
/** @var StyleManager Manages styles */
protected $styleManager;
/** @var FileSystemHelper Helper to perform file system operations */ /** @var FileSystemHelper Helper to perform file system operations */
protected $fileSystemHelper; protected $fileSystemHelper;
/** @var StyleHelper Helper to apply styles */
protected $styleHelper;
/** /**
* @return int Maximum number of rows/columns a sheet can contain * @return int Maximum number of rows/columns a sheet can contain
*/ */
@ -72,7 +72,7 @@ class WorkbookManager extends WorkbookManagerAbstract
->createContentTypesFile($worksheets) ->createContentTypesFile($worksheets)
->createWorkbookFile($worksheets) ->createWorkbookFile($worksheets)
->createWorkbookRelsFile($worksheets) ->createWorkbookRelsFile($worksheets)
->createStylesFile($this->styleHelper) ->createStylesFile($this->styleManager)
->zipRootFolderAndCopyToStream($finalFilePointer); ->zipRootFolderAndCopyToStream($finalFilePointer);
} }
} }

View File

@ -13,7 +13,7 @@ use Box\Spout\Writer\Common\Entity\Worksheet;
use Box\Spout\Writer\Common\Manager\WorksheetManagerInterface; use Box\Spout\Writer\Common\Manager\WorksheetManagerInterface;
use Box\Spout\Writer\Common\Entity\Style\Style; use Box\Spout\Writer\Common\Entity\Style\Style;
use Box\Spout\Writer\XLSX\Helper\SharedStringsHelper; use Box\Spout\Writer\XLSX\Helper\SharedStringsHelper;
use Box\Spout\Writer\XLSX\Helper\StyleHelper; use Box\Spout\Writer\XLSX\Manager\Style\StyleManager;
/** /**
* Class WorksheetManager * Class WorksheetManager
@ -39,12 +39,12 @@ EOD;
/** @var bool Whether inline or shared strings should be used */ /** @var bool Whether inline or shared strings should be used */
protected $shouldUseInlineStrings; protected $shouldUseInlineStrings;
/** @var StyleManager Manages styles */
private $styleManager;
/** @var SharedStringsHelper Helper to write shared strings */ /** @var SharedStringsHelper Helper to write shared strings */
private $sharedStringsHelper; private $sharedStringsHelper;
/** @var StyleHelper Helper to work with styles */
private $styleHelper;
/** @var \Box\Spout\Common\Escaper\XLSX Strings escaper */ /** @var \Box\Spout\Common\Escaper\XLSX Strings escaper */
private $stringsEscaper; private $stringsEscaper;
@ -55,21 +55,21 @@ EOD;
* WorksheetManager constructor. * WorksheetManager constructor.
* *
* @param OptionsManagerInterface $optionsManager * @param OptionsManagerInterface $optionsManager
* @param StyleManager $styleManager
* @param SharedStringsHelper $sharedStringsHelper * @param SharedStringsHelper $sharedStringsHelper
* @param StyleHelper $styleHelper
* @param \Box\Spout\Common\Escaper\XLSX $stringsEscaper * @param \Box\Spout\Common\Escaper\XLSX $stringsEscaper
* @param StringHelper $stringHelper * @param StringHelper $stringHelper
*/ */
public function __construct( public function __construct(
OptionsManagerInterface $optionsManager, OptionsManagerInterface $optionsManager,
StyleManager $styleManager,
SharedStringsHelper $sharedStringsHelper, SharedStringsHelper $sharedStringsHelper,
StyleHelper $styleHelper,
\Box\Spout\Common\Escaper\XLSX $stringsEscaper, \Box\Spout\Common\Escaper\XLSX $stringsEscaper,
StringHelper $stringHelper) StringHelper $stringHelper)
{ {
$this->shouldUseInlineStrings = $optionsManager->getOption(Options::SHOULD_USE_INLINE_STRINGS); $this->shouldUseInlineStrings = $optionsManager->getOption(Options::SHOULD_USE_INLINE_STRINGS);
$this->styleManager = $styleManager;
$this->sharedStringsHelper = $sharedStringsHelper; $this->sharedStringsHelper = $sharedStringsHelper;
$this->styleHelper = $styleHelper;
$this->stringsEscaper = $stringsEscaper; $this->stringsEscaper = $stringsEscaper;
$this->stringHelper = $stringHelper; $this->stringHelper = $stringHelper;
} }
@ -211,7 +211,7 @@ EOD;
} else if ($cell->isNumeric()) { } else if ($cell->isNumeric()) {
$cellXML .= '><v>' . $cell->getValue() . '</v></c>'; $cellXML .= '><v>' . $cell->getValue() . '</v></c>';
} else if ($cell->isEmpty()) { } else if ($cell->isEmpty()) {
if ($this->styleHelper->shouldApplyStyleOnEmptyCell($styleId)) { if ($this->styleManager->shouldApplyStyleOnEmptyCell($styleId)) {
$cellXML .= '/>'; $cellXML .= '/>';
} else { } else {
// don't write empty cells that do no need styling // don't write empty cells that do no need styling

View File

@ -3,7 +3,7 @@
namespace Box\Spout\Reader\XLSX\Helper; namespace Box\Spout\Reader\XLSX\Helper;
/** /**
* Class StyleHelperTest * Class StyleManagerTest
* *
* @package Box\Spout\Reader\XLSX\Helper * @package Box\Spout\Reader\XLSX\Helper
*/ */

View File

@ -0,0 +1,45 @@
<?php
namespace Box\Spout\Writer\Common\Creator\Style;
use Box\Spout\Writer\Common\Entity\Style\Border;
use Box\Spout\Writer\Common\Entity\Style\Color;
use Box\Spout\Writer\Common\Manager\Style\StyleMerger;
/**
* Class StyleManagerTest
*
* @package Box\Spout\Writer\Common\Creator\Style
*/
class StyleBuilderTest extends \PHPUnit_Framework_TestCase
{
/**
* @return void
*/
public function testStyleBuilderShouldApplyBorders()
{
$border = (new BorderBuilder())
->setBorderBottom()
->build();
$style = (new StyleBuilder())->setBorder($border)->build();
$this->assertTrue($style->shouldApplyBorder());
}
/**
* @return void
*/
public function testStyleBuilderShouldMergeBorders()
{
$border = (new BorderBuilder())->setBorderBottom(Color::RED, Border::WIDTH_THIN, Border::STYLE_DASHED)->build();
$baseStyle = (new StyleBuilder())->setBorder($border)->build();
$currentStyle = (new StyleBuilder())->build();
$styleMerger = new StyleMerger();
$mergedStyle = $styleMerger->merge($currentStyle, $baseStyle);
$this->assertEquals(null, $currentStyle->getBorder(), 'Current style has no border');
$this->assertInstanceOf('Box\Spout\Writer\Common\Entity\Style\Border', $baseStyle->getBorder(), 'Base style has a border');
$this->assertInstanceOf('Box\Spout\Writer\Common\Entity\Style\Border', $mergedStyle->getBorder(), 'Merged style has a border');
}
}

View File

@ -0,0 +1,52 @@
<?php
namespace Box\Spout\Writer\Common\Manager\Style;
use Box\Spout\Writer\Common\Creator\Style\StyleBuilder;
/**
* Class StyleManagerTest
*
* @package Box\Spout\Writer\Common\Manager\Style
*/
class StyleManagerTest extends \PHPUnit_Framework_TestCase
{
/**
* @return StyleManager
*/
private function getStyleManager()
{
$style = (new StyleBuilder())->build();
$styleRegistry = new StyleRegistry($style);
return new StyleManager($styleRegistry);
}
/**
* @return void
*/
public function testApplyExtraStylesIfNeededShouldApplyWrapTextIfCellContainsNewLine()
{
$style = (new StyleBuilder())->build();
$this->assertFalse($style->shouldWrapText());
$styleManager = $this->getStyleManager();
$updatedStyle = $styleManager->applyExtraStylesIfNeeded($style, [12, 'single line', "multi\nlines", null]);
$this->assertTrue($updatedStyle->shouldWrapText());
}
/**
* @return void
*/
public function testApplyExtraStylesIfNeededShouldDoNothingIfWrapTextAlreadyApplied()
{
$style = (new StyleBuilder())->setShouldWrapText()->build();
$this->assertTrue($style->shouldWrapText());
$styleManager = $this->getStyleManager();
$updatedStyle = $styleManager->applyExtraStylesIfNeeded($style, ["multi\nlines"]);
$this->assertTrue($updatedStyle->shouldWrapText());
}
}

View File

@ -1,43 +1,27 @@
<?php <?php
namespace Box\Spout\Writer\Common\Manager; namespace Box\Spout\Writer\Common\Manager\Style;
use Box\Spout\Writer\Common\Creator\Style\BorderBuilder;
use Box\Spout\Writer\Common\Creator\Style\StyleBuilder; use Box\Spout\Writer\Common\Creator\Style\StyleBuilder;
use Box\Spout\Writer\Common\Entity\Style\Border;
use Box\Spout\Writer\Common\Entity\Style\Color; use Box\Spout\Writer\Common\Entity\Style\Color;
use Box\Spout\Writer\Common\Entity\Style\Style; use Box\Spout\Writer\Common\Entity\Style\Style;
/** /**
* Class StyleManagerTest * Class StyleMergerTest
* *
* @package Box\Spout\Writer\Common\Manager * @package Box\Spout\Writer\Common\Manager\Style
*/ */
class StyleManagerTest extends \PHPUnit_Framework_TestCase class StyleMergerTest extends \PHPUnit_Framework_TestCase
{ {
/** @var StyleManager */ /** @var StyleMerger */
private $styleManager; private $styleMerger;
/** /**
* @return void * @return void
*/ */
public function setUp() public function setUp()
{ {
$this->styleManager = new StyleManager(); $this->styleMerger = new StyleMerger();
}
/**
* @return void
*/
public function testSerializeShouldNotTakeIntoAccountId()
{
$style1 = (new StyleBuilder())->setFontBold()->build();
$style1->setId(1);
$style2 = (new StyleBuilder())->setFontBold()->build();
$style2->setId(2);
$this->assertEquals($this->styleManager->serialize($style1), $this->styleManager->serialize($style2));
} }
/** /**
@ -47,7 +31,7 @@ class StyleManagerTest extends \PHPUnit_Framework_TestCase
{ {
$baseStyle = (new StyleBuilder())->build(); $baseStyle = (new StyleBuilder())->build();
$currentStyle = (new StyleBuilder())->build(); $currentStyle = (new StyleBuilder())->build();
$mergedStyle = $this->styleManager->merge($currentStyle, $baseStyle); $mergedStyle = $this->styleMerger->merge($currentStyle, $baseStyle);
$this->assertNotSame($mergedStyle, $currentStyle); $this->assertNotSame($mergedStyle, $currentStyle);
} }
@ -57,17 +41,26 @@ class StyleManagerTest extends \PHPUnit_Framework_TestCase
*/ */
public function testMergeWithShouldMergeSetProperties() public function testMergeWithShouldMergeSetProperties()
{ {
$baseStyle = (new StyleBuilder())->setFontSize(99)->setFontBold()->build(); $baseStyle = (new StyleBuilder())
->setFontSize(99)
->setFontBold()
->setFontColor(Color::YELLOW)
->setBackgroundColor(Color::BLUE)
->build();
$currentStyle = (new StyleBuilder())->setFontName('Font')->setFontUnderline()->build(); $currentStyle = (new StyleBuilder())->setFontName('Font')->setFontUnderline()->build();
$mergedStyle = $this->styleManager->merge($currentStyle, $baseStyle); $mergedStyle = $this->styleMerger->merge($currentStyle, $baseStyle);
$this->assertNotEquals(99, $currentStyle->getFontSize()); $this->assertNotEquals(99, $currentStyle->getFontSize());
$this->assertFalse($currentStyle->isFontBold()); $this->assertFalse($currentStyle->isFontBold());
$this->assertEquals(Style::DEFAULT_FONT_COLOR, $currentStyle->getFontColor());
$this->assertEquals(null, $currentStyle->getBackgroundColor());
$this->assertEquals(99, $mergedStyle->getFontSize()); $this->assertEquals(99, $mergedStyle->getFontSize());
$this->assertTrue($mergedStyle->isFontBold()); $this->assertTrue($mergedStyle->isFontBold());
$this->assertEquals('Font', $mergedStyle->getFontName()); $this->assertEquals('Font', $mergedStyle->getFontName());
$this->assertTrue($mergedStyle->isFontUnderline()); $this->assertTrue($mergedStyle->isFontUnderline());
$this->assertEquals(Color::YELLOW, $mergedStyle->getFontColor());
$this->assertEquals(Color::BLUE, $mergedStyle->getBackgroundColor());
} }
/** /**
@ -77,7 +70,7 @@ class StyleManagerTest extends \PHPUnit_Framework_TestCase
{ {
$baseStyle = (new StyleBuilder())->setFontSize(10)->build(); $baseStyle = (new StyleBuilder())->setFontSize(10)->build();
$currentStyle = (new StyleBuilder())->setFontSize(99)->build(); $currentStyle = (new StyleBuilder())->setFontSize(99)->build();
$mergedStyle = $this->styleManager->merge($currentStyle, $baseStyle); $mergedStyle = $this->styleMerger->merge($currentStyle, $baseStyle);
$this->assertEquals(99, $mergedStyle->getFontSize()); $this->assertEquals(99, $mergedStyle->getFontSize());
} }
@ -88,8 +81,12 @@ class StyleManagerTest extends \PHPUnit_Framework_TestCase
public function testMergeWithShouldPreferCurrentStylePropertyIfSetOnCurrentButNotOnBase() public function testMergeWithShouldPreferCurrentStylePropertyIfSetOnCurrentButNotOnBase()
{ {
$baseStyle = (new StyleBuilder())->build(); $baseStyle = (new StyleBuilder())->build();
$currentStyle = (new StyleBuilder())->setFontItalic()->setFontStrikethrough()->build(); $currentStyle = (new StyleBuilder())
$mergedStyle = $this->styleManager->merge($currentStyle, $baseStyle); ->setFontItalic()
->setFontStrikethrough()
->build();
$mergedStyle = $this->styleMerger->merge($currentStyle, $baseStyle);
$this->assertFalse($baseStyle->isFontItalic()); $this->assertFalse($baseStyle->isFontItalic());
$this->assertFalse($baseStyle->isFontStrikethrough()); $this->assertFalse($baseStyle->isFontStrikethrough());
@ -110,7 +107,7 @@ class StyleManagerTest extends \PHPUnit_Framework_TestCase
->setShouldWrapText() ->setShouldWrapText()
->build(); ->build();
$currentStyle = (new StyleBuilder())->build(); $currentStyle = (new StyleBuilder())->build();
$mergedStyle = $this->styleManager->merge($currentStyle, $baseStyle); $mergedStyle = $this->styleMerger->merge($currentStyle, $baseStyle);
$this->assertFalse($currentStyle->isFontUnderline()); $this->assertFalse($currentStyle->isFontUnderline());
$this->assertTrue($mergedStyle->isFontUnderline()); $this->assertTrue($mergedStyle->isFontUnderline());
@ -126,10 +123,10 @@ class StyleManagerTest extends \PHPUnit_Framework_TestCase
{ {
$baseStyle = (new StyleBuilder())->build(); $baseStyle = (new StyleBuilder())->build();
$currentStyle = (new StyleBuilder())->build(); $currentStyle = (new StyleBuilder())->build();
$mergedStyle = $this->styleManager->merge($currentStyle, $baseStyle); $mergedStyle = $this->styleMerger->merge($currentStyle, $baseStyle);
$this->assertTrue($this->styleManager->serialize($baseStyle) === $this->styleManager->serialize($currentStyle)); $this->assertSameStyles($baseStyle, $currentStyle);
$this->assertTrue($this->styleManager->serialize($currentStyle) === $this->styleManager->serialize($mergedStyle)); $this->assertSameStyles($currentStyle, $mergedStyle);
} }
/** /**
@ -142,36 +139,21 @@ class StyleManagerTest extends \PHPUnit_Framework_TestCase
->setFontSize(Style::DEFAULT_FONT_SIZE) ->setFontSize(Style::DEFAULT_FONT_SIZE)
->build(); ->build();
$currentStyle = (new StyleBuilder())->build(); $currentStyle = (new StyleBuilder())->build();
$mergedStyle = $this->styleManager->merge($currentStyle, $baseStyle); $mergedStyle = $this->styleMerger->merge($currentStyle, $baseStyle);
$this->assertTrue($this->styleManager->serialize($currentStyle) === $this->styleManager->serialize($mergedStyle)); $this->assertSameStyles($currentStyle, $mergedStyle);
} }
/** /**
* @param Style $style1
* @param Style $style2
* @return void * @return void
*/ */
public function testStyleBuilderShouldApplyBorders() private function assertSameStyles(Style $style1, Style $style2)
{ {
$border = (new BorderBuilder()) $fakeStyle = (new StyleBuilder())->build();
->setBorderBottom() $styleRegistry = new StyleRegistry($fakeStyle);
->build();
$style = (new StyleBuilder())->setBorder($border)->build();
$this->assertTrue($style->shouldApplyBorder());
}
/** $this->assertTrue($styleRegistry->serialize($style1) === $styleRegistry->serialize($style2));
* @return void
*/
public function testStyleBuilderShouldMergeBorders()
{
$border = (new BorderBuilder())->setBorderBottom(Color::RED, Border::WIDTH_THIN, Border::STYLE_DASHED)->build();
$baseStyle = (new StyleBuilder())->setBorder($border)->build();
$currentStyle = (new StyleBuilder())->build();
$mergedStyle = $this->styleManager->merge($currentStyle, $baseStyle);
$this->assertEquals(null, $currentStyle->getBorder(), 'Current style has no border');
$this->assertInstanceOf('Box\Spout\Writer\Common\Entity\Style\Border', $baseStyle->getBorder(), 'Base style has a border');
$this->assertInstanceOf('Box\Spout\Writer\Common\Entity\Style\Border', $mergedStyle->getBorder(), 'Merged style has a border');
} }
} }

View File

@ -0,0 +1,79 @@
<?php
namespace Box\Spout\Writer\Common\Manager\Style;
use Box\Spout\Writer\Common\Creator\Style\BorderBuilder;
use Box\Spout\Writer\Common\Creator\Style\StyleBuilder;
use Box\Spout\Writer\Common\Entity\Style\Border;
use Box\Spout\Writer\Common\Entity\Style\Color;
use Box\Spout\Writer\Common\Entity\Style\Style;
/**
* Class StyleRegistryTest
*
* @package Box\Spout\Writer\Common\Manager\Style
*/
class StyleRegistryTest extends \PHPUnit_Framework_TestCase
{
/** @var Style */
private $defaultStyle;
/** @var StyleRegistry */
private $styleRegistry;
/**
* @return void
*/
public function setUp()
{
$this->defaultStyle = (new StyleBuilder())->build();
$this->styleRegistry = new StyleRegistry($this->defaultStyle);
}
/**
* @return void
*/
public function testSerializeShouldNotTakeIntoAccountId()
{
$style1 = (new StyleBuilder())->setFontBold()->build();
$style1->setId(1);
$style2 = (new StyleBuilder())->setFontBold()->build();
$style2->setId(2);
$this->assertEquals($this->styleRegistry->serialize($style1), $this->styleRegistry->serialize($style2));
}
/**
* @return void
*/
public function testRegisterStyleShouldUpdateId()
{
$style1 = (new StyleBuilder())->setFontBold()->build();
$style2 = (new StyleBuilder())->setFontUnderline()->build();
$this->assertEquals(0, $this->defaultStyle->getId(), 'Default style ID should be 0');
$this->assertNull($style1->getId());
$this->assertNull($style2->getId());
$registeredStyle1 = $this->styleRegistry->registerStyle($style1);
$registeredStyle2 = $this->styleRegistry->registerStyle($style2);
$this->assertEquals(1, $registeredStyle1->getId());
$this->assertEquals(2, $registeredStyle2->getId());
}
/**
* @return void
*/
public function testRegisterStyleShouldReuseAlreadyRegisteredStyles()
{
$style = (new StyleBuilder())->setFontBold()->build();
$registeredStyle1 = $this->styleRegistry->registerStyle($style);
$registeredStyle2 = $this->styleRegistry->registerStyle($style);
$this->assertEquals(1, $registeredStyle1->getId());
$this->assertEquals(1, $registeredStyle2->getId());
}
}

View File

@ -1,91 +0,0 @@
<?php
namespace Box\Spout\Writer\ODS\Helper;
use Box\Spout\Writer\Common\Creator\Style\StyleBuilder;
use Box\Spout\Writer\Common\Entity\Style\Style;
use Box\Spout\Writer\Common\Manager\StyleManager;
/**
* Class StyleHelperTest
*
* @package Box\Spout\Writer\ODS\Helper
*/
class StyleHelperTest extends \PHPUnit_Framework_TestCase
{
/** @var Style */
protected $defaultStyle;
/** @var StyleHelper */
private $styleHelper;
/**
* @return void
*/
public function setUp()
{
$this->defaultStyle = (new StyleBuilder())->build();
$this->styleHelper = new StyleHelper($this->defaultStyle, new StyleManager());
}
/**
* @return void
*/
public function testRegisterStyleShouldUpdateId()
{
$style1 = (new StyleBuilder())->setFontBold()->build();
$style2 = (new StyleBuilder())->setFontUnderline()->build();
$this->assertEquals(0, $this->defaultStyle->getId(), 'Default style ID should be 0');
$this->assertNull($style1->getId());
$this->assertNull($style2->getId());
$registeredStyle1 = $this->styleHelper->registerStyle($style1);
$registeredStyle2 = $this->styleHelper->registerStyle($style2);
$this->assertEquals(1, $registeredStyle1->getId());
$this->assertEquals(2, $registeredStyle2->getId());
}
/**
* @return void
*/
public function testRegisterStyleShouldReuseAlreadyRegisteredStyles()
{
$style = (new StyleBuilder())->setFontBold()->build();
$registeredStyle1 = $this->styleHelper->registerStyle($style);
$registeredStyle2 = $this->styleHelper->registerStyle($style);
$this->assertEquals(1, $registeredStyle1->getId());
$this->assertEquals(1, $registeredStyle2->getId());
}
/**
* @return void
*/
public function testApplyExtraStylesIfNeededShouldApplyWrapTextIfCellContainsNewLine()
{
$style = clone $this->defaultStyle;
$this->assertFalse($style->shouldWrapText());
$updatedStyle = $this->styleHelper->applyExtraStylesIfNeeded($style, [12, 'single line', "multi\nlines", null]);
$this->assertTrue($updatedStyle->shouldWrapText());
}
/**
* @return void
*/
public function testApplyExtraStylesIfNeededShouldDoNothingIfWrapTextAlreadyApplied()
{
$style = (new StyleBuilder())->setShouldWrapText()->build();
$this->assertTrue($style->shouldWrapText());
$updatedStyle = $this->styleHelper->applyExtraStylesIfNeeded($style, ["multi\nlines"]);
$this->assertTrue($updatedStyle->shouldWrapText());
}
}

View File

@ -0,0 +1,40 @@
<?php
namespace Box\Spout\Writer\ODS\Manager\Style;
use Box\Spout\Writer\Common\Creator\Style\StyleBuilder;
/**
* Class StyleRegistryTest
*
* @package Box\Spout\Writer\ODS\Manager\Style
*/
class StyleRegistryTest extends \PHPUnit_Framework_TestCase
{
/**
* @return StyleRegistry
*/
private function getStyleRegistry()
{
$defaultStyle = (new StyleBuilder())->build();
return new StyleRegistry($defaultStyle);
}
/**
* @return void
*/
public function testRegisterStyleKeepsTrackOfUsedFonts()
{
$styleRegistry = $this->getStyleRegistry();
$this->assertEquals(1, count($styleRegistry->getUsedFonts()), 'There should only be the default font name');
$style1 = (new StyleBuilder())->setFontName("MyFont1")->build();
$styleRegistry->registerStyle($style1);
$style2 = (new StyleBuilder())->setFontName("MyFont2")->build();
$styleRegistry->registerStyle($style2);
$this->assertEquals(3, count($styleRegistry->getUsedFonts()), 'There should be 3 fonts registered');
}
}

View File

@ -22,8 +22,8 @@ class WriterWithStyleTest extends \PHPUnit_Framework_TestCase
{ {
use TestUsingResource; use TestUsingResource;
/** @var \Box\Spout\Writer\Common\Entity\Style\Style */ /** @var Style */
protected $defaultStyle; private $defaultStyle;
/** /**
* @return void * @return void

View File

@ -1,114 +0,0 @@
<?php
namespace Box\Spout\Writer\XLSX\Helper;
use Box\Spout\Writer\Common\Entity\Style\Border;
use Box\Spout\Writer\Common\Creator\Style\BorderBuilder;
use Box\Spout\Writer\Common\Entity\Style\Color;
use Box\Spout\Writer\Common\Creator\Style\StyleBuilder;
use Box\Spout\Writer\Common\Entity\Style\Style;
use Box\Spout\Writer\Common\Manager\StyleManager;
/**
* Class StyleHelperTest
*
* @package Box\Spout\Writer\XLSX\Helper
*/
class StyleHelperTest extends \PHPUnit_Framework_TestCase
{
/** @var Style */
protected $defaultStyle;
/** @var StyleHelper */
private $styleHelper;
/**
* @return void
*/
public function setUp()
{
$this->defaultStyle = (new StyleBuilder())->build();
$this->styleHelper = new StyleHelper($this->defaultStyle, new StyleManager());
}
/**
* @return void
*/
public function testRegisterStyleShouldUpdateId()
{
$style1 = (new StyleBuilder())->setFontBold()->build();
$style2 = (new StyleBuilder())->setFontUnderline()->build();
$this->assertEquals(0, $this->defaultStyle->getId(), 'Default style ID should be 0');
$this->assertNull($style1->getId());
$this->assertNull($style2->getId());
$registeredStyle1 = $this->styleHelper->registerStyle($style1);
$registeredStyle2 = $this->styleHelper->registerStyle($style2);
$this->assertEquals(1, $registeredStyle1->getId());
$this->assertEquals(2, $registeredStyle2->getId());
}
/**
* @return void
*/
public function testRegisterStyleShouldReuseAlreadyRegisteredStyles()
{
$style = (new StyleBuilder())->setFontBold()->build();
$registeredStyle1 = $this->styleHelper->registerStyle($style);
$registeredStyle2 = $this->styleHelper->registerStyle($style);
$this->assertEquals(1, $registeredStyle1->getId());
$this->assertEquals(1, $registeredStyle2->getId());
}
/**
* @return void
*/
public function testShouldApplyStyleOnEmptyCell()
{
$styleWithFont = (new StyleBuilder())->setFontBold()->build();
$styleWithBackground = (new StyleBuilder())->setBackgroundColor(Color::BLUE)->build();
$border = (new BorderBuilder())->setBorderBottom(Color::GREEN)->build();
$styleWithBorder = (new StyleBuilder())->setBorder($border)->build();
$this->styleHelper->registerStyle($styleWithFont);
$this->styleHelper->registerStyle($styleWithBackground);
$this->styleHelper->registerStyle($styleWithBorder);
$this->assertFalse($this->styleHelper->shouldApplyStyleOnEmptyCell($styleWithFont->getId()));
$this->assertTrue($this->styleHelper->shouldApplyStyleOnEmptyCell($styleWithBackground->getId()));
$this->assertTrue($this->styleHelper->shouldApplyStyleOnEmptyCell($styleWithBorder->getId()));
}
/**
* @return void
*/
public function testApplyExtraStylesIfNeededShouldApplyWrapTextIfCellContainsNewLine()
{
$style = clone $this->defaultStyle;
$this->assertFalse($style->shouldWrapText());
$updatedStyle = $this->styleHelper->applyExtraStylesIfNeeded($style, [12, 'single line', "multi\nlines", null]);
$this->assertTrue($updatedStyle->shouldWrapText());
}
/**
* @return void
*/
public function testApplyExtraStylesIfNeededShouldDoNothingIfWrapTextAlreadyApplied()
{
$style = (new StyleBuilder())->setShouldWrapText()->build();
$this->assertTrue($style->shouldWrapText());
$updatedStyle = $this->styleHelper->applyExtraStylesIfNeeded($style, ["multi\nlines"]);
$this->assertTrue($updatedStyle->shouldWrapText());
}
}

View File

@ -0,0 +1,59 @@
<?php
namespace Box\Spout\Writer\XLSX\Manager\Style;
/**
* Class StyleManagerTest
*
* @package Box\Spout\Writer\XLSX\Manager\Style
*/
class StyleManagerTest extends \PHPUnit_Framework_TestCase
{
/**
* @return array
*/
public function dataProviderForTestShouldApplyStyleOnEmptyCell()
{
return [
// fillId, borderId, expected result
[null, null, false],
[0, null, false],
[null, 0, false],
[0, 0, false],
[12, null, true],
[null, 12, true],
[12, 0, true],
[0, 12, true],
[12, 13, true],
];
}
/**
* @dataProvider dataProviderForTestShouldApplyStyleOnEmptyCell
*
* @param int|null $fillId
* @param int|null $borderId
* @param bool $expectedResult
* @return void
*/
public function testShouldApplyStyleOnEmptyCell($fillId, $borderId, $expectedResult)
{
$styleRegistryMock = $this->getMockBuilder(StyleRegistry::class)
->disableOriginalConstructor()
->setMethods(['getFillIdForStyleId', 'getBorderIdForStyleId'])
->getMock();
$styleRegistryMock
->method('getFillIdForStyleId')
->willReturn($fillId);
$styleRegistryMock
->method('getBorderIdForStyleId')
->willReturn($borderId);
$styleManager = new StyleManager($styleRegistryMock);
$shouldApply = $styleManager->shouldApplyStyleOnEmptyCell(99);
$this->assertEquals($expectedResult, $shouldApply);
}
}

View File

@ -0,0 +1,77 @@
<?php
namespace Box\Spout\Writer\XLSX\Manager\Style;
use Box\Spout\Writer\Common\Creator\Style\BorderBuilder;
use Box\Spout\Writer\Common\Creator\Style\StyleBuilder;
use Box\Spout\Writer\Common\Entity\Style\Color;
/**
* Class StyleRegistryTest
*
* @package Box\Spout\Writer\XLSX\Manager\Style
*/
class StyleRegistryTest extends \PHPUnit_Framework_TestCase
{
/**
* @return StyleRegistry
*/
private function getStyleRegistry()
{
$defaultStyle = (new StyleBuilder())->build();
return new StyleRegistry($defaultStyle);
}
/**
* @return void
*/
public function testRegisterStyleAlsoRegistersFills()
{
$styleRegistry = $this->getStyleRegistry();
$styleBlack = (new StyleBuilder())->setBackgroundColor(Color::BLACK)->build();
$styleOrange = (new StyleBuilder())->setBackgroundColor(Color::ORANGE)->build();
$styleOrangeBold = (new StyleBuilder())->setBackgroundColor(Color::ORANGE)->setFontBold()->build();
$styleNoBackgroundColor = (new StyleBuilder())->setFontItalic()->build();
$styleRegistry->registerStyle($styleBlack);
$styleRegistry->registerStyle($styleOrange);
$styleRegistry->registerStyle($styleOrangeBold);
$styleRegistry->registerStyle($styleNoBackgroundColor);
$this->assertEquals(2, count($styleRegistry->getRegisteredFills()), 'There should be 2 registered fills');
$this->assertEquals(2, $styleRegistry->getFillIdForStyleId($styleBlack->getId()), 'First style with background color set should have index 2 (0 and 1 being reserved)');
$this->assertEquals(3, $styleRegistry->getFillIdForStyleId($styleOrange->getId()), 'Second style with background color set - different from first style - should have index 3');
$this->assertEquals(3, $styleRegistry->getFillIdForStyleId($styleOrangeBold->getId()), 'Style with background color already set should have the same index');
$this->assertEquals(0, $styleRegistry->getFillIdForStyleId($styleNoBackgroundColor->getId()), 'Style with no background color should have index 0');
}
/**
* @return void
*/
public function testRegisterStyleAlsoRegistersBorders()
{
$styleRegistry = $this->getStyleRegistry();
$borderLeft = (new BorderBuilder())->setBorderLeft()->build();
$borderRight = (new BorderBuilder())->setBorderRight()->build();
$styleBorderLeft = (new StyleBuilder())->setBorder($borderLeft)->build();
$styleBoderRight = (new StyleBuilder())->setBorder($borderRight)->build();
$styleBoderRightBold = (new StyleBuilder())->setBorder($borderRight)->setFontBold()->build();
$styleNoBorder = (new StyleBuilder())->setFontItalic()->build();
$styleRegistry->registerStyle($styleBorderLeft);
$styleRegistry->registerStyle($styleBoderRight);
$styleRegistry->registerStyle($styleBoderRightBold);
$styleRegistry->registerStyle($styleNoBorder);
$this->assertEquals(2, count($styleRegistry->getRegisteredBorders()), 'There should be 2 registered borders');
$this->assertEquals(1, $styleRegistry->getBorderIdForStyleId($styleBorderLeft->getId()), 'First style with border set should have index 1 (0 is for the default style)');
$this->assertEquals(2, $styleRegistry->getBorderIdForStyleId($styleBoderRight->getId()), 'Second style with border set - different from first style - should have index 2');
$this->assertEquals(2, $styleRegistry->getBorderIdForStyleId($styleBoderRightBold->getId()), 'Style with border already set should have the same index');
$this->assertEquals(0, $styleRegistry->getBorderIdForStyleId($styleNoBorder->getId()), 'Style with no border should have index 0');
}
}

View File

@ -10,7 +10,7 @@ use Box\Spout\Writer\Common\Creator\Style\BorderBuilder;
use Box\Spout\Writer\Common\Entity\Style\Color; use Box\Spout\Writer\Common\Entity\Style\Color;
use Box\Spout\Writer\Common\Entity\Style\Style; use Box\Spout\Writer\Common\Entity\Style\Style;
use Box\Spout\Writer\Common\Creator\Style\StyleBuilder; use Box\Spout\Writer\Common\Creator\Style\StyleBuilder;
use Box\Spout\Writer\Common\Manager\StyleManager; use Box\Spout\Writer\Common\Manager\Style\StyleMerger;
use Box\Spout\Writer\WriterFactory; use Box\Spout\Writer\WriterFactory;
use Box\Spout\Writer\XLSX\Manager\OptionsManager; use Box\Spout\Writer\XLSX\Manager\OptionsManager;
@ -24,7 +24,7 @@ class WriterWithStyleTest extends \PHPUnit_Framework_TestCase
use TestUsingResource; use TestUsingResource;
/** @var \Box\Spout\Writer\Common\Entity\Style\Style */ /** @var \Box\Spout\Writer\Common\Entity\Style\Style */
protected $defaultStyle; private $defaultStyle;
/** /**
* @return void * @return void
@ -463,7 +463,7 @@ class WriterWithStyleTest extends \PHPUnit_Framework_TestCase
$fontStyle = (new StyleBuilder())->setFontBold()->build(); $fontStyle = (new StyleBuilder())->setFontBold()->build();
$emptyStyle = (new StyleBuilder())->build(); $emptyStyle = (new StyleBuilder())->build();
$borderRightFontBoldStyle = (new StyleManager())->merge($borderRightStyle, $fontStyle); $borderRightFontBoldStyle = (new StyleMerger())->merge($borderRightStyle, $fontStyle);
$dataRows = [ $dataRows = [
['Border-Left'], ['Border-Left'],