From 67bf45d700cb32890179d3734f1ebab42a5cb03a Mon Sep 17 00:00:00 2001 From: oleibman Date: Sat, 18 Dec 2021 08:53:23 -0800 Subject: [PATCH] Fill Pattern Start and End Colors (#2444) * Fill Pattern Start and End Colors Fix #2441. The Fill constructor sets start color to white and end color to black and the Xlsx writer writes these values to the output file. This appears to be the wrong setting for all 7 LIGHT* pattern types, 2 of the 7 DARK* patterns (DARKGRAY and DARKTRELLIS), and 1 of the 3 GRAY patterns (GRAY0625). When the wrong colors are written at save time, those patterns are not as expected. Xls writer does not appear to have the same problem. The XML does not require either a start or end color, and the omission of these colors in the file being read was responsible for the problem. The code is changed to mimic that behavior by omitting the color tags at write time if they have not changed from when they were created by the Fill constructor (they will be written for gradient or solid patterns regardless). This is another change which is easier to confirm via samples rather than tests. There are separate samples for Xlsx and Xls; as Excel will be quick to warn you, Xls is not as fully functional as Xlsx with respect to fill patterns. The samples do include a cell where one of the cells (LightGrid in C11) explicitly specifies the "default" colors. * Scrutinizer It somehow ascribed to me a problem in code which was unchanged by this PR. Correct it anyhow, along with some Phpstan fixes (errors now ignored because of change). * Added Tests Also corrected some docBlock problems with Style/*/parent and getSharedComponent. * Create 2 Abstract Methods Scrutinizer complained that 2 methods found in all Supervisor sub-types were not defined in Supervisor. Add abstract methods to satisfy it. * Scrutinizer Ignoring Typehints Try this instead. * Slight Improvement Better handling of Style->getParent(). --- phpstan-baseline.neon | 105 --------------- samples/Basic/47_xlsfill.php | 13 ++ samples/Basic/47_xlsxfill.php | 13 ++ samples/templates/47_xlsfill.xls | Bin 0 -> 33792 bytes samples/templates/47_xlsxfill.xlsx | Bin 0 -> 10682 bytes src/PhpSpreadsheet/Style/Alignment.php | 5 +- src/PhpSpreadsheet/Style/Border.php | 10 +- src/PhpSpreadsheet/Style/Borders.php | 5 +- src/PhpSpreadsheet/Style/Color.php | 34 ++++- src/PhpSpreadsheet/Style/Fill.php | 32 ++++- src/PhpSpreadsheet/Style/Font.php | 5 +- src/PhpSpreadsheet/Style/NumberFormat.php | 9 +- src/PhpSpreadsheet/Style/Protection.php | 5 +- src/PhpSpreadsheet/Style/Style.php | 8 +- src/PhpSpreadsheet/Style/Supervisor.php | 21 ++- src/PhpSpreadsheet/Writer/Xlsx/Style.php | 13 +- .../Style/ExportArrayTest.php | 127 ++++++++++++++++++ 17 files changed, 269 insertions(+), 136 deletions(-) create mode 100644 samples/Basic/47_xlsfill.php create mode 100644 samples/Basic/47_xlsxfill.php create mode 100644 samples/templates/47_xlsfill.xls create mode 100644 samples/templates/47_xlsxfill.xlsx diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 23b3d630..36e9eacf 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -5510,66 +5510,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Spreadsheet.php - - - message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\|PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style\\:\\:getSharedComponent\\(\\)\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Alignment.php - - - - message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\|PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style\\:\\:getSharedComponent\\(\\)\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Border.php - - - - message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\|PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style\\:\\:getStyleArray\\(\\)\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Border.php - - - - message: "#^Parameter \\#1 \\$parent of method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Supervisor\\:\\:bindParent\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\|PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style, \\$this\\(PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Border\\) given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Border.php - - - - message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\|PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style\\:\\:getSharedComponent\\(\\)\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Borders.php - - - - message: "#^Parameter \\#1 \\$parent of method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Supervisor\\:\\:bindParent\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\|PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style, \\$this\\(PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Borders\\) given\\.$#" - count: 10 - path: src/PhpSpreadsheet/Style/Borders.php - - - - message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\|PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style\\:\\:getSharedComponent\\(\\)\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Color.php - - - - message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\|PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style\\:\\:getStyleArray\\(\\)\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Color.php - - - - message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Border\\|PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Fill\\:\\:getColor\\(\\)\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Color.php - - - - message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Border\\|PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Fill\\:\\:getEndColor\\(\\)\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Color.php - - - - message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Border\\|PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Fill\\:\\:getStartColor\\(\\)\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Color.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Color\\:\\:getColourComponent\\(\\) should return int\\|string but returns float\\|int\\|string\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Color.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Conditional\\:\\:\\$condition \\(array\\\\) does not accept array\\\\.$#" count: 1 @@ -5740,36 +5680,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormattingRuleExtension.php - - - message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\|PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style\\:\\:getSharedComponent\\(\\)\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Fill.php - - - - message: "#^Parameter \\#1 \\$parent of method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Supervisor\\:\\:bindParent\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\|PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style, \\$this\\(PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Fill\\) given\\.$#" - count: 2 - path: src/PhpSpreadsheet/Style/Fill.php - - - - message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\|PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style\\:\\:getSharedComponent\\(\\)\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Font.php - - - - message: "#^Parameter \\#1 \\$parent of method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Supervisor\\:\\:bindParent\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\|PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style, \\$this\\(PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\) given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Font.php - - - - message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\|PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style\\:\\:getSharedComponent\\(\\)\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/NumberFormat.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\:\\:\\$builtInFormatCode \\(int\\|false\\) does not accept bool\\|int\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/NumberFormat.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\\\DateFormatter\\:\\:escapeQuotesCallback\\(\\) has parameter \\$matches with no type specified\\.$#" count: 1 @@ -5900,21 +5810,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Style/NumberFormat/PercentageFormatter.php - - - message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\|PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style\\:\\:getSharedComponent\\(\\)\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Protection.php - - - - message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\|PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style\\:\\:getCellXfByIndex\\(\\)\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Style.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style\\:\\:getParent\\(\\) should return PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet but returns PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\|PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Style.php - - message: "#^Argument of an invalid type mixed supplied for foreach, only iterables are supported\\.$#" count: 1 diff --git a/samples/Basic/47_xlsfill.php b/samples/Basic/47_xlsfill.php new file mode 100644 index 00000000..217d7dca --- /dev/null +++ b/samples/Basic/47_xlsfill.php @@ -0,0 +1,13 @@ +log('Read spreadsheet'); +$reader = new Xls(); +$spreadsheet = $reader->load(__DIR__ . '/../templates/47_xlsfill.xls'); + +// Save +$helper->write($spreadsheet, __FILE__, ['Xls']); +$spreadsheet->disconnectWorksheets(); diff --git a/samples/Basic/47_xlsxfill.php b/samples/Basic/47_xlsxfill.php new file mode 100644 index 00000000..c19d789d --- /dev/null +++ b/samples/Basic/47_xlsxfill.php @@ -0,0 +1,13 @@ +log('Read spreadsheet'); +$reader = new Xlsx(); +$spreadsheet = $reader->load(__DIR__ . '/../templates/47_xlsxfill.xlsx'); + +// Save +$helper->write($spreadsheet, __FILE__, ['Xlsx']); +$spreadsheet->disconnectWorksheets(); diff --git a/samples/templates/47_xlsfill.xls b/samples/templates/47_xlsfill.xls new file mode 100644 index 0000000000000000000000000000000000000000..71887217792b2c7191d7dcde6a6d074173c4d3d8 GIT binary patch literal 33792 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 Tw>UME$Nzs(fBcgfhX4Nnt?C~v literal 0 HcmV?d00001 diff --git a/samples/templates/47_xlsxfill.xlsx b/samples/templates/47_xlsxfill.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..ace2361449ac78a87feedf6ca3dd85af81214cec GIT binary patch literal 10682 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 z|7oRPioUF&{}O#9{9W{AMg3C4%VP2`4cx>pZSb$9parent->getSharedComponent()->getAlignment(); + /** @var Style */ + $parent = $this->parent; + + return $parent->getSharedComponent()->getAlignment(); } /** diff --git a/src/PhpSpreadsheet/Style/Border.php b/src/PhpSpreadsheet/Style/Border.php index 9fabf366..a5ec980a 100644 --- a/src/PhpSpreadsheet/Style/Border.php +++ b/src/PhpSpreadsheet/Style/Border.php @@ -70,8 +70,11 @@ class Border extends Supervisor */ public function getSharedComponent() { + /** @var Style */ + $parent = $this->parent; + /** @var Borders $sharedComponent */ - $sharedComponent = $this->parent->getSharedComponent(); + $sharedComponent = $parent->getSharedComponent(); switch ($this->parentPropertyName) { case 'bottom': return $sharedComponent->getBottom(); @@ -97,7 +100,10 @@ class Border extends Supervisor */ public function getStyleArray($array) { - return $this->parent->getStyleArray([$this->parentPropertyName => $array]); + /** @var Style */ + $parent = $this->parent; + + return $parent->getStyleArray([$this->parentPropertyName => $array]); } /** diff --git a/src/PhpSpreadsheet/Style/Borders.php b/src/PhpSpreadsheet/Style/Borders.php index 5d92f935..56a52709 100644 --- a/src/PhpSpreadsheet/Style/Borders.php +++ b/src/PhpSpreadsheet/Style/Borders.php @@ -140,7 +140,10 @@ class Borders extends Supervisor */ public function getSharedComponent() { - return $this->parent->getSharedComponent()->getBorders(); + /** @var Style */ + $parent = $this->parent; + + return $parent->getSharedComponent()->getBorders(); } /** diff --git a/src/PhpSpreadsheet/Style/Color.php b/src/PhpSpreadsheet/Style/Color.php index d9b9830c..c2d4f749 100644 --- a/src/PhpSpreadsheet/Style/Color.php +++ b/src/PhpSpreadsheet/Style/Color.php @@ -45,6 +45,9 @@ class Color extends Supervisor */ protected $argb; + /** @var bool */ + private $hasChanged = false; + /** * Create a new Color. * @@ -75,12 +78,15 @@ class Color extends Supervisor */ public function getSharedComponent() { + /** @var Style */ + $parent = $this->parent; /** @var Border|Fill $sharedComponent */ - $sharedComponent = $this->parent->getSharedComponent(); - if ($this->parentPropertyName === 'endColor') { - return $sharedComponent->getEndColor(); - } - if ($this->parentPropertyName === 'startColor') { + $sharedComponent = $parent->getSharedComponent(); + if ($sharedComponent instanceof Fill) { + if ($this->parentPropertyName === 'endColor') { + return $sharedComponent->getEndColor(); + } + return $sharedComponent->getStartColor(); } @@ -96,7 +102,10 @@ class Color extends Supervisor */ public function getStyleArray($array) { - return $this->parent->getStyleArray([$this->parentPropertyName => $array]); + /** @var Style */ + $parent = $this->parent; + + return $parent->getStyleArray([$this->parentPropertyName => $array]); } /** @@ -153,6 +162,7 @@ class Color extends Supervisor */ public function setARGB(?string $colorValue = self::COLOR_BLACK) { + $this->hasChanged = true; if ($colorValue === '' || $colorValue === null) { $colorValue = self::COLOR_BLACK; } elseif (!$this->validateColor($colorValue, self::VALIDATE_ARGB_SIZE)) { @@ -190,6 +200,7 @@ class Color extends Supervisor */ public function setRGB(?string $colorValue = self::COLOR_BLACK) { + $this->hasChanged = true; if ($colorValue === '' || $colorValue === null) { $colorValue = '000000'; } elseif (!$this->validateColor($colorValue, self::VALIDATE_RGB_SIZE)) { @@ -220,7 +231,7 @@ class Color extends Supervisor { $colour = substr($rgbValue, $offset, 2); - return ($hex) ? $colour : hexdec($colour); + return ($hex) ? $colour : (int) hexdec($colour); } /** @@ -410,4 +421,13 @@ class Color extends Supervisor return $exportedArray; } + + public function getHasChanged(): bool + { + if ($this->isSupervisor) { + return $this->getSharedComponent()->hasChanged; + } + + return $this->hasChanged; + } } diff --git a/src/PhpSpreadsheet/Style/Fill.php b/src/PhpSpreadsheet/Style/Fill.php index 1a7331eb..bd87a792 100644 --- a/src/PhpSpreadsheet/Style/Fill.php +++ b/src/PhpSpreadsheet/Style/Fill.php @@ -49,7 +49,7 @@ class Fill extends Supervisor * * @var float */ - protected $rotation = 0; + protected $rotation = 0.0; /** * Start color. @@ -65,6 +65,9 @@ class Fill extends Supervisor */ protected $endColor; + /** @var bool */ + private $colorChanged = false; + /** * Create a new Fill. * @@ -102,7 +105,10 @@ class Fill extends Supervisor */ public function getSharedComponent() { - return $this->parent->getSharedComponent()->getFill(); + /** @var Style */ + $parent = $this->parent; + + return $parent->getSharedComponent()->getFill(); } /** @@ -124,7 +130,7 @@ class Fill extends Supervisor * $spreadsheet->getActiveSheet()->getStyle('B2')->getFill()->applyFromArray( * [ * 'fillType' => Fill::FILL_GRADIENT_LINEAR, - * 'rotation' => 0, + * 'rotation' => 0.0, * 'startColor' => [ * 'rgb' => '000000' * ], @@ -248,6 +254,7 @@ class Fill extends Supervisor */ public function setStartColor(Color $color) { + $this->colorChanged = true; // make sure parameter is a real color and not a supervisor $color = $color->getIsSupervisor() ? $color->getSharedComponent() : $color; @@ -278,6 +285,7 @@ class Fill extends Supervisor */ public function setEndColor(Color $color) { + $this->colorChanged = true; // make sure parameter is a real color and not a supervisor $color = $color->getIsSupervisor() ? $color->getSharedComponent() : $color; @@ -291,6 +299,17 @@ class Fill extends Supervisor return $this; } + public function getColorsChanged(): bool + { + if ($this->isSupervisor) { + $changed = $this->getSharedComponent()->colorChanged; + } else { + $changed = $this->colorChanged; + } + + return $changed || $this->startColor->getHasChanged() || $this->endColor->getHasChanged(); + } + /** * Get hash code. * @@ -308,6 +327,7 @@ class Fill extends Supervisor $this->getRotation() . ($this->getFillType() !== self::FILL_NONE ? $this->getStartColor()->getHashCode() : '') . ($this->getFillType() !== self::FILL_NONE ? $this->getEndColor()->getHashCode() : '') . + ((string) $this->getColorsChanged()) . __CLASS__ ); } @@ -315,10 +335,12 @@ class Fill extends Supervisor protected function exportArray1(): array { $exportedArray = []; - $this->exportArray2($exportedArray, 'endColor', $this->getEndColor()); $this->exportArray2($exportedArray, 'fillType', $this->getFillType()); $this->exportArray2($exportedArray, 'rotation', $this->getRotation()); - $this->exportArray2($exportedArray, 'startColor', $this->getStartColor()); + if ($this->getColorsChanged()) { + $this->exportArray2($exportedArray, 'endColor', $this->getEndColor()); + $this->exportArray2($exportedArray, 'startColor', $this->getStartColor()); + } return $exportedArray; } diff --git a/src/PhpSpreadsheet/Style/Font.php b/src/PhpSpreadsheet/Style/Font.php index 63a75cc5..13fe2b67 100644 --- a/src/PhpSpreadsheet/Style/Font.php +++ b/src/PhpSpreadsheet/Style/Font.php @@ -122,7 +122,10 @@ class Font extends Supervisor */ public function getSharedComponent() { - return $this->parent->getSharedComponent()->getFont(); + /** @var Style */ + $parent = $this->parent; + + return $parent->getSharedComponent()->getFont(); } /** diff --git a/src/PhpSpreadsheet/Style/NumberFormat.php b/src/PhpSpreadsheet/Style/NumberFormat.php index a4569283..536b1d54 100644 --- a/src/PhpSpreadsheet/Style/NumberFormat.php +++ b/src/PhpSpreadsheet/Style/NumberFormat.php @@ -104,7 +104,10 @@ class NumberFormat extends Supervisor */ public function getSharedComponent() { - return $this->parent->getSharedComponent()->getNumberFormat(); + /** @var Style */ + $parent = $this->parent; + + return $parent->getSharedComponent()->getNumberFormat(); } /** @@ -157,7 +160,7 @@ class NumberFormat extends Supervisor if ($this->isSupervisor) { return $this->getSharedComponent()->getFormatCode(); } - if ($this->builtInFormatCode !== false) { + if (is_int($this->builtInFormatCode)) { return self::builtInFormatCode($this->builtInFormatCode); } @@ -352,7 +355,7 @@ class NumberFormat extends Supervisor * * @param string $formatCodeIndex * - * @return bool|int + * @return false|int */ public static function builtInFormatCodeIndex($formatCodeIndex) { diff --git a/src/PhpSpreadsheet/Style/Protection.php b/src/PhpSpreadsheet/Style/Protection.php index fc15e3b8..1c174e72 100644 --- a/src/PhpSpreadsheet/Style/Protection.php +++ b/src/PhpSpreadsheet/Style/Protection.php @@ -53,7 +53,10 @@ class Protection extends Supervisor */ public function getSharedComponent() { - return $this->parent->getSharedComponent()->getProtection(); + /** @var Style */ + $parent = $this->parent; + + return $parent->getSharedComponent()->getProtection(); } /** diff --git a/src/PhpSpreadsheet/Style/Style.php b/src/PhpSpreadsheet/Style/Style.php index 5823929d..fdb15451 100644 --- a/src/PhpSpreadsheet/Style/Style.php +++ b/src/PhpSpreadsheet/Style/Style.php @@ -132,17 +132,15 @@ class Style extends Supervisor $xfIndex = 0; } - return $this->parent->getCellXfByIndex($xfIndex); + return $activeSheet->getParent()->getCellXfByIndex($xfIndex); } /** * Get parent. Only used for style supervisor. - * - * @return Spreadsheet */ - public function getParent() + public function getParent(): Spreadsheet { - return $this->parent; + return $this->getActiveSheet()->getParent(); } /** diff --git a/src/PhpSpreadsheet/Style/Supervisor.php b/src/PhpSpreadsheet/Style/Supervisor.php index 7f655bef..8a5c350d 100644 --- a/src/PhpSpreadsheet/Style/Supervisor.php +++ b/src/PhpSpreadsheet/Style/Supervisor.php @@ -18,7 +18,7 @@ abstract class Supervisor implements IComparable /** * Parent. Only used for supervisor. * - * @var Spreadsheet|Style + * @var Spreadsheet|Supervisor */ protected $parent; @@ -45,7 +45,7 @@ abstract class Supervisor implements IComparable /** * Bind parent. Only used for supervisor. * - * @param Spreadsheet|Style $parent + * @param Spreadsheet|Supervisor $parent * @param null|string $parentPropertyName * * @return $this @@ -155,4 +155,21 @@ abstract class Supervisor implements IComparable $exportedArray[$index] = $objOrValue; } } + + /** + * Get the shared style component for the currently active cell in currently active sheet. + * Only used for style supervisor. + * + * @return mixed + */ + abstract public function getSharedComponent(); + + /** + * Build style array from subcomponents. + * + * @param array $array + * + * @return array + */ + abstract public function getStyleArray($array); } diff --git a/src/PhpSpreadsheet/Writer/Xlsx/Style.php b/src/PhpSpreadsheet/Writer/Xlsx/Style.php index bf306a80..cb2e3850 100644 --- a/src/PhpSpreadsheet/Writer/Xlsx/Style.php +++ b/src/PhpSpreadsheet/Writer/Xlsx/Style.php @@ -201,6 +201,15 @@ class Style extends WriterPart $objWriter->endElement(); } + private static function writePatternColors(Fill $fill): bool + { + if ($fill->getFillType() === Fill::FILL_NONE) { + return false; + } + + return $fill->getFillType() === Fill::FILL_SOLID || $fill->getColorsChanged(); + } + /** * Write Pattern Fill. */ @@ -213,15 +222,13 @@ class Style extends WriterPart $objWriter->startElement('patternFill'); $objWriter->writeAttribute('patternType', $fill->getFillType()); - if ($fill->getFillType() !== Fill::FILL_NONE) { + if (self::writePatternColors($fill)) { // fgColor if ($fill->getStartColor()->getARGB()) { $objWriter->startElement('fgColor'); $objWriter->writeAttribute('rgb', $fill->getStartColor()->getARGB()); $objWriter->endElement(); } - } - if ($fill->getFillType() !== Fill::FILL_NONE) { // bgColor if ($fill->getEndColor()->getARGB()) { $objWriter->startElement('bgColor'); diff --git a/tests/PhpSpreadsheetTests/Style/ExportArrayTest.php b/tests/PhpSpreadsheetTests/Style/ExportArrayTest.php index e11e5f29..a062b4cf 100644 --- a/tests/PhpSpreadsheetTests/Style/ExportArrayTest.php +++ b/tests/PhpSpreadsheetTests/Style/ExportArrayTest.php @@ -51,6 +51,7 @@ class ExportArrayTest extends TestCase self::AssertEquals($cell1style->getFont()->getHashCode(), $cell2style->getFont()->getHashCode()); self::AssertEquals($cell1style->getFill()->getHashCode(), $cell2style->getFill()->getHashCode()); self::AssertEquals($cell1style->getProtection()->getHashCode(), $cell2style->getProtection()->getHashCode()); + $spreadsheet->disconnectWorksheets(); } public function testStyleFromArrayCopy(): void @@ -89,6 +90,7 @@ class ExportArrayTest extends TestCase self::AssertEquals($cell1style->getFill()->getStartColor()->getHashCode(), $cell2style->getFill()->getStartColor()->getHashCode()); self::AssertEquals($cell1style->getFill()->getEndColor()->getHashCode(), $cell2style->getFill()->getEndColor()->getHashCode()); + $spreadsheet->disconnectWorksheets(); } public function testNumberFormat(): void @@ -112,6 +114,7 @@ class ExportArrayTest extends TestCase self::assertEquals('$ 12,345.679', $cell2->getFormattedValue()); self::AssertEquals($cell1style->getNumberFormat()->getHashCode(), $cell2style->getNumberFormat()->getHashCode()); + $spreadsheet->disconnectWorksheets(); } public function testNumberFormatFromArray(): void @@ -139,6 +142,7 @@ class ExportArrayTest extends TestCase self::AssertEquals($cell1style->getBorders()->getHashCode(), $cell2style->getBorders()->getHashCode()); self::AssertEquals($cell1style->getBorders()->getTop()->getHashCode(), $cell2style->getBorders()->getTop()->getHashCode()); self::AssertEquals($cell1style->getBorders()->getTop()->getBorderStyle(), $cell2style->getBorders()->getTop()->getBorderStyle()); + $spreadsheet->disconnectWorksheets(); } public function testStackedRotation(): void @@ -157,5 +161,128 @@ class ExportArrayTest extends TestCase $cell2style->applyFromArray($styleArray); self::AssertEquals($cell1style->getAlignment()->getTextRotation(), $cell2style->getAlignment()->getTextRotation()); + $spreadsheet->disconnectWorksheets(); + } + + public function testFillColors(): void + { + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + + $cell1 = $sheet->getCell('A2'); + $cell1style = $cell1->getStyle(); + $cell1style->getFill()->setFillType(Fill::FILL_PATTERN_GRAY125); + $cell1style->getFill()->getStartColor()->setArgb('FF112233'); + $styleArray = $cell1style->exportArray(); + self::assertEquals( + [ + 'fillType' => Fill::FILL_PATTERN_GRAY125, + 'rotation' => 0.0, + 'endColor' => ['argb' => 'FF000000'], + 'startColor' => ['argb' => 'FF112233'], + ], + $styleArray['fill'], + 'changed start color with setArgb' + ); + + $cell1 = $sheet->getCell('A1'); + $cell1style = $cell1->getStyle(); + $cell1style->getFill()->setFillType(Fill::FILL_PATTERN_GRAY125); + $styleArray = $cell1style->exportArray(); + self::assertEquals( + [ + 'fillType' => Fill::FILL_PATTERN_GRAY125, + 'rotation' => 0.0, + ], + $styleArray['fill'], + 'default colors' + ); + + $cell1 = $sheet->getCell('A3'); + $cell1style = $cell1->getStyle(); + $cell1style->getFill()->setFillType(Fill::FILL_PATTERN_GRAY125); + $cell1style->getFill()->getEndColor()->setArgb('FF112233'); + $styleArray = $cell1style->exportArray(); + self::assertEquals( + [ + 'fillType' => Fill::FILL_PATTERN_GRAY125, + 'rotation' => 0.0, + 'endColor' => ['argb' => 'FF112233'], + 'startColor' => ['argb' => 'FFFFFFFF'], + ], + $styleArray['fill'], + 'changed end color with setArgb' + ); + + $cell1 = $sheet->getCell('A4'); + $cell1style = $cell1->getStyle(); + $cell1style->getFill()->setFillType(Fill::FILL_PATTERN_GRAY125); + $cell1style->getFill()->setEndColor(new Color('FF0000FF')); + $styleArray = $cell1style->exportArray(); + self::assertEquals( + [ + 'fillType' => Fill::FILL_PATTERN_GRAY125, + 'rotation' => 0.0, + 'endColor' => ['argb' => 'FF0000FF'], + 'startColor' => ['argb' => 'FFFFFFFF'], + ], + $styleArray['fill'], + 'changed end color with setEndColor' + ); + + $cell1 = $sheet->getCell('A5'); + $cell1style = $cell1->getStyle(); + $cell1style->getFill()->setFillType(Fill::FILL_PATTERN_GRAY125); + $cell1style->getFill()->setStartColor(new Color('FF0000FF')); + $styleArray = $cell1style->exportArray(); + self::assertEquals( + [ + 'fillType' => Fill::FILL_PATTERN_GRAY125, + 'rotation' => 0.0, + 'startColor' => ['argb' => 'FF0000FF'], + 'endColor' => ['argb' => 'FF000000'], + ], + $styleArray['fill'], + 'changed start color with setStartColor' + ); + + $cell1 = $sheet->getCell('A6'); + $cell1->getStyle()->getFill()->applyFromArray( + [ + 'fillType' => Fill::FILL_PATTERN_GRAY125, + 'rotation' => 45.0, + 'startColor' => ['argb' => 'FF00FFFF'], + ] + ); + $cell1style = $cell1->getStyle(); + $styleArray = $cell1style->exportArray(); + self::assertEquals( + [ + 'fillType' => Fill::FILL_PATTERN_GRAY125, + 'rotation' => 45.0, + 'startColor' => ['argb' => 'FF00FFFF'], + 'endColor' => ['argb' => 'FF000000'], + ], + $styleArray['fill'], + 'applyFromArray with startColor' + ); + + $cell1 = $sheet->getCell('A7'); + $cell1->getStyle()->getFill()->applyFromArray( + [ + 'fillType' => Fill::FILL_PATTERN_GRAY125, + ] + ); + $cell1style = $cell1->getStyle(); + $styleArray = $cell1style->exportArray(); + self::assertEquals( + [ + 'fillType' => Fill::FILL_PATTERN_GRAY125, + 'rotation' => 0.0, + ], + $styleArray['fill'], + 'applyFromArray without start/endColor' + ); + $spreadsheet->disconnectWorksheets(); } }