diff --git a/src/Spout/Common/Entity/Style/NumberFormat.php b/src/Spout/Common/Entity/Style/NumberFormat.php new file mode 100644 index 0000000..e26af8e --- /dev/null +++ b/src/Spout/Common/Entity/Style/NumberFormat.php @@ -0,0 +1,114 @@ +id = $id; + return $this; + } + + /** + * @return int|null + */ + public function getId() + { + return $this->id; + } + + /** + * @param int $type + * @return NumberFormat + */ + public function setType($type) + { + if (!in_array($type,self::TYPES)) { + return $this; + //todo throw some excpection or something + } + $this->type = $type; + if ($type == self::TYPE_CURRENCY) { + if (($this->minDecimalPlaces === null) && ($this->maxDecimalPlaces === null)) { + $this->setDecimalPlaces(2,2); + } + if ($this->currencySymbol === null) { + $this->setCurrencySymbol('$'); + } + } + return $this; + } + + /** + * @param int $minDecimalPlaces + * @param int $maxDecimalPlaces + * @return NumberFormat + */ + public function setDecimalPlaces(int $minDecimalPlaces = null, int $maxDecimalPlaces = null) + { + $this->minDecimalPlaces = $minDecimalPlaces; + $this->maxDecimalPlaces = $maxDecimalPlaces; + return $this; + } + + /** + * @param int $currencySymbol + * @return NumberFormat + */ + public function setCurrencySymbol(string $currencySymbol) + { + $this->currencySymbol = $currencySymbol; + return $this; + } + + /** + * @return string + */ + public function getFormatCode() + { + //todo spit out xml tag + $formatString = $this->type == self::TYPE_CURRENCY ? '$_' : ''; + $formatString .= ($this->commas ? '#,##0' : '#0'); + $formatString .= '.'; + for ($i = 0; $i < $this->minDecimalPlaces; $i++) { + $formatString .= '0'; + } + for ($i = $this->minDecimalPlaces; $i < $this->maxDecimalPlaces; $i++) { + $formatString .= '#'; + } + if ($this->type == self::TYPE_PERCENTAGE) { + $formatString .= '%'; + } + return $formatString; + } +} diff --git a/src/Spout/Common/Entity/Style/Style.php b/src/Spout/Common/Entity/Style/Style.php index b34e036..261e9bf 100644 --- a/src/Spout/Common/Entity/Style/Style.php +++ b/src/Spout/Common/Entity/Style/Style.php @@ -71,6 +71,8 @@ class Style /** @var bool */ private $hasSetBackgroundColor = false; + private $numberFormat; + /** * @return int|null */ @@ -110,6 +112,25 @@ class Style return $this; } + /** + * @return NumberFormat + */ + public function getNumberFormat() + { + return $this->numberFormat ?? null; + } + + /** + * @param NumberFormat $format + * @return Style + */ + public function setNumberFormat(NumberFormat $format) + { + $this->numberFormat = $format; + + return $this; + } + /** * @return bool */ diff --git a/src/Spout/Writer/Common/Manager/Style/StyleRegistry.php b/src/Spout/Writer/Common/Manager/Style/StyleRegistry.php index fc978e7..d33b3f2 100644 --- a/src/Spout/Writer/Common/Manager/Style/StyleRegistry.php +++ b/src/Spout/Writer/Common/Manager/Style/StyleRegistry.php @@ -2,6 +2,7 @@ namespace Box\Spout\Writer\Common\Manager\Style; +use Box\Spout\Common\Entity\Style\NumberFormat; use Box\Spout\Common\Entity\Style\Style; /** @@ -12,10 +13,13 @@ class StyleRegistry { /** @var array [SERIALIZED_STYLE] => [STYLE_ID] mapping table, keeping track of the registered styles */ protected $serializedStyleToStyleIdMappingTable = []; + protected $serializedNumberFormatToFormatIdMappingTable = []; /** @var array [STYLE_ID] => [STYLE] mapping table, keeping track of the registered styles */ protected $styleIdToStyleMappingTable = []; + protected $numberFormats = []; + /** * @param Style $defaultStyle */ @@ -34,6 +38,11 @@ class StyleRegistry */ public function registerStyle(Style $style) { + $format = $style->getNumberFormat(); + if (!empty($format)) { + $registeredFormat = $this->registerNumberFormat($format); + $style->setNumberFormat($registeredFormat); + } $serializedStyle = $this->serialize($style); if (!$this->hasStyleAlreadyBeenRegistered($style)) { @@ -47,6 +56,19 @@ class StyleRegistry return $this->getStyleFromSerializedStyle($serializedStyle); } + public function registerNumberFormat(NumberFormat $format) + { + $serializedFormat = $this->serializeFormat($format); + if (!$this->hasFormatAlreadyBeenRegistered($format)) { + $nextFormatId = count($this->serializedNumberFormatToFormatIdMappingTable); + $format->setId($nextFormatId); + + $this->serializedNumberFormatToFormatIdMappingTable[$serializedFormat] = $nextFormatId; + $this->numberFormats[$nextFormatId] = $format; + } + return $this->getFormatFromSerializedFormat($serializedFormat); + } + /** * Returns whether the given style has already been registered. * @@ -61,6 +83,20 @@ class StyleRegistry return isset($this->serializedStyleToStyleIdMappingTable[$serializedStyle]); } + /** + * Returns whether the given number format has already been registered. + * + * @param NumberFormat $format + * @return bool + */ + protected function hasFormatAlreadyBeenRegistered(NumberFormat $format) + { + $serializedFormat = $this->serializeFormat($format); + + // Using isset here because it is way faster than array_key_exists... + return isset($this->serializedNumberFormatToFormatIdMappingTable[$serializedFormat]); + } + /** * Returns the registered style associated to the given serialization. * @@ -74,6 +110,19 @@ class StyleRegistry return $this->styleIdToStyleMappingTable[$styleId]; } + /** + * Returns the registered number format associated to the given serialization. + * + * @param string $serializedFormat The serialized number format from which the actual format should be fetched from + * @return NumberFormat + */ + protected function getFormatFromSerializedFormat($serializedFormat) + { + $formatId = $this->serializedNumberFormatToFormatIdMappingTable[$serializedFormat]; + + return $this->numberFormats[$formatId]; + } + /** * @return Style[] List of registered styles */ @@ -82,6 +131,14 @@ class StyleRegistry return array_values($this->styleIdToStyleMappingTable); } + /** + * @return NumberFormat[] List of registered number formats + */ + public function getRegisteredNumberFormats() + { + return array_values($this->numberFormats); + } + /** * @param int $styleId * @return Style @@ -111,4 +168,25 @@ class StyleRegistry return $serializedStyle; } + + /** + * Serializes the number format for future comparison with other formats. + * The ID is excluded from the comparison, as we only care about + * actual number format properties. + * + * @param Style $style + * @return string The serialized style + */ + public function serializeFormat(NumberFormat $format) + { + // In order to be able to properly compare style, set static ID value + $currentId = $format->getId(); + $format->setId(0); + + $serializedFormat = serialize($format); + + $format->setId($currentId); + + return $serializedFormat; + } } diff --git a/src/Spout/Writer/XLSX/Manager/Style/StyleManager.php b/src/Spout/Writer/XLSX/Manager/Style/StyleManager.php index b98307a..9d750de 100644 --- a/src/Spout/Writer/XLSX/Manager/Style/StyleManager.php +++ b/src/Spout/Writer/XLSX/Manager/Style/StyleManager.php @@ -47,7 +47,7 @@ class StyleManager extends \Box\Spout\Writer\Common\Manager\Style\StyleManager EOD; - + $content .= $this->getNumberFormatSectionContent(); $content .= $this->getFontsSectionContent(); $content .= $this->getFillsSectionContent(); $content .= $this->getBordersSectionContent(); @@ -62,6 +62,22 @@ EOD; return $content; } + protected function getNumberFormatSectionContent() + { + $registeredFormats = $this->styleRegistry->getRegisteredNumberFormats(); + if (empty($registeredFormats)) { + return ''; + } + + $content = ''; + foreach ($registeredFormats as $format) { + + $content .= ''; + } + $content .= ''; + return $content; + } + /** * Returns the content of the "" section. * @@ -207,7 +223,7 @@ EOD; $fillId = $this->getFillIdForStyleId($styleId); $borderId = $this->getBorderIdForStyleId($styleId); - $content .= 'getNumberFormat()->getId().'" fontId="' . $styleId . '" fillId="' . $fillId . '" borderId="' . $borderId . '" xfId="0"'; if ($style->shouldApplyFont()) { $content .= ' applyFont="1"';