From e6925a36d5e0853293ccc5688324293360f54fed Mon Sep 17 00:00:00 2001 From: redtailmatt <49280299+redtailmatt@users.noreply.github.com> Date: Fri, 15 Sep 2023 10:31:19 -0400 Subject: [PATCH 1/7] Added Conditional Formatting: ColorScale for Xlsx --- src/PhpSpreadsheet/Style/Conditional.php | 30 ++++ .../ConditionalColorScale.php | 138 ++++++++++++++++++ src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php | 65 ++++++++- 3 files changed, 232 insertions(+), 1 deletion(-) create mode 100644 src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalColorScale.php diff --git a/src/PhpSpreadsheet/Style/Conditional.php b/src/PhpSpreadsheet/Style/Conditional.php index 7785f5cae9..c356856ada 100644 --- a/src/PhpSpreadsheet/Style/Conditional.php +++ b/src/PhpSpreadsheet/Style/Conditional.php @@ -3,6 +3,7 @@ namespace PhpOffice\PhpSpreadsheet\Style; use PhpOffice\PhpSpreadsheet\IComparable; +use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\ConditionalColorScale; use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\ConditionalDataBar; class Conditional implements IComparable @@ -11,6 +12,7 @@ class Conditional implements IComparable const CONDITION_NONE = 'none'; const CONDITION_BEGINSWITH = 'beginsWith'; const CONDITION_CELLIS = 'cellIs'; + const CONDITION_COLORSCALE = 'colorScale'; const CONDITION_CONTAINSBLANKS = 'containsBlanks'; const CONDITION_CONTAINSERRORS = 'containsErrors'; const CONDITION_CONTAINSTEXT = 'containsText'; @@ -27,6 +29,7 @@ class Conditional implements IComparable private const CONDITION_TYPES = [ self::CONDITION_BEGINSWITH, self::CONDITION_CELLIS, + self::CONDITION_COLORSCALE, self::CONDITION_CONTAINSBLANKS, self::CONDITION_CONTAINSERRORS, self::CONDITION_CONTAINSTEXT, @@ -108,6 +111,11 @@ class Conditional implements IComparable */ private $dataBar; + /** + * @var ConditionalColorScale + */ + private $colorScale; + /** * Style. */ @@ -318,6 +326,28 @@ public function setDataBar(ConditionalDataBar $dataBar): static return $this; } + /** + * get ColorScale. + * + * @return null|ConditionalColorScale + */ + public function getColorScale() + { + return $this->colorScale; + } + + /** + * set ColorScale. + * + * @return $this + */ + public function setColorScale(ConditionalColorScale $colorScale): static + { + $this->colorScale = $colorScale; + + return $this; + } + /** * Get hash code. * diff --git a/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalColorScale.php b/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalColorScale.php new file mode 100644 index 0000000000..e478ea24d3 --- /dev/null +++ b/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalColorScale.php @@ -0,0 +1,138 @@ + attribute */ + + /** @var null|bool */ + private $showValue; + + /** children */ + + /** @var ?ConditionalFormatValueObject */ + private $minimumConditionalFormatValueObject; + + /** @var ?ConditionalFormatValueObject */ + private $midpointConditionalFormatValueObject; + + /** @var ?ConditionalFormatValueObject */ + private $maximumConditionalFormatValueObject; + + /** @var ?Color */ + private $minimumColor; + + /** @var ?Color */ + private $midpointColor; + + /** @var ?Color */ + private $maximumColor; + + /** */ + + /** @var ?ConditionalFormattingRuleExtension */ + private $conditionalFormattingRuleExt; + + /** + * @return null|bool + */ + public function getShowValue() + { + return $this->showValue; + } + + /** + * @param bool $showValue + */ + public function setShowValue($showValue): self + { + $this->showValue = $showValue; + + return $this; + } + + public function getMinimumConditionalFormatValueObject(): ?ConditionalFormatValueObject + { + return $this->minimumConditionalFormatValueObject; + } + + public function setMinimumConditionalFormatValueObject(ConditionalFormatValueObject $minimumConditionalFormatValueObject): self + { + $this->minimumConditionalFormatValueObject = $minimumConditionalFormatValueObject; + + return $this; + } + + public function getMidpointConditionalFormatValueObject(): ?ConditionalFormatValueObject + { + return $this->midpointConditionalFormatValueObject; + } + + public function setMidpointConditionalFormatValueObject(ConditionalFormatValueObject $midpointConditionalFormatValueObject): self + { + $this->midpointConditionalFormatValueObject = $midpointConditionalFormatValueObject; + + return $this; + } + + public function getMaximumConditionalFormatValueObject(): ?ConditionalFormatValueObject + { + return $this->maximumConditionalFormatValueObject; + } + + public function setMaximumConditionalFormatValueObject(ConditionalFormatValueObject $maximumConditionalFormatValueObject): self + { + $this->maximumConditionalFormatValueObject = $maximumConditionalFormatValueObject; + + return $this; + } + + public function getMinimumColor(): string + { + return $this->minimumColor; + } + + public function setMinimumColor(string $minimumColor): self + { + $this->minimumColor = $minimumColor; + + return $this; + } + + public function getMidpointColor(): ?string + { + return $this->midpointColor; + } + + public function setMidpointColor(string $midpointColor): self + { + $this->midpointColor = $midpointColor; + + return $this; + } + + public function getMaximumColor(): string + { + return $this->maximumColor; + } + + public function setMaximumColor(string $maximumColor): self + { + $this->maximumColor = $maximumColor; + + return $this; + } + + public function getConditionalFormattingRuleExt(): ?ConditionalFormattingRuleExtension + { + return $this->conditionalFormattingRuleExt; + } + + public function setConditionalFormattingRuleExt(ConditionalFormattingRuleExtension $conditionalFormattingRuleExt): self + { + $this->conditionalFormattingRuleExt = $conditionalFormattingRuleExt; + + return $this; + } +} diff --git a/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php b/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php index e36b853147..d5a0456d4b 100644 --- a/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php +++ b/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php @@ -11,6 +11,7 @@ use PhpOffice\PhpSpreadsheet\Shared\StringHelper; use PhpOffice\PhpSpreadsheet\Shared\XMLWriter; use PhpOffice\PhpSpreadsheet\Style\Conditional; +use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\ConditionalColorScale; use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\ConditionalDataBar; use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\ConditionalFormattingRuleExtension; use PhpOffice\PhpSpreadsheet\Worksheet\RowDimension; @@ -717,6 +718,64 @@ private static function writeDataBarElements(XMLWriter $objWriter, ?ConditionalD } } + private static function writeColorScaleElements(XMLWriter $objWriter, ?ConditionalColorScale $colorScale): void + { + if ($colorScale) { + $objWriter->startElement('colorScale'); + self::writeAttributeIf($objWriter, null !== $colorScale->getShowValue(), 'showValue', $colorScale->getShowValue() ? '1' : '0'); + + $minCfvo = $colorScale->getMinimumConditionalFormatValueObject(); + if ($minCfvo) { + $objWriter->startElement('cfvo'); + self::writeAttributeIf($objWriter, $minCfvo->getType(), 'type', (string) $minCfvo->getType()); + self::writeAttributeIf($objWriter, $minCfvo->getValue(), 'val', (string) $minCfvo->getValue()); + $objWriter->endElement(); + } + $midCfvo = $colorScale->getMidpointConditionalFormatValueObject(); + if ($midCfvo) { + $objWriter->startElement('cfvo'); + self::writeAttributeIf($objWriter, $midCfvo->getType(), 'type', (string) $midCfvo->getType()); + self::writeAttributeIf($objWriter, $midCfvo->getValue(), 'val', (string) $midCfvo->getValue()); + $objWriter->endElement(); + } + $maxCfvo = $colorScale->getMaximumConditionalFormatValueObject(); + if ($maxCfvo) { + $objWriter->startElement('cfvo'); + self::writeAttributeIf($objWriter, $maxCfvo->getType(), 'type', (string) $maxCfvo->getType()); + self::writeAttributeIf($objWriter, $maxCfvo->getValue(), 'val', (string) $maxCfvo->getValue()); + $objWriter->endElement(); + } + if ($colorScale->getMinimumColor()) { + $objWriter->startElement('color'); + $objWriter->writeAttribute('rgb', $colorScale->getMinimumColor()); + $objWriter->endElement(); + } + if ($colorScale->getMidpointColor()) { + $objWriter->startElement('color'); + $objWriter->writeAttribute('rgb', $colorScale->getMidpointColor()); + $objWriter->endElement(); + } + if ($colorScale->getMaximumColor()) { + $objWriter->startElement('color'); + $objWriter->writeAttribute('rgb', $colorScale->getMaximumColor()); + $objWriter->endElement(); + } + $objWriter->endElement(); // end colorScale + + if ($colorScale->getConditionalFormattingRuleExt()) { + $objWriter->startElement('extLst'); + $extension = $colorScale->getConditionalFormattingRuleExt(); + $objWriter->startElement('ext'); + $objWriter->writeAttribute('uri', '{B025F937-C7B1-47D3-B67F-A62EFF666E3E}'); + $objWriter->startElementNs('x14', 'id', null); + $objWriter->text($extension->getId()); + $objWriter->endElement(); + $objWriter->endElement(); + $objWriter->endElement(); //end extLst + } + } + } + /** * Write ConditionalFormatting. */ @@ -740,7 +799,9 @@ private function writeConditionalFormatting(XMLWriter $objWriter, Phpspreadsheet $objWriter->writeAttribute('type', $conditional->getConditionType()); self::writeAttributeIf( $objWriter, - ($conditional->getConditionType() !== Conditional::CONDITION_DATABAR && $conditional->getNoFormatSet() === false), + ($conditional->getConditionType() !== Conditional::CONDITION_COLORSCALE + && $conditional->getConditionType() !== Conditional::CONDITION_DATABAR + && $conditional->getNoFormatSet() === false), 'dxfId', (string) $this->getParentWriter()->getStylesConditionalHashTable()->getIndexForHashCode($conditional->getHashCode()) ); @@ -773,6 +834,8 @@ private function writeConditionalFormatting(XMLWriter $objWriter, Phpspreadsheet self::writeTextCondElements($objWriter, $conditional, $topLeftCell); } elseif ($conditional->getConditionType() === Conditional::CONDITION_TIMEPERIOD) { self::writeTimePeriodCondElements($objWriter, $conditional, $topLeftCell); + } elseif ($conditional->getConditionType() === Conditional::CONDITION_COLORSCALE) { + self::writeColorScaleElements($objWriter, $conditional->getColorScale()); } else { self::writeOtherCondElements($objWriter, $conditional, $topLeftCell); } From 853b694aec973bff4f79439798d647142002f528 Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Wed, 27 Sep 2023 08:10:06 -0700 Subject: [PATCH 2/7] Add Reader Support, Tests, Sample Also correct Phpstan and phpcs problems. --- .../cond08_colorscale.php | 65 ++++++++++++++++++ .../Reader/Xlsx/ConditionalStyles.php | 44 +++++++++++- .../ConditionalColorScale.php | 19 +++-- .../ConditionalDataBar.php | 14 +--- .../ConditionalFormatValueObject.php | 35 +++------- src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php | 55 +++++++++------ .../Reader/Xlsx/ConditionalColorScaleTest.php | 33 +++++++++ tests/data/Reader/XLSX/colorscale.xlsx | Bin 0 -> 9457 bytes 8 files changed, 195 insertions(+), 70 deletions(-) create mode 100644 samples/ConditionalFormatting/cond08_colorscale.php create mode 100644 tests/PhpSpreadsheetTests/Reader/Xlsx/ConditionalColorScaleTest.php create mode 100644 tests/data/Reader/XLSX/colorscale.xlsx diff --git a/samples/ConditionalFormatting/cond08_colorscale.php b/samples/ConditionalFormatting/cond08_colorscale.php new file mode 100644 index 0000000000..5f6bfa6c1b --- /dev/null +++ b/samples/ConditionalFormatting/cond08_colorscale.php @@ -0,0 +1,65 @@ +log('Create new Spreadsheet object'); +$spreadsheet = new Spreadsheet(); +$sheet = $spreadsheet->getActiveSheet(); + +// Set document properties +$helper->log('Set document properties'); +$spreadsheet->getProperties()->setCreator('Owen Leibman') + ->setLastModifiedBy('Owen Leibman') + ->setTitle('PhpSpreadsheet Test Document') + ->setSubject('PhpSpreadsheet Test Document') + ->setDescription('Test document for PhpSpreadsheet, generated using PHP classes.') + ->setKeywords('office PhpSpreadsheet php') + ->setCategory('Test result file'); + +// Create the worksheet +$helper->log('Add data'); +$sheet + ->setCellValue('A1', 1) + ->setCellValue('A2', 2) + ->setCellValue('A3', 8) + ->setCellValue('A4', 4) + ->setCellValue('A5', 5) + ->setCellValue('A6', 6) + ->setCellValue('A7', 7) + ->setCellValue('A8', 3) + ->setCellValue('A9', 9) + ->setCellValue('A10', 10); + +// Set conditional formatting rules and styles +$helper->log('Define conditional formatting using Color Scales'); + +$cellRange = 'A1:A10'; +$condition1 = new Conditional(); +$condition1->setConditionType(Conditional::CONDITION_COLORSCALE); +$colorScale = new ConditionalColorScale(); +$condition1->setColorScale($colorScale); +$colorScale + ->setMinimumConditionalFormatValueObject(new ConditionalFormatValueObject('min')) + ->setMidpointConditionalFormatValueObject(new ConditionalFormatValueObject('percentile', '40')) + ->setMaximumConditionalFormatValueObject(new ConditionalFormatValueObject('max')) + ->setMinimumColor(new Color('FFF8696B')) + ->setMidpointColor(new Color('FFFFEB84')) + ->setMaximumColor(new Color('FF63BE7B')); + +$conditionalStyles = [$condition1]; + +$sheet + ->getStyle($cellRange) + ->setConditionalStyles($conditionalStyles); +$sheet->setSelectedCells('B1'); + +// Save +$helper->write($spreadsheet, __FILE__, ['Xlsx']); diff --git a/src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php b/src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php index 5b68189e1b..43dc3a9c08 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php +++ b/src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php @@ -3,7 +3,9 @@ namespace PhpOffice\PhpSpreadsheet\Reader\Xlsx; use PhpOffice\PhpSpreadsheet\Reader\Xlsx\Styles as StyleReader; +use PhpOffice\PhpSpreadsheet\Style\Color; use PhpOffice\PhpSpreadsheet\Style\Conditional; +use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\ConditionalColorScale; use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\ConditionalDataBar; use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\ConditionalFormattingRuleExtension; use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\ConditionalFormatValueObject; @@ -199,6 +201,7 @@ private function readStyleRules(array $cfRules, SimpleXMLElement $extLst): array $conditionalFormattingRuleExtensions = ConditionalFormattingRuleExtension::parseExtLstXml($extLst); $conditionalStyles = []; + /** @var SimpleXMLElement $cfRule */ foreach ($cfRules as $cfRule) { $objConditional = new Conditional(); $objConditional->setConditionType((string) $cfRule['type']); @@ -232,7 +235,11 @@ private function readStyleRules(array $cfRules, SimpleXMLElement $extLst): array if (isset($cfRule->dataBar)) { $objConditional->setDataBar( - $this->readDataBarOfConditionalRule($cfRule, $conditionalFormattingRuleExtensions) // @phpstan-ignore-line + $this->readDataBarOfConditionalRule($cfRule, $conditionalFormattingRuleExtensions) + ); + } elseif (isset($cfRule->colorScale)) { + $objConditional->setColorScale( + $this->readColorScale($cfRule) ); } elseif (isset($cfRule['dxfId'])) { $objConditional->setStyle(clone $this->dxfs[(int) ($cfRule['dxfId'])]); @@ -279,6 +286,41 @@ private function readDataBarOfConditionalRule($cfRule, array $conditionalFormatt return $dataBar; } + private function readColorScale(simpleXMLElement|stdClass $cfRule): ConditionalColorScale + { + $colorScale = new ConditionalColorScale(); + $types = []; + 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)); + } + } + $idx = 0; + foreach ($cfRule->colorScale->color as $color) { + $type = $types[$idx]; + $attr = $color->attributes() ?? []; + $rgb = $attr['rgb'] ?? ''; + if ($type === 'min') { + $colorScale->setMinimumColor(new Color($rgb)); + } elseif ($type === 'percentile') { + $colorScale->setMidpointColor(new Color($rgb)); + } elseif ($type === 'max') { + $colorScale->setMaximumColor(new Color($rgb)); + } + ++$idx; + } + + return $colorScale; + } + /** * @param SimpleXMLElement|stdClass $cfRule */ diff --git a/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalColorScale.php b/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalColorScale.php index e478ea24d3..a0ac40d252 100644 --- a/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalColorScale.php +++ b/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalColorScale.php @@ -2,6 +2,8 @@ namespace PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting; +use PhpOffice\PhpSpreadsheet\Style\Color; + class ConditionalColorScale { /** attribute */ @@ -42,10 +44,7 @@ public function getShowValue() return $this->showValue; } - /** - * @param bool $showValue - */ - public function setShowValue($showValue): self + public function setShowValue(bool $showValue): self { $this->showValue = $showValue; @@ -88,36 +87,36 @@ public function setMaximumConditionalFormatValueObject(ConditionalFormatValueObj return $this; } - public function getMinimumColor(): string + public function getMinimumColor(): ?Color { return $this->minimumColor; } - public function setMinimumColor(string $minimumColor): self + public function setMinimumColor(Color $minimumColor): self { $this->minimumColor = $minimumColor; return $this; } - public function getMidpointColor(): ?string + public function getMidpointColor(): ?Color { return $this->midpointColor; } - public function setMidpointColor(string $midpointColor): self + public function setMidpointColor(Color $midpointColor): self { $this->midpointColor = $midpointColor; return $this; } - public function getMaximumColor(): string + public function getMaximumColor(): ?Color { return $this->maximumColor; } - public function setMaximumColor(string $maximumColor): self + public function setMaximumColor(Color $maximumColor): self { $this->maximumColor = $maximumColor; diff --git a/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalDataBar.php b/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalDataBar.php index c07c753b8b..b6755fb7d1 100644 --- a/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalDataBar.php +++ b/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalDataBar.php @@ -5,9 +5,7 @@ class ConditionalDataBar { /** attribute */ - - /** @var null|bool */ - private $showValue; + private ?bool $showValue = null; private ?ConditionalFormatValueObject $minimumConditionalFormatValueObject = null; @@ -17,18 +15,12 @@ class ConditionalDataBar private ?ConditionalFormattingRuleExtension $conditionalFormattingRuleExt = null; - /** - * @return null|bool - */ - public function getShowValue() + public function getShowValue(): ?bool { return $this->showValue; } - /** - * @param bool $showValue - */ - public function setShowValue($showValue): self + public function setShowValue(bool $showValue): self { $this->showValue = $showValue; diff --git a/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormatValueObject.php b/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormatValueObject.php index 4c13444621..140ad744a0 100644 --- a/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormatValueObject.php +++ b/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormatValueObject.php @@ -4,59 +4,40 @@ class ConditionalFormatValueObject { - /** @var mixed */ - private $type; + private string $type; - /** @var mixed */ - private $value; + private null|float|int|string $value; - /** @var mixed */ - private $cellFormula; + private mixed $cellFormula; /** * ConditionalFormatValueObject constructor. - * - * @param mixed $type - * @param mixed $value - * @param null|mixed $cellFormula */ - public function __construct($type, $value = null, $cellFormula = null) + public function __construct(string $type, mixed $value = null, mixed $cellFormula = null) { $this->type = $type; $this->value = $value; $this->cellFormula = $cellFormula; } - /** - * @return mixed - */ - public function getType() + public function getType(): string { return $this->type; } - /** - * @param mixed $type - */ - public function setType($type): self + public function setType(string $type): self { $this->type = $type; return $this; } - /** - * @return mixed - */ - public function getValue() + public function getValue(): null|float|int|string { return $this->value; } - /** - * @param mixed $value - */ - public function setValue($value): self + public function setValue(null|float|int|string $value): self { $this->value = $value; diff --git a/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php b/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php index d5a0456d4b..1354aee889 100644 --- a/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php +++ b/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php @@ -686,15 +686,15 @@ private static function writeDataBarElements(XMLWriter $objWriter, ?ConditionalD $minCfvo = $dataBar->getMinimumConditionalFormatValueObject(); if ($minCfvo) { $objWriter->startElement('cfvo'); - self::writeAttributeIf($objWriter, $minCfvo->getType(), 'type', (string) $minCfvo->getType()); - self::writeAttributeIf($objWriter, $minCfvo->getValue(), 'val', (string) $minCfvo->getValue()); + $objWriter->writeAttribute('type', $minCfvo->getType()); + self::writeAttributeIf($objWriter, $minCfvo->getValue() !== null, 'val', (string) $minCfvo->getValue()); $objWriter->endElement(); } $maxCfvo = $dataBar->getMaximumConditionalFormatValueObject(); if ($maxCfvo) { $objWriter->startElement('cfvo'); - self::writeAttributeIf($objWriter, $maxCfvo->getType(), 'type', (string) $maxCfvo->getType()); - self::writeAttributeIf($objWriter, $maxCfvo->getValue(), 'val', (string) $maxCfvo->getValue()); + $objWriter->writeAttribute('type', $maxCfvo->getType()); + self::writeAttributeIf($objWriter, $maxCfvo->getValue() !== null, 'val', (string) $maxCfvo->getValue()); $objWriter->endElement(); } if ($dataBar->getColor()) { @@ -725,39 +725,52 @@ private static function writeColorScaleElements(XMLWriter $objWriter, ?Condition self::writeAttributeIf($objWriter, null !== $colorScale->getShowValue(), 'showValue', $colorScale->getShowValue() ? '1' : '0'); $minCfvo = $colorScale->getMinimumConditionalFormatValueObject(); - if ($minCfvo) { + $minArgb = $colorScale->getMinimumColor()?->getARGB(); + if ($minCfvo !== null || $minArgb !== null) { $objWriter->startElement('cfvo'); - self::writeAttributeIf($objWriter, $minCfvo->getType(), 'type', (string) $minCfvo->getType()); - self::writeAttributeIf($objWriter, $minCfvo->getValue(), 'val', (string) $minCfvo->getValue()); + $objWriter->writeAttribute('type', $minCfvo?->getType() ?? 'min'); + if ($minCfvo?->getValue() !== null) { + $objWriter->writeAttribute('val', (string) $minCfvo->getValue()); + } $objWriter->endElement(); } $midCfvo = $colorScale->getMidpointConditionalFormatValueObject(); - if ($midCfvo) { + $midArgb = $colorScale->getMidpointColor()?->getARGB(); + if ($midCfvo !== null || $midArgb !== null) { $objWriter->startElement('cfvo'); - self::writeAttributeIf($objWriter, $midCfvo->getType(), 'type', (string) $midCfvo->getType()); - self::writeAttributeIf($objWriter, $midCfvo->getValue(), 'val', (string) $midCfvo->getValue()); + $objWriter->writeAttribute('type', $midCfvo?->getType() ?? 'percentile'); + $objWriter->writeAttribute('val', (string) (($midCfvo?->getValue()) ?? '50')); $objWriter->endElement(); } $maxCfvo = $colorScale->getMaximumConditionalFormatValueObject(); - if ($maxCfvo) { + $maxArgb = $colorScale->getMaximumColor()?->getARGB(); + if ($maxCfvo !== null || $maxArgb !== null) { $objWriter->startElement('cfvo'); - self::writeAttributeIf($objWriter, $maxCfvo->getType(), 'type', (string) $maxCfvo->getType()); - self::writeAttributeIf($objWriter, $maxCfvo->getValue(), 'val', (string) $maxCfvo->getValue()); + $objWriter->writeAttribute('type', $maxCfvo?->getType() ?? 'max'); + if ($maxCfvo?->getValue() !== null) { + $objWriter->writeAttribute('val', (string) $maxCfvo->getValue()); + } $objWriter->endElement(); } - if ($colorScale->getMinimumColor()) { + if ($minCfvo !== null || $minArgb !== null) { $objWriter->startElement('color'); - $objWriter->writeAttribute('rgb', $colorScale->getMinimumColor()); + if ($minArgb !== null) { + $objWriter->writeAttribute('rgb', $minArgb); + } $objWriter->endElement(); } - if ($colorScale->getMidpointColor()) { + if ($midCfvo !== null || $midArgb !== null) { $objWriter->startElement('color'); - $objWriter->writeAttribute('rgb', $colorScale->getMidpointColor()); + if ($midArgb !== null) { + $objWriter->writeAttribute('rgb', $midArgb); + } $objWriter->endElement(); } - if ($colorScale->getMaximumColor()) { + if ($maxCfvo !== null || $maxArgb !== null) { $objWriter->startElement('color'); - $objWriter->writeAttribute('rgb', $colorScale->getMaximumColor()); + if ($maxArgb !== null) { + $objWriter->writeAttribute('rgb', $maxArgb); + } $objWriter->endElement(); } $objWriter->endElement(); // end colorScale @@ -800,8 +813,8 @@ private function writeConditionalFormatting(XMLWriter $objWriter, Phpspreadsheet self::writeAttributeIf( $objWriter, ($conditional->getConditionType() !== Conditional::CONDITION_COLORSCALE - && $conditional->getConditionType() !== Conditional::CONDITION_DATABAR - && $conditional->getNoFormatSet() === false), + && $conditional->getConditionType() !== Conditional::CONDITION_DATABAR + && $conditional->getNoFormatSet() === false), 'dxfId', (string) $this->getParentWriter()->getStylesConditionalHashTable()->getIndexForHashCode($conditional->getHashCode()) ); diff --git a/tests/PhpSpreadsheetTests/Reader/Xlsx/ConditionalColorScaleTest.php b/tests/PhpSpreadsheetTests/Reader/Xlsx/ConditionalColorScaleTest.php new file mode 100644 index 0000000000..6296f8e977 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Reader/Xlsx/ConditionalColorScaleTest.php @@ -0,0 +1,33 @@ +load($filename); + $reloadedSpreadsheet = $this->writeAndReload($spreadsheet, 'Xlsx'); + $spreadsheet->disconnectWorksheets(); + $worksheet = $reloadedSpreadsheet->getActiveSheet(); + $styles = $worksheet->getConditionalStyles('A1:A10'); + self::assertCount(1, $styles); + $colorScale = $styles[0]->getColorScale(); + self::assertNotNull($colorScale); + self::assertNotNull($colorScale->getMinimumConditionalFormatValueObject()); + self::assertNotNull($colorScale->getMidpointConditionalFormatValueObject()); + self::assertSame('50', $colorScale->getMidpointConditionalFormatValueObject()->getValue()); + self::assertNotNull($colorScale->getMaximumConditionalFormatValueObject()); + self::assertSame('FFF8696B', $colorScale->getMinimumColor()?->getARGB()); + self::assertSame('FFFFEB84', $colorScale->getMidpointColor()?->getARGB()); + self::assertSame('FF63BE7B', $colorScale->getMaximumColor()?->getARGB()); + $reloadedSpreadsheet->disconnectWorksheets(); + } +} diff --git a/tests/data/Reader/XLSX/colorscale.xlsx b/tests/data/Reader/XLSX/colorscale.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..35652544c563637ea33a1c237befdcd53632ff28 GIT binary patch literal 9457 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 literal 0 HcmV?d00001 From a16ca48ff03826727bf091c386643f8078f9156b Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Wed, 27 Sep 2023 08:18:34 -0700 Subject: [PATCH 3/7] Update cond08_colorscale.php --- samples/ConditionalFormatting/cond08_colorscale.php | 1 - 1 file changed, 1 deletion(-) diff --git a/samples/ConditionalFormatting/cond08_colorscale.php b/samples/ConditionalFormatting/cond08_colorscale.php index 5f6bfa6c1b..d63145970e 100644 --- a/samples/ConditionalFormatting/cond08_colorscale.php +++ b/samples/ConditionalFormatting/cond08_colorscale.php @@ -5,7 +5,6 @@ use PhpOffice\PhpSpreadsheet\Style\Conditional; use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\ConditionalColorScale; use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\ConditionalFormatValueObject; -use PhpOffice\PhpSpreadsheet\Style\Style; require __DIR__ . '/../Header.php'; From fe7193db7d6cededa6470fe2a99e6ffd5daf5e60 Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Wed, 27 Sep 2023 09:38:52 -0700 Subject: [PATCH 4/7] Improve Coverage --- src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php | 32 +++----------------- 1 file changed, 5 insertions(+), 27 deletions(-) diff --git a/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php b/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php index bc04cc6501..7ab023c604 100644 --- a/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php +++ b/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php @@ -729,9 +729,7 @@ private static function writeColorScaleElements(XMLWriter $objWriter, ?Condition if ($minCfvo !== null || $minArgb !== null) { $objWriter->startElement('cfvo'); $objWriter->writeAttribute('type', $minCfvo?->getType() ?? 'min'); - if ($minCfvo?->getValue() !== null) { - $objWriter->writeAttribute('val', (string) $minCfvo->getValue()); - } + self::writeAttributeIf($objWriter, $minCfvo?->getValue() !== null, 'val', (string) $minCfvo?->getValue()); $objWriter->endElement(); } $midCfvo = $colorScale->getMidpointConditionalFormatValueObject(); @@ -747,45 +745,25 @@ private static function writeColorScaleElements(XMLWriter $objWriter, ?Condition if ($maxCfvo !== null || $maxArgb !== null) { $objWriter->startElement('cfvo'); $objWriter->writeAttribute('type', $maxCfvo?->getType() ?? 'max'); - if ($maxCfvo?->getValue() !== null) { - $objWriter->writeAttribute('val', (string) $maxCfvo->getValue()); - } + self::writeAttributeIf($objWriter, $maxCfvo?->getValue() !== null, 'val', (string) $maxCfvo?->getValue()); $objWriter->endElement(); } if ($minCfvo !== null || $minArgb !== null) { $objWriter->startElement('color'); - if ($minArgb !== null) { - $objWriter->writeAttribute('rgb', $minArgb); - } + self::writeAttributeIf($objWriter, $minArgb !== null, 'rgb', "$minArgb"); $objWriter->endElement(); } if ($midCfvo !== null || $midArgb !== null) { $objWriter->startElement('color'); - if ($midArgb !== null) { - $objWriter->writeAttribute('rgb', $midArgb); - } + self::writeAttributeIf($objWriter, $midArgb !== null, 'rgb', "$midArgb"); $objWriter->endElement(); } if ($maxCfvo !== null || $maxArgb !== null) { $objWriter->startElement('color'); - if ($maxArgb !== null) { - $objWriter->writeAttribute('rgb', $maxArgb); - } + self::writeAttributeIf($objWriter, $maxArgb !== null, 'rgb', "$maxArgb"); $objWriter->endElement(); } $objWriter->endElement(); // end colorScale - - if ($colorScale->getConditionalFormattingRuleExt()) { - $objWriter->startElement('extLst'); - $extension = $colorScale->getConditionalFormattingRuleExt(); - $objWriter->startElement('ext'); - $objWriter->writeAttribute('uri', '{B025F937-C7B1-47D3-B67F-A62EFF666E3E}'); - $objWriter->startElementNs('x14', 'id', null); - $objWriter->text($extension->getId()); - $objWriter->endElement(); - $objWriter->endElement(); - $objWriter->endElement(); //end extLst - } } } From cac163f9ea11117f5c209e128bfe91bb91dd596f Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Wed, 27 Sep 2023 10:22:27 -0700 Subject: [PATCH 5/7] More Coverage Improvements --- .../ConditionalColorScale.php | 39 ------------------- src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php | 16 ++++---- 2 files changed, 9 insertions(+), 46 deletions(-) diff --git a/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalColorScale.php b/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalColorScale.php index a0ac40d252..d0bad650d2 100644 --- a/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalColorScale.php +++ b/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalColorScale.php @@ -6,13 +6,6 @@ class ConditionalColorScale { - /** attribute */ - - /** @var null|bool */ - private $showValue; - - /** children */ - /** @var ?ConditionalFormatValueObject */ private $minimumConditionalFormatValueObject; @@ -31,26 +24,6 @@ class ConditionalColorScale /** @var ?Color */ private $maximumColor; - /** */ - - /** @var ?ConditionalFormattingRuleExtension */ - private $conditionalFormattingRuleExt; - - /** - * @return null|bool - */ - public function getShowValue() - { - return $this->showValue; - } - - public function setShowValue(bool $showValue): self - { - $this->showValue = $showValue; - - return $this; - } - public function getMinimumConditionalFormatValueObject(): ?ConditionalFormatValueObject { return $this->minimumConditionalFormatValueObject; @@ -122,16 +95,4 @@ public function setMaximumColor(Color $maximumColor): self return $this; } - - public function getConditionalFormattingRuleExt(): ?ConditionalFormattingRuleExtension - { - return $this->conditionalFormattingRuleExt; - } - - public function setConditionalFormattingRuleExt(ConditionalFormattingRuleExtension $conditionalFormattingRuleExt): self - { - $this->conditionalFormattingRuleExt = $conditionalFormattingRuleExt; - - return $this; - } } diff --git a/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php b/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php index 7ab023c604..7efaaf9396 100644 --- a/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php +++ b/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php @@ -722,11 +722,11 @@ private static function writeColorScaleElements(XMLWriter $objWriter, ?Condition { if ($colorScale) { $objWriter->startElement('colorScale'); - self::writeAttributeIf($objWriter, null !== $colorScale->getShowValue(), 'showValue', $colorScale->getShowValue() ? '1' : '0'); $minCfvo = $colorScale->getMinimumConditionalFormatValueObject(); $minArgb = $colorScale->getMinimumColor()?->getARGB(); - if ($minCfvo !== null || $minArgb !== null) { + $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()); @@ -734,7 +734,8 @@ private static function writeColorScaleElements(XMLWriter $objWriter, ?Condition } $midCfvo = $colorScale->getMidpointConditionalFormatValueObject(); $midArgb = $colorScale->getMidpointColor()?->getARGB(); - if ($midCfvo !== null || $midArgb !== null) { + $useMid = $midCfvo !== null || $midArgb !== null; + if ($useMid) { $objWriter->startElement('cfvo'); $objWriter->writeAttribute('type', $midCfvo?->getType() ?? 'percentile'); $objWriter->writeAttribute('val', (string) (($midCfvo?->getValue()) ?? '50')); @@ -742,23 +743,24 @@ private static function writeColorScaleElements(XMLWriter $objWriter, ?Condition } $maxCfvo = $colorScale->getMaximumConditionalFormatValueObject(); $maxArgb = $colorScale->getMaximumColor()?->getARGB(); - if ($maxCfvo !== null || $maxArgb !== null) { + $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()); $objWriter->endElement(); } - if ($minCfvo !== null || $minArgb !== null) { + if ($useMin) { $objWriter->startElement('color'); self::writeAttributeIf($objWriter, $minArgb !== null, 'rgb', "$minArgb"); $objWriter->endElement(); } - if ($midCfvo !== null || $midArgb !== null) { + if ($useMid) { $objWriter->startElement('color'); self::writeAttributeIf($objWriter, $midArgb !== null, 'rgb', "$midArgb"); $objWriter->endElement(); } - if ($maxCfvo !== null || $maxArgb !== null) { + if ($useMax) { $objWriter->startElement('color'); self::writeAttributeIf($objWriter, $maxArgb !== null, 'rgb', "$maxArgb"); $objWriter->endElement(); From 6482ac57e43ef4086a2d4130ed79ed39a68af282 Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Thu, 28 Sep 2023 09:16:54 -0700 Subject: [PATCH 6/7] Use StyleReader for Colors for ColorScale and DataBar The implementation of DataBar looks for an rgb attribute, but the color may be provided via theme attribute instead. The initial implementation for ColorScale did the same. Change both to use the existing code in Reader\Xlsx\Styles to parse the color. --- src/PhpSpreadsheet/Reader/Xlsx.php | 4 ++-- .../Reader/Xlsx/ConditionalStyles.php | 24 ++++++++++--------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/PhpSpreadsheet/Reader/Xlsx.php b/src/PhpSpreadsheet/Reader/Xlsx.php index 57d1c1c402..fad37d7f1b 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx.php +++ b/src/PhpSpreadsheet/Reader/Xlsx.php @@ -790,10 +790,10 @@ protected function loadSpreadsheetFromFile(string $filename): Spreadsheet // Setting Conditional Styles adjusts selected cells, so we need to execute this // before reading the sheet view data to get the actual selected cells if (!$this->readDataOnly && ($xmlSheet->conditionalFormatting)) { - (new ConditionalStyles($docSheet, $xmlSheet, $dxfs))->load(); + (new ConditionalStyles($docSheet, $xmlSheet, $dxfs, $this->styleReader))->load(); } if (!$this->readDataOnly && $xmlSheet->extLst) { - (new ConditionalStyles($docSheet, $xmlSheet, $dxfs))->loadFromExt($this->styleReader); + (new ConditionalStyles($docSheet, $xmlSheet, $dxfs, $this->styleReader))->loadFromExt(); } if (isset($xmlSheetMain->sheetViews, $xmlSheetMain->sheetViews->sheetView)) { $sheetViews = new SheetViews($xmlSheetMain->sheetViews->sheetView, $docSheet); diff --git a/src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php b/src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php index 564d7bd457..280c75eb09 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php +++ b/src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php @@ -27,11 +27,14 @@ class ConditionalStyles private array $dxfs; - public function __construct(Worksheet $workSheet, SimpleXMLElement $worksheetXml, array $dxfs = []) + private StyleReader $styleReader; + + public function __construct(Worksheet $workSheet, SimpleXMLElement $worksheetXml, array $dxfs, StyleReader $styleReader) { $this->worksheet = $workSheet; $this->worksheetXml = $worksheetXml; $this->dxfs = $dxfs; + $this->styleReader = $styleReader; } public function load(): void @@ -47,13 +50,13 @@ public function load(): void $this->worksheet->setSelectedCells($selectedCells); } - public function loadFromExt(StyleReader $styleReader): void + public function loadFromExt(): void { $selectedCells = $this->worksheet->getSelectedCells(); $this->ns = $this->worksheetXml->getNamespaces(true); $this->setConditionalsFromExt( - $this->readConditionalsFromExt($this->worksheetXml->extLst, $styleReader) + $this->readConditionalsFromExt($this->worksheetXml->extLst) ); $this->worksheet->setSelectedCells($selectedCells); @@ -70,7 +73,7 @@ private function setConditionalsFromExt(array $conditionals): void } } - private function readConditionalsFromExt(SimpleXMLElement $extLst, StyleReader $styleReader): array + private function readConditionalsFromExt(SimpleXMLElement $extLst): array { $conditionals = []; if (!isset($extLst->ext)) { @@ -112,7 +115,7 @@ private function readConditionalsFromExt(SimpleXMLElement $extLst, StyleReader $ $priority = (int) $attributes->priority; $conditional = $this->readConditionalRuleFromExt($extCfRuleXml, $attributes); - $cfStyle = $this->readStyleFromExt($extCfRuleXml, $styleReader); + $cfStyle = $this->readStyleFromExt($extCfRuleXml); $conditional->setStyle($cfStyle); $conditionals[$sqref][$priority] = $conditional; } @@ -148,17 +151,17 @@ private function readConditionalRuleFromExt(SimpleXMLElement $cfRuleXml, SimpleX return $conditional; } - private function readStyleFromExt(SimpleXMLElement $extCfRuleXml, StyleReader $styleReader): Style + private function readStyleFromExt(SimpleXMLElement $extCfRuleXml): Style { $cfStyle = new Style(false, true); if ($extCfRuleXml->dxf) { $styleXML = $extCfRuleXml->dxf->children(); if ($styleXML->borders) { - $styleReader->readBorderStyle($cfStyle->getBorders(), $styleXML->borders); + $this->styleReader->readBorderStyle($cfStyle->getBorders(), $styleXML->borders); } if ($styleXML->fill) { - $styleReader->readFillStyle($cfStyle->getFill(), $styleXML->fill); + $this->styleReader->readFillStyle($cfStyle->getFill(), $styleXML->fill); } } @@ -277,7 +280,7 @@ private function readDataBarOfConditionalRule($cfRule, array $conditionalFormatt //color if (isset($cfRule->dataBar->color)) { - $dataBar->setColor((string) $cfRule->dataBar->color['rgb']); + $dataBar->setColor($this->styleReader->readColor($cfRule->dataBar->color)); } //extLst $this->readDataBarExtLstOfConditionalRule($dataBar, $cfRule, $conditionalFormattingRuleExtensions); @@ -305,8 +308,7 @@ private function readColorScale(simpleXMLElement|stdClass $cfRule): ConditionalC $idx = 0; foreach ($cfRule->colorScale->color as $color) { $type = $types[$idx]; - $attr = $color->attributes() ?? []; - $rgb = $attr['rgb'] ?? ''; + $rgb = $this->styleReader->readColor($color); if ($type === 'min') { $colorScale->setMinimumColor(new Color($rgb)); } elseif ($type === 'percentile') { From 3fe6e8b190f114cdadcbf5601c3f3722aedea035 Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Fri, 29 Sep 2023 00:00:44 -0700 Subject: [PATCH 7/7] Change Some Doc Blocks to Type Declarations --- src/PhpSpreadsheet/Style/Conditional.php | 44 +++---------------- .../ConditionalColorScale.php | 18 +++----- .../ConditionalDataBar.php | 1 - .../ConditionalFormatValueObject.php | 10 +---- 4 files changed, 14 insertions(+), 59 deletions(-) diff --git a/src/PhpSpreadsheet/Style/Conditional.php b/src/PhpSpreadsheet/Style/Conditional.php index fb5c4643fe..9f6e8c7dce 100644 --- a/src/PhpSpreadsheet/Style/Conditional.php +++ b/src/PhpSpreadsheet/Style/Conditional.php @@ -94,10 +94,8 @@ class Conditional implements IComparable /** * Stop on this condition, if it matches. - * - * @var bool */ - private $stopIfTrue = false; + private bool $stopIfTrue = false; /** * Condition. @@ -106,23 +104,13 @@ class Conditional implements IComparable */ private $condition = []; - /** - * @var ConditionalDataBar - */ - private $dataBar; + private ?ConditionalDataBar $dataBar = null; - /** - * @var ConditionalColorScale - */ - private $colorScale; + private ?ConditionalColorScale $colorScale = null; - /** - * Style. - */ private Style $style; - /** @var bool */ - private $noFormatSet = false; + private bool $noFormatSet = false; /** * Create a new Conditional. @@ -304,21 +292,11 @@ public function setStyle(Style $style): static return $this; } - /** - * get DataBar. - * - * @return null|ConditionalDataBar - */ - public function getDataBar() + public function getDataBar(): ?ConditionalDataBar { return $this->dataBar; } - /** - * set DataBar. - * - * @return $this - */ public function setDataBar(ConditionalDataBar $dataBar): static { $this->dataBar = $dataBar; @@ -326,21 +304,11 @@ public function setDataBar(ConditionalDataBar $dataBar): static return $this; } - /** - * get ColorScale. - * - * @return null|ConditionalColorScale - */ - public function getColorScale() + public function getColorScale(): ?ConditionalColorScale { return $this->colorScale; } - /** - * set ColorScale. - * - * @return $this - */ public function setColorScale(ConditionalColorScale $colorScale): static { $this->colorScale = $colorScale; diff --git a/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalColorScale.php b/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalColorScale.php index d0bad650d2..7fcc08038d 100644 --- a/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalColorScale.php +++ b/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalColorScale.php @@ -6,23 +6,17 @@ class ConditionalColorScale { - /** @var ?ConditionalFormatValueObject */ - private $minimumConditionalFormatValueObject; + private ?ConditionalFormatValueObject $minimumConditionalFormatValueObject = null; - /** @var ?ConditionalFormatValueObject */ - private $midpointConditionalFormatValueObject; + private ?ConditionalFormatValueObject $midpointConditionalFormatValueObject = null; - /** @var ?ConditionalFormatValueObject */ - private $maximumConditionalFormatValueObject; + private ?ConditionalFormatValueObject $maximumConditionalFormatValueObject = null; - /** @var ?Color */ - private $minimumColor; + private ?Color $minimumColor = null; - /** @var ?Color */ - private $midpointColor; + private ?Color $midpointColor = null; - /** @var ?Color */ - private $maximumColor; + private ?Color $maximumColor = null; public function getMinimumConditionalFormatValueObject(): ?ConditionalFormatValueObject { diff --git a/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalDataBar.php b/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalDataBar.php index b6755fb7d1..370f102547 100644 --- a/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalDataBar.php +++ b/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalDataBar.php @@ -4,7 +4,6 @@ class ConditionalDataBar { - /** attribute */ private ?bool $showValue = null; private ?ConditionalFormatValueObject $minimumConditionalFormatValueObject = null; diff --git a/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormatValueObject.php b/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormatValueObject.php index 1790e23b12..43f480804b 100644 --- a/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormatValueObject.php +++ b/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormatValueObject.php @@ -10,10 +10,7 @@ class ConditionalFormatValueObject private mixed $cellFormula; - /** - * ConditionalFormatValueObject constructor. - */ - public function __construct(string $type, mixed $value = null, mixed $cellFormula = null) + public function __construct(string $type, null|float|int|string $value = null, mixed $cellFormula = null) { $this->type = $type; $this->value = $value; @@ -44,10 +41,7 @@ public function setValue(null|float|int|string $value): self return $this; } - /** - * @return mixed - */ - public function getCellFormula() + public function getCellFormula(): mixed { return $this->cellFormula; }