Skip to content

Commit a863926

Browse files
committed
Support DataBar of conditional formatting rule
Implemented the databar of Conditional Type. - DataBar can be read, written, and added for basic use. - Supports reading, writing and adding using "extLst". About "extLst" - https://docs.microsoft.com/en-us/openspecs/office_standards/ms-xlsx/07d607af-5618-4ca2-b683-6a78dc0d9627 The following setting items on the Excel setting screen can be read, written, and added. - (minimum, maximum)type: Automatic, LowestValue, Number, Percent, Formula, Percentile - Direction: context, leftToRight, rightToLeft (show data bar only) - Fills Solid, Gradient - FillColor: PositiveValues, NegativeValues - Borders: Solid, None - BorderColor: PositiveValues, NegativeValues - Axis position: Automatic, Midpoint, None - Axis color
1 parent 40abd18 commit a863926

File tree

9 files changed

+1189
-12
lines changed

9 files changed

+1189
-12
lines changed

src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php

+56-10
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22

33
namespace PhpOffice\PhpSpreadsheet\Reader\Xlsx;
44

5+
use PhpOffice\PhpSpreadsheet\Style\Color;
56
use PhpOffice\PhpSpreadsheet\Style\Conditional;
7+
use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\ConditionalDataBar;
8+
use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\ConditionalFormattingRuleExtension;
69
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
710
use SimpleXMLElement;
811

@@ -25,7 +28,8 @@ public function load(): void
2528
{
2629
$this->setConditionalStyles(
2730
$this->worksheet,
28-
$this->readConditionalStyles($this->worksheetXml)
31+
$this->readConditionalStyles($this->worksheetXml),
32+
$this->worksheetXml->extLst
2933
);
3034
}
3135

@@ -36,26 +40,28 @@ private function readConditionalStyles($xmlSheet)
3640
foreach ($conditional->cfRule as $cfRule) {
3741
if (
3842
((string) $cfRule['type'] == Conditional::CONDITION_NONE
39-
|| (string) $cfRule['type'] == Conditional::CONDITION_CELLIS
40-
|| (string) $cfRule['type'] == Conditional::CONDITION_CONTAINSTEXT
41-
|| (string) $cfRule['type'] == Conditional::CONDITION_CONTAINSBLANKS
42-
|| (string) $cfRule['type'] == Conditional::CONDITION_NOTCONTAINSBLANKS
43-
|| (string) $cfRule['type'] == Conditional::CONDITION_EXPRESSION)
43+
|| (string) $cfRule['type'] == Conditional::CONDITION_CELLIS
44+
|| (string) $cfRule['type'] == Conditional::CONDITION_CONTAINSTEXT
45+
|| (string) $cfRule['type'] == Conditional::CONDITION_CONTAINSBLANKS
46+
|| (string) $cfRule['type'] == Conditional::CONDITION_NOTCONTAINSBLANKS
47+
|| (string) $cfRule['type'] == Conditional::CONDITION_EXPRESSION)
4448
&& isset($this->dxfs[(int) ($cfRule['dxfId'])])
4549
) {
4650
$conditionals[(string) $conditional['sqref']][(int) ($cfRule['priority'])] = $cfRule;
51+
} elseif ((string) $cfRule['type'] == Conditional::CONDITION_DATABAR) {
52+
$conditionals[(string) $conditional['sqref']][(int) ($cfRule['priority'])] = $cfRule;
4753
}
4854
}
4955
}
5056

5157
return $conditionals;
5258
}
5359

54-
private function setConditionalStyles(Worksheet $worksheet, array $conditionals): void
60+
private function setConditionalStyles(Worksheet $worksheet, array $conditionals, $xmlExtLst): void
5561
{
5662
foreach ($conditionals as $ref => $cfRules) {
5763
ksort($cfRules);
58-
$conditionalStyles = $this->readStyleRules($cfRules);
64+
$conditionalStyles = $this->readStyleRules($cfRules, $xmlExtLst);
5965

6066
// Extract all cell references in $ref
6167
$cellBlocks = explode(' ', str_replace('$', '', strtoupper($ref)));
@@ -65,8 +71,9 @@ private function setConditionalStyles(Worksheet $worksheet, array $conditionals)
6571
}
6672
}
6773

