diff --git a/src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php b/src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php
index 8731d642e5..a03fa71b24 100644
--- a/src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php
+++ b/src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php
@@ -125,6 +125,7 @@ private function readConditionalRuleFromExt(SimpleXMLElement $cfRuleXml, SimpleX
{
$conditionType = (string) $attributes->type;
$operatorType = (string) $attributes->operator;
+ $priority = (int) (string) $attributes->priority;
$operands = [];
foreach ($cfRuleXml->children($this->ns['xm']) as $cfRuleOperandsXml) {
@@ -134,6 +135,7 @@ private function readConditionalRuleFromExt(SimpleXMLElement $cfRuleXml, SimpleX
$conditional = new Conditional();
$conditional->setConditionType($conditionType);
$conditional->setOperatorType($operatorType);
+ $conditional->setPriority($priority);
if (
$conditionType === Conditional::CONDITION_CONTAINSTEXT
|| $conditionType === Conditional::CONDITION_NOTCONTAINSTEXT
@@ -184,7 +186,7 @@ private function readConditionalStyles(SimpleXMLElement $xmlSheet): array
private function setConditionalStyles(Worksheet $worksheet, array $conditionals, SimpleXMLElement $xmlExtLst): void
{
foreach ($conditionals as $cellRangeReference => $cfRules) {
- ksort($cfRules);
+ ksort($cfRules); // no longer needed for Xlsx, but helps Xls
$conditionalStyles = $this->readStyleRules($cfRules, $xmlExtLst);
// Extract all cell references in $cellRangeReference
@@ -205,6 +207,7 @@ private function readStyleRules(array $cfRules, SimpleXMLElement $extLst): array
$objConditional = new Conditional();
$objConditional->setConditionType((string) $cfRule['type']);
$objConditional->setOperatorType((string) $cfRule['operator']);
+ $objConditional->setPriority((int) (string) $cfRule['priority']);
$objConditional->setNoFormatSet(!isset($cfRule['dxfId']));
if ((string) $cfRule['text'] != '') {
diff --git a/src/PhpSpreadsheet/Style/Conditional.php b/src/PhpSpreadsheet/Style/Conditional.php
index 01a4d8a9f3..d476bdffd2 100644
--- a/src/PhpSpreadsheet/Style/Conditional.php
+++ b/src/PhpSpreadsheet/Style/Conditional.php
@@ -106,6 +106,8 @@ class Conditional implements IComparable
private bool $noFormatSet = false;
+ private int $priority = 0;
+
/**
* Create a new Conditional.
*/
@@ -115,6 +117,18 @@ public function __construct()
$this->style = new Style(false, true);
}
+ public function getPriority(): int
+ {
+ return $this->priority;
+ }
+
+ public function setPriority(int $priority): self
+ {
+ $this->priority = $priority;
+
+ return $this;
+ }
+
public function getNoFormatSet(): bool
{
return $this->noFormatSet;
diff --git a/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php b/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php
index 28af258297..98ee0bd31e 100644
--- a/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php
+++ b/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php
@@ -861,7 +861,12 @@ private static function writeColorScaleElements(XMLWriter $objWriter, ?Condition
private function writeConditionalFormatting(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet): void
{
// Conditional id
- $id = 1;
+ $id = 0;
+ foreach ($worksheet->getConditionalStylesCollection() as $conditionalStyles) {
+ foreach ($conditionalStyles as $conditional) {
+ $id = max($id, $conditional->getPriority());
+ }
+ }
// Loop through styles in the current worksheet
foreach ($worksheet->getConditionalStylesCollection() as $cellCoordinate => $conditionalStyles) {
@@ -888,7 +893,8 @@ private function writeConditionalFormatting(XMLWriter $objWriter, Phpspreadsheet
'dxfId',
(string) $this->getParentWriter()->getStylesConditionalHashTable()->getIndexForHashCode($conditional->getHashCode())
);
- $objWriter->writeAttribute('priority', (string) $id++);
+ $priority = $conditional->getPriority() ?: ++$id;
+ $objWriter->writeAttribute('priority', (string) $priority);
self::writeAttributeif(
$objWriter,
diff --git a/tests/PhpSpreadsheetTests/Reader/Xlsx/ConditionalPriorityTest.php b/tests/PhpSpreadsheetTests/Reader/Xlsx/ConditionalPriorityTest.php
new file mode 100644
index 0000000000..542b78d865
--- /dev/null
+++ b/tests/PhpSpreadsheetTests/Reader/Xlsx/ConditionalPriorityTest.php
@@ -0,0 +1,129 @@
+load($filename);
+ $reloadedSpreadsheet = $this->writeAndReload($spreadsheet, 'Xlsx');
+ $spreadsheet->disconnectWorksheets();
+ $worksheet = $reloadedSpreadsheet->getActiveSheet();
+ $priorities = [];
+ foreach ($worksheet->getConditionalStylesCollection() as $conditionalStyles) {
+ foreach ($conditionalStyles as $conditional) {
+ $priorities[] = $conditional->getPriority();
+ }
+ }
+ $expected = [27, 2, 3, 4, 1, 22, 14, 5, 6, 7, 20];
+ self::assertSame($expected, $priorities);
+ $reloadedSpreadsheet->disconnectWorksheets();
+ }
+
+ public function testZeroPriority(): void
+ {
+ $spreadsheet = new Spreadsheet();
+ $sheet = $spreadsheet->getActiveSheet();
+ $sheet->fromArray([
+ [1, 1, 1, 1],
+ [2, 2, 2, 2],
+ [3, 3, 3, 3],
+ [4, 4, 4, 4],
+ [5, 5, 5, 5],
+ ]);
+
+ $range = 'A1:A5';
+ $styles = [];
+ $new = new Conditional();
+ $new->setConditionType(Conditional::CONDITION_CELLIS)
+ ->setOperatorType(Conditional::OPERATOR_EQUAL)
+ ->setPriority(30)
+ ->setConditions(['3'])
+ ->getStyle()
+ ->getFill()
+ ->setFillType(Fill::FILL_SOLID)
+ ->getStartColor()
+ ->setArgb('FFC00000');
+ $styles[] = $new;
+ $sheet->setConditionalStyles($range, $styles);
+
+ $range = 'B1:B5';
+ $styles = [];
+ $new = new Conditional();
+ $new->setConditionType(Conditional::CONDITION_EXPRESSION)
+ ->setConditions('=MOD(A1,2)=0')
+ ->getStyle()
+ ->getFill()
+ ->setFillType(Fill::FILL_SOLID)
+ ->getStartColor()
+ ->setArgb('FF00B0F0');
+ $styles[] = $new;
+ $new = new Conditional();
+ $new->setConditionType(Conditional::CONDITION_CELLIS)
+ ->setOperatorType(Conditional::OPERATOR_EQUAL)
+ ->setPriority(40)
+ ->setConditions(['4'])
+ ->getStyle()
+ ->getFill()
+ ->setFillType(Fill::FILL_SOLID)
+ ->getStartColor()
+ ->setArgb('FFFFC000');
+ $styles[] = $new;
+ $sheet->setConditionalStyles($range, $styles);
+
+ $range = 'C1:C5';
+ $styles = [];
+ $new = new Conditional();
+ $new->setConditionType(Conditional::CONDITION_CELLIS)
+ ->setOperatorType(Conditional::OPERATOR_EQUAL)
+ ->setPriority(20)
+ ->setConditions(['2'])
+ ->getStyle()
+ ->getFill()
+ ->setFillType(Fill::FILL_SOLID)
+ ->getStartColor()
+ ->setArgb('FFFFFF00');
+ $styles[] = $new;
+ $new = new Conditional();
+ $new->setConditionType(Conditional::CONDITION_CELLIS)
+ ->setOperatorType(Conditional::OPERATOR_EQUAL)
+ ->setConditions(['5'])
+ ->getStyle()
+ ->getFill()
+ ->setFillType(Fill::FILL_SOLID)
+ ->getStartColor()
+ ->setArgb('FF008080');
+ $styles[] = $new;
+ $sheet->setConditionalStyles($range, $styles);
+
+ $reloadedSpreadsheet = $this->writeAndReload($spreadsheet, 'Xlsx');
+ $spreadsheet->disconnectWorksheets();
+ $worksheet = $reloadedSpreadsheet->getActiveSheet();
+ $priorities = [];
+ foreach ($worksheet->getConditionalStylesCollection() as $conditionalStyles) {
+ foreach ($conditionalStyles as $conditional) {
+ $priorities[] = $conditional->getPriority();
+ }
+ }
+ // B1:B5 is written in order 41, 40, but Reader sorts them
+ $expected = [30, 40, 41, 20, 42];
+ self::assertSame($expected, $priorities);
+ $styles = $worksheet->getConditionalStyles('B1:B5');
+ self::assertSame(Conditional::CONDITION_CELLIS, $styles[0]->getConditionType());
+ self::assertSame(40, $styles[0]->getPriority());
+ self::assertSame(Conditional::CONDITION_EXPRESSION, $styles[1]->getConditionType());
+ self::assertSame(41, $styles[1]->getPriority());
+ $reloadedSpreadsheet->disconnectWorksheets();
+ }
+}
diff --git a/tests/PhpSpreadsheetTests/Reader/Xlsx/Issue4248Test.php b/tests/PhpSpreadsheetTests/Reader/Xlsx/Issue4248Test.php
index 06b0b7f31c..de5ec8f029 100644
--- a/tests/PhpSpreadsheetTests/Reader/Xlsx/Issue4248Test.php
+++ b/tests/PhpSpreadsheetTests/Reader/Xlsx/Issue4248Test.php
@@ -66,13 +66,13 @@ public function testStyles(): void
$file .= '#xl/worksheets/sheet1.xml';
$data = file_get_contents($file) ?: '';
$expected = ''
- . ''
+ . ''
. 'NOT(ISERROR(SEARCH("Oui",C16)))'
. ''
. '';
self::assertStringContainsString($expected, $data, 'first condition for D18');
$expected = ''
- . ''
+ . ''
. 'NOT(ISERROR(SEARCH("Non",C16)))'
. ''
. '';
diff --git a/tests/data/Reader/XLSX/issue.4312c.xlsx b/tests/data/Reader/XLSX/issue.4312c.xlsx
new file mode 100644
index 0000000000..0446ed6cc0
Binary files /dev/null and b/tests/data/Reader/XLSX/issue.4312c.xlsx differ