Skip to content

Commit 004de10

Browse files
author
Mark Baker
authored
Merge pull request #2673 from PHPOffice/Resolve-CF-Issues-with-Xls-Writer
Resolve Conditional Formatting issues with Xls writer
2 parents 2cdffeb + 7101da8 commit 004de10

File tree

11 files changed

+214
-66
lines changed

11 files changed

+214
-66
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ and this project adheres to [Semantic Versioning](https://semver.org).
3939

4040
### Fixed
4141

42+
- Fix bug in Conditional Formatting in the Xls Writer that resulted in a broken file when there were multiple conditional ranges in a worksheet.
43+
- Fix Conditional Formatting in the Xls Writer to work with rules that contain string literals, cell references and formulae.
4244
- Fix for setting Active Sheet to the first loaded worksheet when bookViews element isn't defined [Issue #2666](https://github.com/PHPOffice/PhpSpreadsheet/issues/2666) [PR #2669](https://github.com/PHPOffice/PhpSpreadsheet/pull/2669)
4345
- Fixed behaviour of XLSX font style vertical align settings.
4446
- Resolved formula translations to handle separators (row and column) for array functions as well as for function argument separators; and cleanly handle nesting levels.

samples/ConditionalFormatting/01_Basic_Comparisons.php

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@
3030
->setCellValue('A1', 'Literal Value Comparison')
3131
->setCellValue('A9', 'Value Comparison with Absolute Cell Reference $H$9')
3232
->setCellValue('A17', 'Value Comparison with Relative Cell References')
33-
->setCellValue('A23', 'Value Comparison with Formula based on AVERAGE() ± STDEV()');
33+
->setCellValue('A23', 'Value Comparison with Formula based on AVERAGE() ± STDEV()')
34+
->setCellValue('A30', 'Literal String Value Comparison');
3435

3536
$dataArray = [
3637
[-2, -1, 0, 1, 2],
@@ -45,11 +46,18 @@
4546
[4, 3, 8],
4647
];
4748

49+
$stringArray = [
50+
['I'],
51+
['Love'],
52+
['PHP'],
53+
];
54+
4855
$spreadsheet->getActiveSheet()
4956
->fromArray($dataArray, null, 'A2', true)
5057
->fromArray($dataArray, null, 'A10', true)
5158
->fromArray($betweenDataArray, null, 'A18', true)
5259
->fromArray($dataArray, null, 'A24', true)
60+
->fromArray($stringArray, null, 'A31', true)
5361
->setCellValue('H9', 1);
5462

5563
// Set title row bold
@@ -58,21 +66,31 @@
5866
$spreadsheet->getActiveSheet()->getStyle('A9:E9')->getFont()->setBold(true);
5967
$spreadsheet->getActiveSheet()->getStyle('A17:E17')->getFont()->setBold(true);
6068
$spreadsheet->getActiveSheet()->getStyle('A23:E23')->getFont()->setBold(true);
69+
$spreadsheet->getActiveSheet()->getStyle('A30:E30')->getFont()->setBold(true);
6170

6271
// Define some styles for our Conditionals
6372
$helper->log('Define some styles for our Conditionals');
6473
$yellowStyle = new Style(false, true);
6574
$yellowStyle->getFill()
6675
->setFillType(Fill::FILL_SOLID)
76+
->getStartColor()->setARGB(Color::COLOR_YELLOW);
77+
$yellowStyle->getFill()
6778
->getEndColor()->setARGB(Color::COLOR_YELLOW);
79+
$yellowStyle->getFont()->setColor(new Color(Color::COLOR_BLUE));
6880
$greenStyle = new Style(false, true);
6981
$greenStyle->getFill()
7082
->setFillType(Fill::FILL_SOLID)
83+
->getStartColor()->setARGB(Color::COLOR_GREEN);
84+
$greenStyle->getFill()
7185
->getEndColor()->setARGB(Color::COLOR_GREEN);
86+
$greenStyle->getFont()->setColor(new Color(Color::COLOR_DARKRED));
7287
$redStyle = new Style(false, true);
7388
$redStyle->getFill()
7489
->setFillType(Fill::FILL_SOLID)
90+
->getStartColor()->setARGB(Color::COLOR_RED);
91+
$redStyle->getFill()
7592
->getEndColor()->setARGB(Color::COLOR_RED);
93+
$redStyle->getFont()->setColor(new Color(Color::COLOR_GREEN));
7694

7795
// Set conditional formatting rules and styles
7896
$helper->log('Define conditional formatting and set styles');
@@ -166,6 +184,32 @@
166184
->setStyle($redStyle);
167185
$conditionalStyles[] = $cellWizard->getConditional();
168186

187+
$spreadsheet->getActiveSheet()
188+
->getStyle($cellWizard->getCellRange())
189+
->setConditionalStyles($conditionalStyles);
190+
191+
// Set rules for Value Comparison with String Literal
192+
$cellRange = 'A31:A33';
193+
$formulaRange = implode(
194+
':',
195+
array_map(
196+
[Coordinate::class, 'absoluteCoordinate'],
197+
Coordinate::splitRange($cellRange)[0]
198+
)
199+
);
200+
$conditionalStyles = [];
201+
$wizardFactory = new Wizard($cellRange);
202+
/** @var Wizard\CellValue $cellWizard */
203+
$cellWizard = $wizardFactory->newRule(Wizard::CELL_VALUE);
204+
205+
$cellWizard->equals('LOVE')
206+
->setStyle($redStyle);
207+
$conditionalStyles[] = $cellWizard->getConditional();
208+
209+
$cellWizard->equals('PHP')
210+
->setStyle($greenStyle);
211+
$conditionalStyles[] = $cellWizard->getConditional();
212+
169213
$spreadsheet->getActiveSheet()
170214
->getStyle($cellWizard->getCellRange())
171215
->setConditionalStyles($conditionalStyles);

samples/ConditionalFormatting/02_Text_Comparisons.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,14 +74,17 @@
7474
$yellowStyle->getFill()
7575
->setFillType(Fill::FILL_SOLID)
7676
->getEndColor()->setARGB(Color::COLOR_YELLOW);
77+
$yellowStyle->getFont()->setColor(new Color(Color::COLOR_BLUE));
7778
$greenStyle = new Style(false, true);
7879
$greenStyle->getFill()
7980
->setFillType(Fill::FILL_SOLID)
8081
->getEndColor()->setARGB(Color::COLOR_GREEN);
82+
$greenStyle->getFont()->setColor(new Color(Color::COLOR_DARKRED));
8183
$redStyle = new Style(false, true);
8284
$redStyle->getFill()
8385
->setFillType(Fill::FILL_SOLID)
8486
->getEndColor()->setARGB(Color::COLOR_RED);
87+
$redStyle->getFont()->setColor(new Color(Color::COLOR_GREEN));
8588

8689
// Set conditional formatting rules and styles
8790
$helper->log('Define conditional formatting and set styles');

samples/ConditionalFormatting/03_Blank_Comparisons.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,12 @@
4646
$greenStyle->getFill()
4747
->setFillType(Fill::FILL_SOLID)
4848
->getEndColor()->setARGB(Color::COLOR_GREEN);
49+
$greenStyle->getFont()->setColor(new Color(Color::COLOR_DARKRED));
4950
$redStyle = new Style(false, true);
5051
$redStyle->getFill()
5152
->setFillType(Fill::FILL_SOLID)
5253
->getEndColor()->setARGB(Color::COLOR_RED);
54+
$redStyle->getFont()->setColor(new Color(Color::COLOR_GREEN));
5355

5456
// Set conditional formatting rules and styles
5557
$helper->log('Define conditional formatting and set styles');

samples/ConditionalFormatting/04_Error_Comparisons.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,12 @@
4949
$greenStyle->getFill()
5050
->setFillType(Fill::FILL_SOLID)
5151
->getEndColor()->setARGB(Color::COLOR_GREEN);
52+
$greenStyle->getFont()->setColor(new Color(Color::COLOR_DARKRED));
5253
$redStyle = new Style(false, true);
5354
$redStyle->getFill()
5455
->setFillType(Fill::FILL_SOLID)
5556
->getEndColor()->setARGB(Color::COLOR_RED);
57+
$redStyle->getFont()->setColor(new Color(Color::COLOR_GREEN));
5658

5759
// Set conditional formatting rules and styles
5860
$helper->log('Define conditional formatting and set styles');

samples/ConditionalFormatting/05_Date_Comparisons.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,12 +108,11 @@
108108

109109
// Define some styles for our Conditionals
110110
$helper->log('Define some styles for our Conditionals');
111-
112111
$yellowStyle = new Style(false, true);
113112
$yellowStyle->getFill()
114113
->setFillType(Fill::FILL_SOLID)
115114
->getEndColor()->setARGB(Color::COLOR_YELLOW);
116-
$yellowStyle->getNumberFormat()->setFormatCode('ddd dd-mmm-yyyy');
115+
$yellowStyle->getFont()->setColor(new Color(Color::COLOR_BLUE));
117116

118117
// Set conditional formatting rules and styles
119118
$helper->log('Define conditional formatting and set styles');

samples/ConditionalFormatting/06_Duplicate_Comparisons.php

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,16 @@
5151

5252
// Define some styles for our Conditionals
5353
$helper->log('Define some styles for our Conditionals');
54-
$greenStyle = new Style(false, true);
55-
$greenStyle->getFill()
56-
->setFillType(Fill::FILL_SOLID)
57-
->getEndColor()->setARGB(Color::COLOR_GREEN);
5854
$yellowStyle = new Style(false, true);
5955
$yellowStyle->getFill()
6056
->setFillType(Fill::FILL_SOLID)
6157
->getEndColor()->setARGB(Color::COLOR_YELLOW);
58+
$yellowStyle->getFont()->setColor(new Color(Color::COLOR_BLUE));
59+
$greenStyle = new Style(false, true);
60+
$greenStyle->getFill()
61+
->setFillType(Fill::FILL_SOLID)
62+
->getEndColor()->setARGB(Color::COLOR_GREEN);
63+
$greenStyle->getFont()->setColor(new Color(Color::COLOR_DARKRED));
6264

6365
// Set conditional formatting rules and styles
6466
$helper->log('Define conditional formatting and set styles');

samples/ConditionalFormatting/07_Expression_Comparisons.php

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
$spreadsheet->setActiveSheetIndex(0);
2929
$spreadsheet->getActiveSheet()
3030
->setCellValue('A1', 'Odd/Even Expression Comparison')
31+
->setCellValue('A4', 'Note that these functions are not available for Xls files')
3132
->setCellValue('A15', 'Sales Grid Expression Comparison')
3233
->setCellValue('A25', 'Sales Grid Multiple Expression Comparison');
3334

@@ -69,14 +70,16 @@
6970

7071
// Define some styles for our Conditionals
7172
$helper->log('Define some styles for our Conditionals');
72-
$greenStyle = new Style(false, true);
73-
$greenStyle->getFill()
74-
->setFillType(Fill::FILL_SOLID)
75-
->getEndColor()->setARGB(Color::COLOR_GREEN);
7673
$yellowStyle = new Style(false, true);
7774
$yellowStyle->getFill()
7875
->setFillType(Fill::FILL_SOLID)
7976
->getEndColor()->setARGB(Color::COLOR_YELLOW);
77+
$yellowStyle->getFont()->setColor(new Color(Color::COLOR_BLUE));
78+
$greenStyle = new Style(false, true);
79+
$greenStyle->getFill()
80+
->setFillType(Fill::FILL_SOLID)
81+
->getEndColor()->setARGB(Color::COLOR_GREEN);
82+
$greenStyle->getFont()->setColor(new Color(Color::COLOR_DARKRED));
8083

8184
$greenStyleMoney = clone $greenStyle;
8285
$greenStyleMoney->getNumberFormat()->setFormatCode(NumberFormat::FORMAT_ACCOUNTING_USD);

src/PhpSpreadsheet/Style/ConditionalFormatting/Wizard/WizardAbstract.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ protected static function reverseCellAdjustment(array $matches, int $referenceCo
122122
return "{$worksheet}{$column}{$row}";
123123
}
124124

125-
protected static function reverseAdjustCellRef(string $condition, string $cellRange): string
125+
public static function reverseAdjustCellRef(string $condition, string $cellRange): string
126126
{
127127
$conditionalRange = Coordinate::splitRange(str_replace('$', '', strtoupper($cellRange)));
128128
[$referenceCell] = $conditionalRange[0];
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
<?php
2+
3+
namespace PhpOffice\PhpSpreadsheet\Writer\Xls;
4+
5+
use PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException;
6+
use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\Wizard;
7+
8+
class ConditionalHelper
9+
{
10+
/**
11+
* Formula parser.
12+
*
13+
* @var Parser
14+
*/
15+
protected $parser;
16+
17+
/**
18+
* @var mixed
19+
*/
20+
protected $condition;
21+
22+
/**
23+
* @var string
24+
*/
25+
protected $cellRange;
26+
27+
/**
28+
* @var null|string
29+
*/
30+
protected $tokens;
31+
32+
/**
33+
* @var int
34+
*/
35+
protected $size;
36+
37+
public function __construct(Parser $parser)
38+
{
39+
$this->parser = $parser;
40+
}
41+
42+
/**
43+
* @param mixed $condition
44+
*/
45+
public function processCondition($condition, string $cellRange): void
46+
{
47+
$this->condition = $condition;
48+
$this->cellRange = $cellRange;
49+
50+
if (is_int($condition) || is_float($condition)) {
51+
$this->size = ($condition <= 65535 ? 3 : 0x0000);
52+
$this->tokens = pack('Cv', 0x1E, $condition);
53+
} else {
54+
try {
55+
$formula = Wizard\WizardAbstract::reverseAdjustCellRef((string) $condition, $cellRange);
56+
$this->parser->parse($formula);
57+
$this->tokens = $this->parser->toReversePolish();
58+
$this->size = strlen($this->tokens ?? '');
59+
} catch (PhpSpreadsheetException $e) {
60+
// In the event of a parser error with a formula value, we set the expression to ptgInt + 0
61+
$this->tokens = pack('Cv', 0x1E, 0);
62+
$this->size = 3;
63+
}
64+
}
65+
}
66+
67+
public function tokens(): ?string
68+
{
69+
return $this->tokens;
70+
}
71+
72+
public function size(): int
73+
{
74+
return $this->size;
75+
}
76+
}

0 commit comments

Comments
 (0)