Skip to content

Commit 653645c

Browse files
authored
Merge pull request #4574 from issakujitsuk/icon-set
Add Conditional Formatting with IconSet
2 parents d88efca + 782610d commit 653645c

File tree

10 files changed

+598
-6
lines changed

10 files changed

+598
-6
lines changed
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
<?php
2+
3+
use PhpOffice\PhpSpreadsheet\Spreadsheet;
4+
use PhpOffice\PhpSpreadsheet\Style\Conditional;
5+
use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\ConditionalFormatValueObject;
6+
use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\ConditionalIconSet;
7+
use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\IconSetValues;
8+
9+
require __DIR__ . '/../Header.php';
10+
/** @var PhpOffice\PhpSpreadsheet\Helper\Sample $helper */
11+
12+
// Create new Spreadsheet object
13+
$helper->log('Create new Spreadsheet object');
14+
$spreadsheet = new Spreadsheet();
15+
$sheet = $spreadsheet->getActiveSheet();
16+
17+
// Set document properties
18+
$helper->log('Set document properties');
19+
$spreadsheet->getProperties()->setCreator('issakujitsuk')
20+
->setLastModifiedBy('issakujitsuk')
21+
->setTitle('PhpSpreadsheet Test Document')
22+
->setSubject('PhpSpreadsheet Test Document')
23+
->setDescription('Test document for PhpSpreadsheet, generated using PHP classes.')
24+
->setKeywords('office PhpSpreadsheet php')
25+
->setCategory('Test result file');
26+
27+
// Create the worksheet
28+
$helper->log('Add data');
29+
foreach (['A', 'B', 'C'] as $columnIndex) {
30+
$sheet
31+
->setCellValue("{$columnIndex}1", 1)
32+
->setCellValue("{$columnIndex}2", 2)
33+
->setCellValue("{$columnIndex}3", 8)
34+
->setCellValue("{$columnIndex}4", 4)
35+
->setCellValue("{$columnIndex}5", 5)
36+
->setCellValue("{$columnIndex}6", 6)
37+
->setCellValue("{$columnIndex}7", 7)
38+
->setCellValue("{$columnIndex}8", 3)
39+
->setCellValue("{$columnIndex}9", 9)
40+
->setCellValue("{$columnIndex}10", 10);
41+
}
42+
43+
// Set conditional formatting rules and styles
44+
$helper->log('Define conditional formatting using Icon Set');
45+
46+
// 3 icons
47+
$sheet->getStyle('A1:A10')
48+
->setConditionalStyles([
49+
makeConditionalIconSet(
50+
IconSetValues::ThreeSymbols,
51+
[
52+
new ConditionalFormatValueObject('percent', 0),
53+
new ConditionalFormatValueObject('percent', 33),
54+
new ConditionalFormatValueObject('percent', 67),
55+
]
56+
),
57+
]);
58+
59+
// 4 icons
60+
$sheet->getStyle('B1:B10')
61+
->setConditionalStyles([
62+
makeConditionalIconSet(
63+
IconSetValues::FourArrows,
64+
[
65+
new ConditionalFormatValueObject('percent', 0),
66+
new ConditionalFormatValueObject('percent', 25),
67+
new ConditionalFormatValueObject('percent', 50),
68+
new ConditionalFormatValueObject('percent', 75),
69+
]
70+
),
71+
]);
72+
73+
// 5 icons
74+
$sheet->getStyle('C1:C10')
75+
->setConditionalStyles([
76+
makeConditionalIconSet(
77+
IconSetValues::FiveQuarters,
78+
[
79+
new ConditionalFormatValueObject('percent', 0),
80+
new ConditionalFormatValueObject('percent', 20),
81+
new ConditionalFormatValueObject('percent', 40),
82+
new ConditionalFormatValueObject('percent', 60),
83+
new ConditionalFormatValueObject('percent', 80),
84+
]
85+
),
86+
]);
87+
88+
// Save
89+
$sheet->setSelectedCells('A1');
90+
$helper->write($spreadsheet, __FILE__, ['Xlsx']);
91+
92+
/**
93+
* Helper function to create a Conditional object with an IconSet.
94+
*
95+
* @param IconSetValues $type The type of icon set
96+
* @param ConditionalFormatValueObject[] $cfvos The conditional format value objects
97+
*/
98+
function makeConditionalIconSet(
99+
IconSetValues $type,
100+
array $cfvos,
101+
): Conditional {
102+
$condition = new Conditional();
103+
$condition->setConditionType(Conditional::CONDITION_ICONSET);
104+
$iconSet = new ConditionalIconSet();
105+
$condition->setIconSet($iconSet);
106+
$iconSet->setIconSetType($type)
107+
->setCfvos($cfvos);
108+
109+
return $condition;
110+
}