68-
private function readStyleRules($cfRules)
74+
private function readStyleRules($cfRules, $extLst)
6975
{
76+
$conditionalFormattingRuleExtensions = ConditionalFormattingRuleExtension::parseExtLstXml($extLst);
7077
$conditionalStyles = [];
7178
foreach ($cfRules as $cfRule) {
7279
$objConditional = new Conditional();
@@ -88,10 +95,49 @@ private function readStyleRules($cfRules)
8895
} else {
8996
$objConditional->addCondition((string) $cfRule->formula);
9097
}
91-
$objConditional->setStyle(clone $this->dxfs[(int) ($cfRule['dxfId'])]);
98+
99+
if (isset($cfRule->dataBar)) {
100+
$objConditional->setDataBar($this->readDataBarOfConditionalRule($cfRule, $conditionalFormattingRuleExtensions));
101+
} else {
102+
$objConditional->setStyle(clone $this->dxfs[(int) ($cfRule['dxfId'])]);
103+
}
104+
92105
$conditionalStyles[] = $objConditional;
93106
}
94107

95108
return $conditionalStyles;
96109
}
110+
111+
private function readDataBarOfConditionalRule($cfRule, $conditionalFormattingRuleExtensions): ConditionalDataBar
112+
{
113+
$dataBar = new ConditionalDataBar();
114+
//dataBar attribute
115+
if (isset($cfRule->dataBar['showValue'])) {
116+
$dataBar->setShowValue((int) $cfRule->dataBar['showValue']);
117+
}
118+
119+
//dataBar children
120+
//conditionalFormatValueObjects
121+
$cfvoXml = $cfRule->dataBar->cfvo;
122+
foreach ((count($cfvoXml) > 1 ? $cfvoXml : [$cfvoXml]) as $cfvo) {
123+
$dataBar->addConditionalFormatValueObject((string) $cfvo['type'], (string) $cfvo['val']);
124+
}
125+
126+
//color
127+
if (isset($cfRule->dataBar->color)) {
128+
$dataBar->setColor(new Color((string) $cfRule->dataBar->color['rgb']));
129+
}
130+
//extLst
131+
if (isset($cfRule->extLst)) {
132+
$ns = $cfRule->extLst->getNamespaces(true);
133+
foreach ((count($cfRule->extLst) > 0 ? $cfRule->extLst->ext : [$cfRule->extLst->ext]) as $ext) {
134+
$extId = (string) $ext->children($ns['x14'])->id;
135+
if (isset($conditionalFormattingRuleExtensions[$extId]) && (string) $ext['uri'] === '{B025F937-C7B1-47D3-B67F-A62EFF666E3E}') {
136+
$dataBar->addConditionalFormattingRuleExtList($conditionalFormattingRuleExtensions[$extId]);
137+
}
138+
}
139+
}
140+
141+
return $dataBar;
142+
}
97143
}

src/PhpSpreadsheet/Style/Conditional.php

+29
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace PhpOffice\PhpSpreadsheet\Style;
44

55
use PhpOffice\PhpSpreadsheet\IComparable;
6+
use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\ConditionalDataBar;
67

