Added support for cell formats when writing Excel files
This commit is contained in:
1 parent
a420e3fffa
commit
8a1a088677
4 files changed
+230
-2
No files matched your search
@@ -14,6 +14,62 @@ use Box\Spout\Writer\Style\Style;
|
||||
*/
|
||||
class StyleHelper extends AbstractStyleHelper
|
||||
{
|
||||
|
||||
/**
|
||||
* @see https://msdn.microsoft.com/en-us/library/ff529597(v=office.12).aspx
|
||||
* @var array Mapping between built-in format and the associated numFmtId
|
||||
*/
|
||||
protected static $builtinNumFormatToIdMapping = [
|
||||
|
||||
'General' => 0,
|
||||
'0' => 1,
|
||||
'0.00' => 2,
|
||||
'#,##0' => 3,
|
||||
'#,##0.00' => 4,
|
||||
'$#,##0,\-$#,##0' => 5,
|
||||
'$#,##0,[Red]\-$#,##0' => 6,
|
||||
'$#,##0.00,\-$#,##0.00' => 7,
|
||||
'$#,##0.00,[Red]\-$#,##0.00' => 8,
|
||||
'0%' => 9,
|
||||
'0.00%' => 10,
|
||||
'0.00E+00' => 11,
|
||||
'# ?/?' => 12,
|
||||
'# ??/??' => 13,
|
||||
'mm-dd-yy' => 14,
|
||||
'd-mmm-yy' => 15,
|
||||
'd-mmm' => 16,
|
||||
'mmm-yy' => 17,
|
||||
'h:mm AM/PM' => 18,
|
||||
'h:mm:ss AM/PM' => 19,
|
||||
'h:mm' => 20,
|
||||
'h:mm:ss' => 21,
|
||||
'm/d/yy h:mm' => 22,
|
||||
|
||||
'#,##0 ,(#,##0)' => 37,
|
||||
'#,##0 ,[Red](#,##0)' => 38,
|
||||
'#,##0.00,(#,##0.00)' => 39,
|
||||
'#,##0.00,[Red](#,##0.00)' => 40,
|
||||
|
||||
'_("$"* #,##0.00_),_("$"* \(#,##0.00\),_("$"* "-"??_),_(@_)' => 44,
|
||||
'mm:ss' => 45,
|
||||
'[h]:mm:ss' => 46,
|
||||
'mm:ss.0' => 47,
|
||||
|
||||
'##0.0E+0' => 48,
|
||||
'@' => 49,
|
||||
|
||||
'[$-404]e/m/d' => 27,
|
||||
'm/d/yy' => 30,
|
||||
't0' => 59,
|
||||
't0.00' => 60,
|
||||
't#,##0' => 61,
|
||||
't#,##0.00' => 62,
|
||||
't0%' => 67,
|
||||
't0.00%' => 68,
|
||||
't# ?/?' => 69,
|
||||
't# ??/??' => 70,
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
@@ -24,6 +80,16 @@ class StyleHelper extends AbstractStyleHelper
|
||||
*/
|
||||
protected $styleIdToFillMappingTable = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $registeredFormats = [];
|
||||
|
||||
/**
|
||||
* @var array [STYLE_ID] => [FORMAT_ID] maps a style to a format declaration
|
||||
*/
|
||||
protected $styleIdToFormatsMappingTable = [];
|
||||
|
||||
/**
|
||||
* Excel preserves two default fills with index 0 and 1
|
||||
* Since Excel is the dominant vendor - we play along here
|
||||
@@ -32,6 +98,15 @@ class StyleHelper extends AbstractStyleHelper
|
||||
*/
|
||||
protected $fillIndex = 2;
|
||||
|
||||
/**
|
||||
* If the numFmtId is lower than 0xA4 (164 in decimal)
|
||||
* then it's a built-in number format.
|
||||
* Since Excel is the dominant vendor - we play along here
|
||||
*
|
||||
* @var int The fill index counter for custom fills.
|
||||
*/
|
||||
protected $formatIndex = 164;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
@@ -52,10 +127,48 @@ class StyleHelper extends AbstractStyleHelper
|
||||
{
|
||||
$registeredStyle = parent::registerStyle($style);
|
||||
$this->registerFill($registeredStyle);
|
||||
$this->registerFormat($registeredStyle);
|
||||
$this->registerBorder($registeredStyle);
|
||||
|
||||
return $registeredStyle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a format definition
|
||||
*
|
||||
* @param \Box\Spout\Writer\Style\Style $style
|
||||
*/
|
||||
protected function registerFormat($style)
|
||||
{
|
||||
$styleId = $style->getId();
|
||||
|
||||
$format = $style->getFormat();
|
||||
|
||||
if ($format) {
|
||||
$isFormatRegistered = isset($this->registeredFormats[$format]);
|
||||
|
||||
// We need to track the already registered format definitions
|
||||
if ($isFormatRegistered) {
|
||||
$registeredStyleId = $this->registeredFormats[$format];
|
||||
$registeredFormatId = $this->styleIdToFormatsMappingTable[$registeredStyleId];
|
||||
$this->styleIdToFormatsMappingTable[$styleId] = $registeredFormatId;
|
||||
} else {
|
||||
$this->registeredFormats[$format] = $styleId;
|
||||
if (isset(self::$builtinNumFormatToIdMapping[$format])) {
|
||||
$id = self::$builtinNumFormatToIdMapping[$format];
|
||||
} else {
|
||||
$id = $this->formatIndex++;
|
||||
}
|
||||
$this->styleIdToFormatsMappingTable[$styleId] = $id;
|
||||
}
|
||||
|
||||
} else {
|
||||
// The formatId maps a style to a format declaration
|
||||
// When there is no format definition - we default to 0 ( General )
|
||||
$this->styleIdToFormatsMappingTable[$styleId] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a fill definition
|
||||
*
|
||||
@@ -134,8 +247,9 @@ class StyleHelper extends AbstractStyleHelper
|
||||
{
|
||||
$hasStyleCustomFill = (isset($this->styleIdToFillMappingTable[$styleId]) && $this->styleIdToFillMappingTable[$styleId] !== 0);
|
||||
$hasStyleCustomBorders = (isset($this->styleIdToBorderMappingTable[$styleId]) && $this->styleIdToBorderMappingTable[$styleId] !== 0);
|
||||
$hasStyleCustomFormats = (isset($this->styleIdToFormatsMappingTable[$styleId]) && $this->styleIdToFormatsMappingTable[$styleId] !== 0);
|
||||
|
||||
return ($hasStyleCustomFill || $hasStyleCustomBorders);
|
||||
return ($hasStyleCustomFill || $hasStyleCustomBorders || $hasStyleCustomFormats);
|
||||
}
|
||||
|
||||
|
||||
@@ -151,6 +265,7 @@ class StyleHelper extends AbstractStyleHelper
|
||||
<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
|
||||
EOD;
|
||||
|
||||
$content .= $this->getNumFmtsSectionContent();
|
||||
$content .= $this->getFontsSectionContent();
|
||||
$content .= $this->getFillsSectionContent();
|
||||
$content .= $this->getBordersSectionContent();
|
||||
@@ -165,6 +280,34 @@ EOD;
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the content of the "<fonts>" section.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getNumFmtsSectionContent()
|
||||
{
|
||||
$tags = [];
|
||||
foreach ($this->registeredFormats as $styleId) {
|
||||
$numFmtId = $this->styleIdToFormatsMappingTable[$styleId];
|
||||
|
||||
//Built-in formats do not need to be declared, skip them
|
||||
if ($numFmtId < 164) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/** @var Style $style */
|
||||
$style = $this->styleIdToStyleMappingTable[$styleId];
|
||||
$format = $style->getFormat();
|
||||
$tags[] = '<numFmt numFmtId="' . $numFmtId . '" formatCode="' . $format . '"/>';
|
||||
}
|
||||
$content = '<numFmts count="' . count($tags) . '">';
|
||||
$content .= implode('', $tags);
|
||||
$content .= '</numFmts>';
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the content of the "<fonts>" section.
|
||||
*
|
||||
@@ -305,8 +448,9 @@ EOD;
|
||||
$styleId = $style->getId();
|
||||
$fillId = $this->styleIdToFillMappingTable[$styleId];
|
||||
$borderId = $this->styleIdToBorderMappingTable[$styleId];
|
||||
$numFmtId = $this->styleIdToFormatsMappingTable[$styleId];
|
||||
|
||||
$content .= '<xf numFmtId="0" fontId="' . $styleId . '" fillId="' . $fillId . '" borderId="' . $borderId . '" xfId="0"';
|
||||
$content .= '<xf numFmtId="' . $numFmtId . '" fontId="' . $styleId . '" fillId="' . $fillId . '" borderId="' . $borderId . '" xfId="0"';
|
||||
|
||||
if ($style->shouldApplyFont()) {
|
||||
$content .= ' applyFont="1"';
|
||||
|
||||
Reference in new issue
Block a user