Skip to content

Commit 2760e5a

Browse files
committed
Conditional Color Scale Improvements
Fix PHPOffice#4049. Some possible options were not included for read or write. In addition, although it isn't well documented, it appears that 2-color scale always has 2 cvfo entries in Xml in order minimum/maximum, and 3-color scale always has 3 entries in order minimum/midpoint/maximum.
1 parent 2ed696f commit 2760e5a

File tree

4 files changed

+106
-18
lines changed

4 files changed

+106
-18
lines changed

src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -285,29 +285,34 @@ private function readDataBarOfConditionalRule(SimpleXMLElement $cfRule, array $c
285285
private function readColorScale(SimpleXMLElement|stdClass $cfRule): ConditionalColorScale
286286
{
287287
$colorScale = new ConditionalColorScale();
288-
$types = [];
288+
$count = count($cfRule->colorScale->cfvo);
289+
$idx = 0;
289290
foreach ($cfRule->colorScale->cfvo as $cfvoXml) {
290291
$attr = $cfvoXml->attributes() ?? [];
291292
$type = (string) ($attr['type'] ?? '');
292-
$types[] = $type;
293293
$val = $attr['val'] ?? null;
294-
if ($type === 'min') {
295-
$colorScale->setMinimumConditionalFormatValueObject(new ConditionalFormatValueObject($type, $val));
296-
} elseif ($type === 'percentile') {
297-
$colorScale->setMidpointConditionalFormatValueObject(new ConditionalFormatValueObject($type, $val));
298-
} elseif ($type === 'max') {
299-
$colorScale->setMaximumConditionalFormatValueObject(new ConditionalFormatValueObject($type, $val));
294+
if ($idx === 0) {
295+
$method = 'setMinimumConditionalFormatValueObject';
296+
} elseif ($idx === 1 && $count === 3) {
297+
$method = 'setMidpointConditionalFormatValueObject';
298+
} else {
299+
$method = 'setMaximumConditionalFormatValueObject';
300+
}
301+
if ($type !== 'formula') {
302+
$colorScale->$method(new ConditionalFormatValueObject($type, $val));
303+
} else {
304+
$colorScale->$method(new ConditionalFormatValueObject($type, null, $val));
300305
}
306+
++$idx;
301307
}
302308
$idx = 0;
303309
foreach ($cfRule->colorScale->color as $color) {
304-
$type = $types[$idx];
305310
$rgb = $this->styleReader->readColor($color);
306-
if ($type === 'min') {
311+
if ($idx === 0) {
307312
$colorScale->setMinimumColor(new Color($rgb));
308-
} elseif ($type === 'percentile') {
313+
} elseif ($idx === 1 && $count === 3) {
309314
$colorScale->setMidpointColor(new Color($rgb));
310-
} elseif ($type === 'max') {
315+
} else {
311316
$colorScale->setMaximumColor(new Color($rgb));
312317
}
313318
++$idx;

src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php

Lines changed: 51 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -763,26 +763,71 @@ private static function writeColorScaleElements(XMLWriter $objWriter, ?Condition
763763
$useMin = $minCfvo !== null || $minArgb !== null;
764764
if ($useMin) {
765765
$objWriter->startElement('cfvo');
766-
$objWriter->writeAttribute('type', $minCfvo?->getType() ?? 'min');
767-
self::writeAttributeIf($objWriter, $minCfvo?->getValue() !== null, 'val', (string) $minCfvo?->getValue());
766+
$type = 'min';
767+
$value = null;
768+
if ($minCfvo !== null) {
769+
$typex = $minCfvo->getType();
770+
if ($typex === 'formula') {
771+
$value = $minCfvo->getCellFormula();
772+
if ($value !== null) {
773+
$type = $typex;
774+
}
775+
} else {
776+
$type = $typex;
777+
$defaults = ['number' => '0', 'percent' => '0', 'percentile' => '10'];
778+
$value = $minCfvo->getValue() ?? $defaults[$type] ?? null;
779+
}
780+
}
781+
$objWriter->writeAttribute('type', $type);
782+
self::writeAttributeIf($objWriter, $value !== null, 'val', (string) $value);
768783
$objWriter->endElement();
769784
}
770785
$midCfvo = $colorScale->getMidpointConditionalFormatValueObject();
771786
$midArgb = $colorScale->getMidpointColor()?->getARGB();
772787
$useMid = $midCfvo !== null || $midArgb !== null;
773788
if ($useMid) {
774789
$objWriter->startElement('cfvo');
775-
$objWriter->writeAttribute('type', $midCfvo?->getType() ?? 'percentile');
776-
$objWriter->writeAttribute('val', (string) (($midCfvo?->getValue()) ?? '50'));
790+
$type = 'percentile';
791+
$value = '50';
792+
if ($midCfvo !== null) {
793+
$type = $midCfvo->getType();
794+
if ($type === 'formula') {
795+
$value = $midCfvo->getCellFormula();
796+
if ($value === null) {
797+
$type = 'percentile';
798+
$value = '50';
799+
}
800+
} else {
801+
$defaults = ['number' => '0', 'percent' => '50', 'percentile' => '50'];
802+
$value = $midCfvo->getValue() ?? $defaults[$type] ?? null;
803+
}
804+
}
805+
$objWriter->writeAttribute('type', $type);
806+
self::writeAttributeIf($objWriter, $value !== null, 'val', (string) $value);
777807
$objWriter->endElement();
778808
}
779809
$maxCfvo = $colorScale->getMaximumConditionalFormatValueObject();
780810
$maxArgb = $colorScale->getMaximumColor()?->getARGB();
781811
$useMax = $maxCfvo !== null || $maxArgb !== null;
782812
if ($useMax) {
783813
$objWriter->startElement('cfvo');
784-
$objWriter->writeAttribute('type', $maxCfvo?->getType() ?? 'max');
785-
self::writeAttributeIf($objWriter, $maxCfvo?->getValue() !== null, 'val', (string) $maxCfvo?->getValue());
814+
$type = 'max';
815+
$value = null;
816+
if ($maxCfvo !== null) {
817+
$typex = $maxCfvo->getType();
818+
if ($typex === 'formula') {
819+
$value = $maxCfvo->getCellFormula();
820+
if ($value !== null) {
821+
$type = $typex;
822+
}
823+
} else {
824+
$type = $typex;
825+
$defaults = ['number' => '0', 'percent' => '100', 'percentile' => '90'];
826+
$value = $maxCfvo->getValue() ?? $defaults[$type] ?? null;
827+
}
828+
}
829+
$objWriter->writeAttribute('type', $type);
830+
self::writeAttributeIf($objWriter, $value !== null, 'val', (string) $value);
786831
$objWriter->endElement();
787832
}
788833
if ($useMin) {
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpOffice\PhpSpreadsheetTests\Reader\Xlsx;
6+
7+
use PhpOffice\PhpSpreadsheet\Reader\Xlsx;
8+
use PHPUnit\Framework\TestCase;
9+
10+
class Issue4049Test extends TestCase
11+
{
12+
public static function testPr1869(): void
13+
{
14+
$xlsxFile = 'tests/data/Reader/XLSX/issue.4049.xlsx';
15+
$reader = new Xlsx();
16+
$spreadsheet = $reader->load($xlsxFile);
17+
$sheet = $spreadsheet->getActiveSheet();
18+
$conditionals = $sheet->getConditionalStylesCollection();
19+
self::assertCount(1, $conditionals);
20+
self::assertSame('E9:E14', array_keys($conditionals)[0]);
21+
$cond1 = $conditionals['E9:E14'];
22+
self::assertCount(1, $cond1);
23+
self::assertSame('colorScale', $cond1[0]->getConditionType());
24+
$colorScale = $cond1[0]->getColorScale();
25+
self::assertNotNull($colorScale);
26+
$min = $colorScale->getMinimumConditionalFormatValueObject();
27+
self::assertSame('formula', $min->getType());
28+
self::assertSame('25', $min->getCellFormula());
29+
30+
self::assertNull($colorScale->getMidpointConditionalFormatValueObject());
31+
32+
$max = $colorScale->getMaximumConditionalFormatValueObject();
33+
self::assertSame('max', $max->getType());
34+
self::assertNull($max->getValue());
35+
36+
$spreadsheet->disconnectWorksheets();
37+
}
38+
}
4.66 KB
Binary file not shown.

0 commit comments

Comments
 (0)