Skip to content

Commit 9dc82e6

Browse files
authored
Merge pull request #4250 from oleibman/issue4248
Fill Patterns/Colors When Xml Attributes are Missing
2 parents e78ab77 + eeef6dc commit 9dc82e6

File tree

9 files changed

+170
-19
lines changed

9 files changed

+170
-19
lines changed

src/PhpSpreadsheet/Reader/Xlsx/Styles.php

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -149,14 +149,22 @@ public function readFillStyle(Fill $fillStyle, SimpleXMLElement $fillStyleXml):
149149
$fillStyle->getStartColor()->setARGB($this->readColor(self::getArrayItem($gradientFill->xpath('sml:stop[@position=0]'))->color)); //* @phpstan-ignore-line
150150
$fillStyle->getEndColor()->setARGB($this->readColor(self::getArrayItem($gradientFill->xpath('sml:stop[@position=1]'))->color)); //* @phpstan-ignore-line
151151
} elseif ($fillStyleXml->patternFill) {
152-
$defaultFillStyle = Fill::FILL_NONE;
152+
$defaultFillStyle = ($fillStyle->getFillType() !== null) ? Fill::FILL_NONE : '';
153+
$fgFound = false;
154+
$bgFound = false;
153155
if ($fillStyleXml->patternFill->fgColor) {
154156
$fillStyle->getStartColor()->setARGB($this->readColor($fillStyleXml->patternFill->fgColor, true));
155-
$defaultFillStyle = Fill::FILL_SOLID;
157+
if ($fillStyle->getFillType() !== null) {
158+
$defaultFillStyle = Fill::FILL_SOLID;
159+
}
160+
$fgFound = true;
156161
}
157162
if ($fillStyleXml->patternFill->bgColor) {
158163
$fillStyle->getEndColor()->setARGB($this->readColor($fillStyleXml->patternFill->bgColor, true));
159-
$defaultFillStyle = Fill::FILL_SOLID;
164+
if ($fillStyle->getFillType() !== null) {
165+
$defaultFillStyle = Fill::FILL_SOLID;
166+
}
167+
$bgFound = true;
160168
}
161169

162170
$type = '';
@@ -169,6 +177,22 @@ public function readFillStyle(Fill $fillStyle, SimpleXMLElement $fillStyleXml):
169177
$patternType = ($type === '') ? $defaultFillStyle : $type;
170178

171179
$fillStyle->setFillType($patternType);
180+
if (
181+
!$fgFound // no foreground color specified
182+
&& !in_array($patternType, [Fill::FILL_NONE, Fill::FILL_SOLID], true) // these patterns aren't relevant
183+
&& $fillStyle->getStartColor()->getARGB() // not conditional
184+
) {
185+
$fillStyle->getStartColor()
186+
->setARGB('', true);
187+
}
188+
if (
189+
!$bgFound // no background color specified
190+
&& !in_array($patternType, [Fill::FILL_NONE, Fill::FILL_SOLID], true) // these patterns aren't relevant
191+
&& $fillStyle->getEndColor()->getARGB() // not conditional
192+
) {
193+
$fillStyle->getEndColor()
194+
->setARGB('', true);
195+
}
172196
}
173197
}
174198