78
class Conditional implements IComparable
89
{
@@ -13,6 +14,7 @@ class Conditional implements IComparable
1314
const CONDITION_EXPRESSION = 'expression';
1415
const CONDITION_CONTAINSBLANKS = 'containsBlanks';
1516
const CONDITION_NOTCONTAINSBLANKS = 'notContainsBlanks';
17+
const CONDITION_DATABAR = 'dataBar';
1618

1719
// Operator types
1820
const OPERATOR_NONE = '';
@@ -64,6 +66,11 @@ class Conditional implements IComparable
6466
*/
6567
private $condition = [];
6668

69+
/**
70+
* @var ConditionalDataBar
71+
*/
72+
private $dataBar;
73+
6774
/**
6875
* Style.
6976
*
@@ -241,6 +248,28 @@ public function setStyle(?Style $pValue = null)
241248
return $this;
242249
}
243250

251+
/**
252+
* get DataBar.
253+
*
254+
* @return ConditionalDataBar | null
255+
*/
256+
public function getDataBar()
257+
{
258+
return $this->dataBar;
259+
}
260+
261+
/**
262+
* set DataBar.
263+
*
264+
* @return $this
265+
*/
266+
public function setDataBar(ConditionalDataBar $dataBar)
267+
{
268+
$this->dataBar = $dataBar;
269+
270+
return $this;
271+
}
272+
244273
/**
245274
* Get hash code.
246275
*
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
<?php
2+
3+
namespace PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting;
4+
5+
use PhpOffice\PhpSpreadsheet\Style\Color;
6+
7+
class ConditionalDataBar
8+
{
9+
/** <dataBar> attribute */
10+
private $showValue;
11+
12+
/** <dataBar> children */
13+
14+
/** @var ConditionalFormatValueObject[] */
15+
private $conditionalFormatValueObjects = [];
16+
17+
/** @var Color */
18+
private $color;
19+
20+
/** @var ConditionalFormattingRuleExtension[] */
21+
private $conditionalFormattingRuleExtList = [];
22+
23+
/**
24+
* @return null|string
25+
*/
26+
public function getShowValue()
27+
{
28+
return $this->showValue;
29+
}
30+
31+
/**
32+
* @param int $showValue
33+
*/
34+
public function setShowValue($showValue)
35+
{
36+
$this->showValue = $showValue;
37+
38+
return $this;
39+
}
40+
41+
/**
42+
* @return ConditionalFormatValueObject[]
43+
*/
44+
public function getConditionalFormatValueObjects(): array
45+
{
46+
return $this->conditionalFormatValueObjects;
47+
}
48+
49+
/**
50+
* @param ConditionalFormatValueObject[] $conditionalFormatValueObjects
51+
*/
52+
public function setConditionalFormatValueObjects(array $conditionalFormatValueObjects)
53+
{
54+
$this->conditionalFormatValueObjects = $conditionalFormatValueObjects;
55+
56+
return $this;
57+
}
58+
59+
/**
60+
* @param mixed $type
61+
* @param null|mixed $value
62+
* @param null|mixed $cellFomula
63+
*
64+
* @return $this
65+
*/
66+
public function addConditionalFormatValueObject($type, $value = null, $cellFomula = null): self
67+
{
68+
$this->conditionalFormatValueObjects[] = new ConditionalFormatValueObject($type, $value, $cellFomula);
69+
70+
return $this;
71+
}
72+
73+
public function getColor(): Color
74+
{
75+
return $this->color;
76+
}
77+
78+
public function setColor(Color $color): self
79+
{
80+
$this->color = $color;
81+
82+
return $this;
83+
}
84+
85+
/**
86+
* @return ConditionalFormattingRuleExtension[]
87+
*/
88+
public function getConditionalFormattingRuleExtList(): array
89+
{
90+
return $this->conditionalFormattingRuleExtList;
91+
}
92+
93+
/**
94+
* @param ConditionalFormattingRuleExtension[] $conditionalFormattingRuleExtList
95+
*/
96+
public function setConditionalFormattingRuleExtList(array $conditionalFormattingRuleExtList): self
97+
{
98+
$this->conditionalFormattingRuleExtList = $conditionalFormattingRuleExtList;
99+
100+
return $this;
101+
}
102+
103+
/**
104+
* @return $this
105+
*/
106+
public function addConditionalFormattingRuleExtList(ConditionalFormattingRuleExtension $conditionalFormattingRuleExt): self
107+
{
108+
$this->conditionalFormattingRuleExtList[] = $conditionalFormattingRuleExt;
109+
110+
return $this;
111+
}
112+
}

0 commit comments

Comments
 (0)