src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\ConditionalDataBar;
1010
use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\ConditionalFormattingRuleExtension;
1111
use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\ConditionalFormatValueObject;
12+
use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\ConditionalIconSet;
13+
use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\IconSetValues;
1214
use PhpOffice\PhpSpreadsheet\Style\Style as Style;
1315
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
1416
use SimpleXMLElement;
@@ -265,6 +267,8 @@ private function readStyleRules(array $cfRules, SimpleXMLElement $extLst): array
265267
$objConditional->setColorScale(
266268
$this->readColorScale($cfRule)
267269
);
270+
} elseif (isset($cfRule->iconSet)) {
271+
$objConditional->setIconSet($this->readIconSet($cfRule));
268272
} elseif (isset($cfRule['dxfId'])) {
269273
$objConditional->setStyle(clone $this->dxfs[(int) ($cfRule['dxfId'])]);
270274
}
@@ -349,6 +353,40 @@ private function readColorScale(SimpleXMLElement|stdClass $cfRule): ConditionalC
349353
return $colorScale;
350354
}
351355

356+
private function readIconSet(SimpleXMLElement $cfRule): ConditionalIconSet
357+
{
358+
$iconSet = new ConditionalIconSet();
359+
360+
if (isset($cfRule->iconSet['iconSet'])) {
361+
$iconSet->setIconSetType(IconSetValues::from($cfRule->iconSet['iconSet']));
362+
}
363+
if (isset($cfRule->iconSet['reverse'])) {
364+
$iconSet->setReverse('1' === (string) $cfRule->iconSet['reverse']);
365+
}
366+
if (isset($cfRule->iconSet['showValue'])) {
367+
$iconSet->setShowValue('1' === (string) $cfRule->iconSet['showValue']);
368+
}
369+
if (isset($cfRule->iconSet['custom'])) {
370+
$iconSet->setCustom('1' === (string) $cfRule->iconSet['custom']);
371+
}
372+
373+
$cfvos = [];
374+
foreach ($cfRule->iconSet->cfvo as $cfvoXml) {
375+
$type = (string) $cfvoXml['type'];
376+
$value = (string) ($cfvoXml['val'] ?? '');
377+
$cfvo = new ConditionalFormatValueObject($type, $value);
378+
if (isset($cfvoXml['gte'])) {
379+
$cfvo->setGreaterThanOrEqual('1' === (string) $cfvoXml['gte']);
380+
}
381+
$cfvos[] = $cfvo;
382+
}
383+
$iconSet->setCfvos($cfvos);
384+
385+
// TODO: The cfIcon element is not implemented yet.
386+
387+
return $iconSet;
388+
}
389+
352390
/** @param ConditionalFormattingRuleExtension[] $conditionalFormattingRuleExtensions */
353391
private function readDataBarExtLstOfConditionalRule(ConditionalDataBar $dataBar, SimpleXMLElement $cfRule, array $conditionalFormattingRuleExtensions): void
354392
{

src/PhpSpreadsheet/Style/Conditional.php

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use PhpOffice\PhpSpreadsheet\IComparable;
66
use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\ConditionalColorScale;
77
use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\ConditionalDataBar;
8+
use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\ConditionalIconSet;
89

910
class Conditional implements IComparable
1011
{
@@ -25,6 +26,7 @@ class Conditional implements IComparable
2526
const CONDITION_TIMEPERIOD = 'timePeriod';
2627
const CONDITION_DUPLICATES = 'duplicateValues';
2728
const CONDITION_UNIQUE = 'uniqueValues';
29+
const CONDITION_ICONSET = 'iconSet';
2830

2931
private const CONDITION_TYPES = [
3032
self::CONDITION_BEGINSWITH,
@@ -43,6 +45,7 @@ class Conditional implements IComparable
4345
self::CONDITION_NOTCONTAINSTEXT,
4446
self::CONDITION_TIMEPERIOD,
4547
self::CONDITION_UNIQUE,
48+
self::CONDITION_ICONSET,
4649
];
4750

4851
// Operator types
@@ -102,6 +105,8 @@ class Conditional implements IComparable
102105

103106
private ?ConditionalColorScale $colorScale = null;
104107

108+
private ?ConditionalIconSet $iconSet = null;
109+
105110
private Style $style;
106111

107112
private bool $noFormatSet = false;
@@ -318,6 +323,18 @@ public function setColorScale(ConditionalColorScale $colorScale): static
318323
return $this;
319324
}
320325

326+
public function getIconSet(): ?ConditionalIconSet
327+
{
328+
return $this->iconSet;
329+
}
330+
331+
public function setIconSet(ConditionalIconSet $iconSet): static
332+
{
333+
$this->iconSet = $iconSet;
334+
335+
return $this;
336+
}
337+
321338
/**
322339
* Get hash code.
323340
*
@@ -327,10 +344,10 @@ public function getHashCode(): string
327344
{
328345
return md5(
329346
$this->conditionType
330-
. $this->operatorType
331-
. implode(';', $this->condition)
332-
. $this->style->getHashCode()
333-
. __CLASS__
347+
. $this->operatorType
348+
. implode(';', $this->condition)
349+
. $this->style->getHashCode()
350+
. __CLASS__
334351
);
335352
}
336353

src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormatValueObject.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,13 @@ class ConditionalFormatValueObject
1010

1111
private ?string $cellFormula;
1212

13+
/**
14+
* For icon sets, determines whether this threshold value uses the greater
15+
* than or equal to operator. False indicates 'greater than' is used instead
16+
* of 'greater than or equal to'.
17+
*/
18+
private ?bool $greaterThanOrEqual = null;
19+
1320
public function __construct(string $type, null|float|int|string $value = null, ?string $cellFormula = null)
1421
{
1522
$this->type = $type;
@@ -52,4 +59,16 @@ public function setCellFormula(?string $cellFormula): self
5259

5360
return $this;
5461
}
62+
63+
public function getGreaterThanOrEqual(): ?bool
64+
{
65+
return $this->greaterThanOrEqual;
66+
}
67+
68+
public function setGreaterThanOrEqual(?bool $greaterThanOrEqual): self
69+
{
70+
$this->greaterThanOrEqual = $greaterThanOrEqual;
71+
72+
return $this;
73+
}
5574
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<?php
2+
3+
namespace PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting;
4+
5+
class ConditionalIconSet
6+
{
7+
/** The icon set to display. */
8+
private ?IconSetValues $iconSetType = null;
9+
10+
/** If true, reverses the default order of the icons in this icon set. */
11+
private ?bool $reverse = null;
12+
13+
/** Indicates whether to show the values of the cells on which this icon set is applied. */
14+
private ?bool $showValue = null;
15+
16+
/**
17+
* If true, indicates that the icon set is a custom icon set.
18+
* If this value is "true", there MUST be the same number of cfIcon elements
19+
* as cfvo elements.
20+
* If this value is "false", there MUST be 0 cfIcon elements.
21+
*/
22+
private ?bool $custom = null;
23+
24+
/** @var ConditionalFormatValueObject[] */
25+
private array $cfvos = [];
26+
27+
public function getIconSetType(): ?IconSetValues
28+
{
29+
return $this->iconSetType;
30+
}
31+
32+
public function setIconSetType(IconSetValues $type): self
33+
{
34+
$this->iconSetType = $type;
35+
36+
return $this;
37+
}
38+
39+
public function getReverse(): ?bool
40+
{
41+
return $this->reverse;
42+
}
43+
44+
public function setReverse(bool $reverse): self
45+
{
46+
$this->reverse = $reverse;
47+
48+
return $this;
49+
}
50+
51+
public function getShowValue(): ?bool
52+
{
53+
return $this->showValue;
54+
}
55+
56+
public function setShowValue(bool $showValue): self
57+
{
58+
$this->showValue = $showValue;
59+
60+
return $this;
61+
}
62+
63+
public function getCustom(): ?bool
64+
{
65+
return $this->custom;
66+
}
67+
68+
public function setCustom(bool $custom): self
69+
{
70+
$this->custom = $custom;
71+
72+
return $this;
73+
}
74+
75+
/**
76+
* Get the conditional format value objects.
77+
*
78+
* @return ConditionalFormatValueObject[]
79+
*/
80+
public function getCfvos(): array
81+
{
82+
return $this->cfvos;
83+
}
84+
85+
/**
86+
* Set the conditional format value objects.
87+
*
88+
* @param ConditionalFormatValueObject[] $cfvos
89+
*/
90+
public function setCfvos(array $cfvos): self
91+
{
92+
$this->cfvos = $cfvos;
93+
94+
return $this;
95+
}
96+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
namespace PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting;
4+
5+
enum IconSetValues: string
6+
{
7+
case ThreeArrows = '3Arrows';
8+
case ThreeArrowsGray = '3ArrowsGray';
9+
case ThreeFlags = '3Flags';
10+
case ThreeTrafficLights1 = '3TrafficLights1';
11+
case ThreeTrafficLights2 = '3TrafficLights2';
12+
case ThreeSigns = '3Signs';
13+
case ThreeSymbols = '3Symbols';
14+
case ThreeSymbols2 = '3Symbols2';
15+
case FourArrows = '4Arrows';
16+
case FourArrowsGray = '4ArrowsGray';
17+
case FourRedToBlack = '4RedToBlack';
18+
case FourRating = '4Rating';
19+
case FourTrafficLights = '4TrafficLights';
20+
case FiveArrows = '5Arrows';
21+
case FiveArrowsGray = '5ArrowsGray';
22+
case FiveRating = '5Rating';
23+
case FiveQuarters = '5Quarters';
24+
// The following icon sets are not implemented yet:
25+
// case ThreeStars = "3Stars";
26+
// case ThreeTriangles = "3Triangles";
27+
// case FiveBoxes = "5Boxes";
28+
}

0 commit comments

Comments
 (0)