diff --git a/CHANGELOG.md b/CHANGELOG.md index bc2299555d..5b624567d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). - Incorrect Reader CSV with BOM. [Issue #4028](https://github.com/PHPOffice/PhpSpreadsheet/issues/4028) [PR #4029](https://github.com/PHPOffice/PhpSpreadsheet/pull/4029) - POWER Null/Bool Args. [PR #4031](https://github.com/PHPOffice/PhpSpreadsheet/pull/4031) - Do Not Output Alignment and Protection for Conditional Format. [Issue #4025](https://github.com/PHPOffice/PhpSpreadsheet/issues/4025) [PR #4027](https://github.com/PHPOffice/PhpSpreadsheet/pull/4027) +- Conditional Color Scale Improvements. [Issue #4049](https://github.com/PHPOffice/PhpSpreadsheet/issues/4049) [PR #4050](https://github.com/PHPOffice/PhpSpreadsheet/pull/4050) - Mpdf and Tcpdf Borders on Merged Cells. [Issue #3557](https://github.com/PHPOffice/PhpSpreadsheet/issues/3557) [PR #4047](https://github.com/PHPOffice/PhpSpreadsheet/pull/4047) - Xls Conditional Format Improvements. [PR #4030](https://github.com/PHPOffice/PhpSpreadsheet/pull/4030) [PR #4033](https://github.com/PHPOffice/PhpSpreadsheet/pull/4033) - Csv Reader allow use of html mimetype. [Issue #4036](https://github.com/PHPOffice/PhpSpreadsheet/issues/4036) [PR #4049](https://github.com/PHPOffice/PhpSpreadsheet/pull/4040) diff --git a/src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php b/src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php index a26b9f6334..e353227e74 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php +++ b/src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php @@ -285,29 +285,34 @@ private function readDataBarOfConditionalRule(SimpleXMLElement $cfRule, array $c private function readColorScale(SimpleXMLElement|stdClass $cfRule): ConditionalColorScale { $colorScale = new ConditionalColorScale(); - $types = []; + $count = count($cfRule->colorScale->cfvo); + $idx = 0; foreach ($cfRule->colorScale->cfvo as $cfvoXml) { $attr = $cfvoXml->attributes() ?? []; $type = (string) ($attr['type'] ?? ''); - $types[] = $type; $val = $attr['val'] ?? null; - if ($type === 'min') { - $colorScale->setMinimumConditionalFormatValueObject(new ConditionalFormatValueObject($type, $val)); - } elseif ($type === 'percentile') { - $colorScale->setMidpointConditionalFormatValueObject(new ConditionalFormatValueObject($type, $val)); - } elseif ($type === 'max') { - $colorScale->setMaximumConditionalFormatValueObject(new ConditionalFormatValueObject($type, $val)); + if ($idx === 0) { + $method = 'setMinimumConditionalFormatValueObject'; + } elseif ($idx === 1 && $count === 3) { + $method = 'setMidpointConditionalFormatValueObject'; + } else { + $method = 'setMaximumConditionalFormatValueObject'; + } + if ($type !== 'formula') { + $colorScale->$method(new ConditionalFormatValueObject($type, $val)); + } else { + $colorScale->$method(new ConditionalFormatValueObject($type, null, $val)); } + ++$idx; } $idx = 0; foreach ($cfRule->colorScale->color as $color) { - $type = $types[$idx]; $rgb = $this->styleReader->readColor($color); - if ($type === 'min') { + if ($idx === 0) { $colorScale->setMinimumColor(new Color($rgb)); - } elseif ($type === 'percentile') { + } elseif ($idx === 1 && $count === 3) { $colorScale->setMidpointColor(new Color($rgb)); - } elseif ($type === 'max') { + } else { $colorScale->setMaximumColor(new Color($rgb)); } ++$idx; diff --git a/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php b/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php index c621e52fd3..7b230202c2 100644 --- a/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php +++ b/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php @@ -763,8 +763,23 @@ private static function writeColorScaleElements(XMLWriter $objWriter, ?Condition $useMin = $minCfvo !== null || $minArgb !== null; if ($useMin) { $objWriter->startElement('cfvo'); - $objWriter->writeAttribute('type', $minCfvo?->getType() ?? 'min'); - self::writeAttributeIf($objWriter, $minCfvo?->getValue() !== null, 'val', (string) $minCfvo?->getValue()); + $type = 'min'; + $value = null; + if ($minCfvo !== null) { + $typex = $minCfvo->getType(); + if ($typex === 'formula') { + $value = $minCfvo->getCellFormula(); + if ($value !== null) { + $type = $typex; + } + } else { + $type = $typex; + $defaults = ['number' => '0', 'percent' => '0', 'percentile' => '10']; + $value = $minCfvo->getValue() ?? $defaults[$type] ?? null; + } + } + $objWriter->writeAttribute('type', $type); + self::writeAttributeIf($objWriter, $value !== null, 'val', (string) $value); $objWriter->endElement(); } $midCfvo = $colorScale->getMidpointConditionalFormatValueObject(); @@ -772,8 +787,23 @@ private static function writeColorScaleElements(XMLWriter $objWriter, ?Condition $useMid = $midCfvo !== null || $midArgb !== null; if ($useMid) { $objWriter->startElement('cfvo'); - $objWriter->writeAttribute('type', $midCfvo?->getType() ?? 'percentile'); - $objWriter->writeAttribute('val', (string) (($midCfvo?->getValue()) ?? '50')); + $type = 'percentile'; + $value = '50'; + if ($midCfvo !== null) { + $type = $midCfvo->getType(); + if ($type === 'formula') { + $value = $midCfvo->getCellFormula(); + if ($value === null) { + $type = 'percentile'; + $value = '50'; + } + } else { + $defaults = ['number' => '0', 'percent' => '50', 'percentile' => '50']; + $value = $midCfvo->getValue() ?? $defaults[$type] ?? null; + } + } + $objWriter->writeAttribute('type', $type); + self::writeAttributeIf($objWriter, $value !== null, 'val', (string) $value); $objWriter->endElement(); } $maxCfvo = $colorScale->getMaximumConditionalFormatValueObject(); @@ -781,8 +811,23 @@ private static function writeColorScaleElements(XMLWriter $objWriter, ?Condition $useMax = $maxCfvo !== null || $maxArgb !== null; if ($useMax) { $objWriter->startElement('cfvo'); - $objWriter->writeAttribute('type', $maxCfvo?->getType() ?? 'max'); - self::writeAttributeIf($objWriter, $maxCfvo?->getValue() !== null, 'val', (string) $maxCfvo?->getValue()); + $type = 'max'; + $value = null; + if ($maxCfvo !== null) { + $typex = $maxCfvo->getType(); + if ($typex === 'formula') { + $value = $maxCfvo->getCellFormula(); + if ($value !== null) { + $type = $typex; + } + } else { + $type = $typex; + $defaults = ['number' => '0', 'percent' => '100', 'percentile' => '90']; + $value = $maxCfvo->getValue() ?? $defaults[$type] ?? null; + } + } + $objWriter->writeAttribute('type', $type); + self::writeAttributeIf($objWriter, $value !== null, 'val', (string) $value); $objWriter->endElement(); } if ($useMin) { diff --git a/tests/PhpSpreadsheetTests/Reader/Xlsx/Issue4049Test.php b/tests/PhpSpreadsheetTests/Reader/Xlsx/Issue4049Test.php new file mode 100644 index 0000000000..d1d6cde386 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Reader/Xlsx/Issue4049Test.php @@ -0,0 +1,40 @@ +load($xlsxFile); + $spreadsheet = $this->writeAndReload($oldSpreadsheet, 'Xlsx'); + $oldSpreadsheet->disconnectWorksheets(); + $sheet = $spreadsheet->getActiveSheet(); + $conditionals = $sheet->getConditionalStylesCollection(); + self::assertCount(1, $conditionals); + self::assertSame('E9:E14', array_keys($conditionals)[0]); + $cond1 = $conditionals['E9:E14']; + self::assertCount(1, $cond1); + self::assertSame('colorScale', $cond1[0]->getConditionType()); + $colorScale = $cond1[0]->getColorScale(); + self::assertNotNull($colorScale); + $min = $colorScale->getMinimumConditionalFormatValueObject(); + self::assertSame('formula', $min->getType()); + self::assertSame('25', $min->getCellFormula()); + + self::assertNull($colorScale->getMidpointConditionalFormatValueObject()); + + $max = $colorScale->getMaximumConditionalFormatValueObject(); + self::assertSame('max', $max->getType()); + self::assertNull($max->getValue()); + + $spreadsheet->disconnectWorksheets(); + } +} diff --git a/tests/data/Reader/XLSX/issue.4049.xlsx b/tests/data/Reader/XLSX/issue.4049.xlsx new file mode 100644 index 0000000000..ef8d47351c Binary files /dev/null and b/tests/data/Reader/XLSX/issue.4049.xlsx differ