Skip to content

Commit 5082b35

Browse files
committed
Conditional Formatting in extLst
Fix #4629. Excel Xml can specify Conditional Formatting in 2 ways - either using a `conditionalFormatting` tag as a child of `worksheet`, or in a slightly different manner as a child of `worksheet->extLst`. Although these are both handled by PhpSpreadsheet, the former is lost if there exists a latter whose cell range (`sqref`) matches it. This PR merges the former with the latter in that circumstance, preserving both. The issue also notes that `font` and `stopIfTrue` are not handled correctly. Support for those was missing in the `extlst` handling, and is now added with this PR.
1 parent fd26e45 commit 5082b35

File tree

3 files changed

+52
-0
lines changed

3 files changed

+52
-0
lines changed

src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,11 @@ private function setConditionalsFromExt(array $conditionals): void
7171
ksort($cfRules);
7272
// Priority is used as the key for sorting; but may not start at 0,
7373
// so we use array_values to reset the index after sorting.
74+
$existing = $this->worksheet->getConditionalStylesCollection();
75+
if (array_key_exists($conditionalRange, $existing)) {
76+
$conditionalStyle = $existing[$conditionalRange];
77+
$cfRules = array_merge($conditionalStyle, $cfRules);
78+
}
7479
$this->worksheet->getStyle($conditionalRange)
7580
->setConditionalStyles(array_values($cfRules));
7681
}
@@ -133,6 +138,7 @@ private function readConditionalRuleFromExt(SimpleXMLElement $cfRuleXml, SimpleX
133138
$conditionType = (string) $attributes->type;
134139
$operatorType = (string) $attributes->operator;
135140
$priority = (int) (string) $attributes->priority;
141+
$stopIfTrue = (int) (string) $attributes->stopIfTrue;
136142

137143
$operands = [];
138144
foreach ($cfRuleXml->children($this->ns['xm']) as $cfRuleOperandsXml) {
@@ -143,6 +149,7 @@ private function readConditionalRuleFromExt(SimpleXMLElement $cfRuleXml, SimpleX
143149
$conditional->setConditionType($conditionType);
144150
$conditional->setOperatorType($operatorType);
145151
$conditional->setPriority($priority);
152+
$conditional->setStopIfTrue($stopIfTrue === 1);
146153
if (
147154
$conditionType === Conditional::CONDITION_CONTAINSTEXT
148155
|| $conditionType === Conditional::CONDITION_NOTCONTAINSTEXT
@@ -169,6 +176,9 @@ private function readStyleFromExt(SimpleXMLElement $extCfRuleXml): Style
169176
if ($styleXML->fill) {
170177
$this->styleReader->readFillStyle($cfStyle->getFill(), $styleXML->fill);
171178
}
179+
if ($styleXML->font) {
180+
$this->styleReader->readFontStyle($cfStyle->getFont(), $styleXML->font);
181+
}
172182
}
173183

174184
return $cfStyle;
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
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 PHPUnit\Framework\TestCase;
9+
10+
class Issue4629Test extends TestCase
11+
{
12+
public function testExternalAndInternalCondionalStyles(): void
13+
{
14+
$infile = 'tests/data/Reader/XLSX/issue.4629.xlsx';
15+
$reader = new XlsxReader();
16+
$spreadsheet = $reader->load($infile);
17+
$sheet = $spreadsheet->getSheetByNameOrThrow('top');
18+
$conditionals = $sheet->getStyle('A1:A20')->getConditionalStyles();
19+
self::assertCount(3, $conditionals);
20+
21+
$conditional = $conditionals[0];
22+
self::assertSame('expression', $conditional->getConditionType());
23+
self::assertFalse($conditional->getStopIfTrue());
24+
self::assertSame(['$A1<>$B1'], $conditional->getConditions());
25+
self::assertSame(2, $conditional->getPriority());
26+
27+
$conditional = $conditionals[1];
28+
self::assertSame('expression', $conditional->getConditionType());
29+
self::assertFalse($conditional->getStopIfTrue());
30+
self::assertSame(['AND($A1="cheese", $C1="yogurt")'], $conditional->getConditions());
31+
self::assertSame(3, $conditional->getPriority());
32+
33+
$conditional = $conditionals[2]; // defined within <ext>
34+
self::assertSame('expression', $conditional->getConditionType());
35+
self::assertTrue($conditional->getStopIfTrue());
36+
self::assertSame(['A1<>bottom!A1'], $conditional->getConditions());
37+
self::assertSame(1, $conditional->getPriority());
38+
self::assertSame('FF9C5700', $conditional->getStyle()->getFont()->getColor()->getArgb());
39+
40+
$spreadsheet->disconnectWorksheets();
41+
}
42+
}
9.74 KB
Binary file not shown.

0 commit comments

Comments
 (0)