src/PhpSpreadsheet/Style/Color.php

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -230,12 +230,14 @@ public function getARGB(): ?string
230230
*
231231
* @return $this
232232
*/
233-
public function setARGB(?string $colorValue = self::COLOR_BLACK): static
233+
public function setARGB(?string $colorValue = self::COLOR_BLACK, bool $nullStringOkay = false): static
234234
{
235235
$this->hasChanged = true;
236-
$colorValue = $this->validateColor($colorValue);
237-
if ($colorValue === '') {
238-
return $this;
236+
if (!$nullStringOkay || $colorValue !== '') {
237+
$colorValue = $this->validateColor($colorValue);
238+
if ($colorValue === '') {
239+
return $this;
240+
}
239241
}
240242

241243
if ($this->isSupervisor) {

src/PhpSpreadsheet/Writer/Html.php

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1139,9 +1139,16 @@ private function createCSSStyleFill(Fill $fill): array
11391139

11401140
// Create CSS
11411141
if ($fill->getFillType() !== Fill::FILL_NONE) {
1142-
$value = $fill->getFillType() == Fill::FILL_NONE
1143-
? 'white' : '#' . $fill->getStartColor()->getRGB();
1144-
$css['background-color'] = $value;
1142+
if (
1143+
(in_array($fill->getFillType(), ['', Fill::FILL_SOLID], true) || !$fill->getEndColor()->getRGB())
1144+
&& $fill->getStartColor()->getRGB()
1145+
) {
1146+
$value = '#' . $fill->getStartColor()->getRGB();
1147+
$css['background-color'] = $value;
1148+
} elseif ($fill->getEndColor()->getRGB()) {
1149+
$value = '#' . $fill->getEndColor()->getRGB();
1150+
$css['background-color'] = $value;
1151+
}
11451152
}
11461153

11471154
return $css;

src/PhpSpreadsheet/Writer/Xls/Workbook.php

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,8 +210,20 @@ public function addXfWriter(Style $style, bool $isStyleXf = false): int
210210
$xfWriter->setFontIndex($fontIndex);
211211

212212
// Background colors, best to treat these after the font so black will come after white in custom palette
213-
$xfWriter->setFgColor($this->addColor($style->getFill()->getStartColor()->getRGB()));
214-
$xfWriter->setBgColor($this->addColor($style->getFill()->getEndColor()->getRGB()));
213+
if ($style->getFill()->getStartColor()->getRGB()) {
214+
$xfWriter->setFgColor(
215+
$this->addColor(
216+
$style->getFill()->getStartColor()->getRGB()
217+
)
218+
);
219+
}
220+
if ($style->getFill()->getEndColor()->getRGB()) {
221+
$xfWriter->setBgColor(
222+
$this->addColor(
223+
$style->getFill()->getEndColor()->getRGB()
224+
)
225+
);
226+
}
215227
$xfWriter->setBottomColor($this->addColor($style->getBorders()->getBottom()->getColor()->getRGB()));
216228
$xfWriter->setTopColor($this->addColor($style->getBorders()->getTop()->getColor()->getRGB()));
217229
$xfWriter->setRightColor($this->addColor($style->getBorders()->getRight()->getColor()->getRGB()));

src/PhpSpreadsheet/Writer/Xls/Worksheet.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2875,9 +2875,9 @@ private function writeCFRule(
28752875
$bFormatBorder = 0;
28762876
}
28772877
// Pattern
2878-
$bFillStyle = ($conditional->getStyle()->getFill()->getFillType() === null ? 0 : 1);
2879-
$bFillColor = ($conditional->getStyle()->getFill()->getStartColor()->getARGB() === null ? 0 : 1);
2880-
$bFillColorBg = ($conditional->getStyle()->getFill()->getEndColor()->getARGB() === null ? 0 : 1);
2878+
$bFillStyle = $conditional->getStyle()->getFill()->getFillType() ? 1 : 0;
2879+
$bFillColor = $conditional->getStyle()->getFill()->getStartColor()->getARGB() ? 1 : 0;
2880+
$bFillColorBg = $conditional->getStyle()->getFill()->getEndColor()->getARGB() ? 1 : 0;
28812881
if ($bFillStyle == 1 || $bFillColor == 1 || $bFillColorBg == 1) {
28822882
$bFormatFill = 1;
28832883
} else {

src/PhpSpreadsheet/Writer/Xlsx/Style.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ private function writeGradientFill(XMLWriter $objWriter, Fill $fill): void
199199
$objWriter->writeAttribute('position', '0');
200200

201201
// color
202-
if ($fill->getStartColor()->getARGB() !== null) {
202+
if (!empty($fill->getStartColor()->getARGB())) {
203203
$objWriter->startElement('color');
204204
$objWriter->writeAttribute('rgb', $fill->getStartColor()->getARGB());
205205
$objWriter->endElement();
@@ -212,7 +212,7 @@ private function writeGradientFill(XMLWriter $objWriter, Fill $fill): void
212212
$objWriter->writeAttribute('position', '1');
213213

214214
// color
215-
if ($fill->getEndColor()->getARGB() !== null) {
215+
if (!empty($fill->getEndColor()->getARGB())) {
216216
$objWriter->startElement('color');
217217
$objWriter->writeAttribute('rgb', $fill->getEndColor()->getARGB());
218218
$objWriter->endElement();
@@ -244,7 +244,9 @@ private function writePatternFill(XMLWriter $objWriter, Fill $fill): void
244244

245245
// patternFill
246246
$objWriter->startElement('patternFill');
247-
$objWriter->writeAttribute('patternType', (string) $fill->getFillType());
247+
if ($fill->getFillType()) {
248+
$objWriter->writeAttribute('patternType', (string) $fill->getFillType());
249+
}
248250

249251
if (self::writePatternColors($fill)) {
250252
// fgColor

tests/PhpSpreadsheetTests/Reader/Xlsx/DefaultFillTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,6 @@ public function testDefaultConditionalFill(): void
4040
$spreadsheet = $reader->load($filename);
4141

4242
$style = $spreadsheet->getActiveSheet()->getConditionalStyles('A1')[0]->getStyle();
43-
self::assertSame('solid', $style->getFill()->getFillType());
43+
self::assertSame('', $style->getFill()->getFillType());
4444
}
4545
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpOffice\PhpSpreadsheetTests\Reader\Xlsx;
6+
7+
use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;
8+
use PhpOffice\PhpSpreadsheet\Shared\File;
9+
use PhpOffice\PhpSpreadsheet\Writer\Html as HtmlWriter;
10+
use PhpOffice\PhpSpreadsheet\Writer\Xlsx as XlsxWriter;
11+
use PHPUnit\Framework\TestCase;
12+
13+
class Issue4248Test extends TestCase
14+
{
15+
private string $outfile = '';
16+
17+
protected function tearDown(): void
18+
{
19+
if ($this->outfile !== '') {
20+
unlink($this->outfile);
21+
$this->outfile = '';
22+
}
23+
}
24+
25+
public function testStyles(): void
26+
{
27+
$file = 'tests/data/Reader/XLSX/issue.4248.xlsx';
28+
$reader = new XlsxReader();
29+
$spreadsheet = $reader->load($file);
30+
$writer = new XlsxWriter($spreadsheet);
31+
$this->outfile = File::temporaryFilename();
32+
$writer->save($this->outfile);
33+
$spreadsheet->disconnectWorksheets();
34+
35+
$file = 'zip://';
36+
$file .= $this->outfile;
37+
$file .= '#xl/styles.xml';
38+
$data = file_get_contents($file) ?: '';
39+
$expected = '<fill>'
40+
. '<patternFill patternType="darkDown"/>'
41+
. '</fill>';
42+
self::assertStringContainsString($expected, $data, 'neither fgColor nor bgColor');
43+
$expected = '<fill>'
44+
. '<patternFill patternType="darkDown">'
45+
. '<bgColor rgb="FFBDD7EE"/>'
46+
. '</patternFill></fill>';
47+
self::assertStringContainsString($expected, $data, 'bgColor but no fgColor');
48+
$expected = '<dxfs count="15">'
49+
. '<dxf>' // dxfId 1 - fill color for Oui
50+
. '<fill>'
51+
. '<patternFill><bgColor rgb="FF00B050"/></patternFill>'
52+
. '</fill>'
53+
. '<border/>'
54+
. '</dxf>'
55+
. '<dxf>' // dxfId 2 - fill color for Non
56+
. '<font><color rgb="FF9C0006"/></font>'
57+
. '<fill>'
58+
. '<patternFill><bgColor rgb="FFFFC7CE"/></patternFill>'
59+
. '</fill>'
60+
. '<border/>'
61+
. '</dxf>';
62+
self::assertStringContainsString($expected, $data, 'conditional fill styles');
63+
64+
$file = 'zip://';
65+
$file .= $this->outfile;
66+
$file .= '#xl/worksheets/sheet1.xml';
67+
$data = file_get_contents($file) ?: '';
68+
$expected = '<conditionalFormatting sqref="C16:C38 E17:H18 I17:J37 D18 J23:J38 E38 I38">'
69+
. '<cfRule type="containsText" dxfId="0" priority="1" operator="containsText" text="Oui">'
70+
. '<formula>NOT(ISERROR(SEARCH(&quot;Oui&quot;,C16)))</formula>'
71+
. '</cfRule>'
72+
. '</conditionalFormatting>';
73+
self::assertStringContainsString($expected, $data, 'first condition for D18');
74+
$expected = '<conditionalFormatting sqref="C16:C38 I17:J37 E17:H18 D18 J23:J38 E38 I38">'
75+
. '<cfRule type="containsText" dxfId="1" priority="2" operator="containsText" text="Non">'
76+
. '<formula>NOT(ISERROR(SEARCH(&quot;Non&quot;,C16)))</formula>'
77+
. '</cfRule>'
78+
. '</conditionalFormatting>';
79+
self::assertStringContainsString($expected, $data, 'second condition for D18');
80+
}
81+
82+
public function testHtml(): void
83+
{
84+
$file = 'tests/data/Reader/XLSX/issue.4248.xlsx';
85+
$reader = new XlsxReader();
86+
$spreadsheet = $reader->load($file);
87+
$writer = new HtmlWriter($spreadsheet);
88+
89+
$file = 'zip://';
90+
$file .= $this->outfile;
91+
$file .= '#xl/styles.xml';
92+
$data = str_replace(["\r", "\n"], '', $writer->generateHtmlAll());
93+
$expected = ' <tr class="row17">' // Cell D18
94+
. ' <td class="column0 style0">&nbsp;</td>'
95+
. ' <td class="column1 style28 null"></td>'
96+
. ' <td class="column2 style35 s">Eligible </td>'
97+
. ' <td class="column3 style70 f">Non</td>';
98+
self::assertStringContainsString($expected, $data, 'Cell D18 style');
99+
$expected = ' td.style70, th.style70 { vertical-align:middle; text-align:center; border-bottom:1px solid #000000 !important; border-top:2px solid #000000 !important; border-left:2px solid #000000 !important; border-right:1px solid #000000 !important; font-weight:bold; color:#000000; font-family:\'Calibri\'; font-size:16pt; background-color:#BDD7EE }';
100+
self::assertStringContainsString($expected, $data, 'background color');
101+
102+
$spreadsheet->disconnectWorksheets();
103+
}
104+
}
696 KB
Binary file not shown.

0 commit comments

Comments
 (0)