Skip to content

Commit c8f5c62

Browse files
committed
Invert Union and Intersection Between Excel and Xml
I don't know why MS did this. We're stuck with it.
1 parent 33edddf commit c8f5c62

File tree

7 files changed

+68
-8
lines changed

7 files changed

+68
-8
lines changed

src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,9 @@ private function setConditionalStyles(Worksheet $worksheet, array $conditionals,
188188
$conditionalStyles = $this->readStyleRules($cfRules, $xmlExtLst);
189189

190190
// Extract all cell references in $cellRangeReference
191-
$cellRangeReference = str_replace('$', '', strtoupper($cellRangeReference));
191+
// N.B. In Excel UI, intersection is space and union is comma.
192+
// But in Xml, intersection is comma and union is space.
193+
$cellRangeReference = str_replace(['$', ' ', ',', '^'], ['', '^', ' ', ','], strtoupper($cellRangeReference));
192194
$worksheet->getStyle($cellRangeReference)->setConditionalStyles($conditionalStyles);
193195
}
194196
}

src/PhpSpreadsheet/Style/ConditionalFormatting/CellMatcher.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ public function __construct(Cell $cell, string $conditionalRange)
6060

6161
protected function setReferenceCellForExpressions(string $conditionalRange): void
6262
{
63-
$conditionalRange = str_replace(' ', ',', $conditionalRange);
6463
$conditionalRange = Coordinate::splitRange(str_replace('$', '', strtoupper($conditionalRange)));
6564
[$this->referenceCell] = $conditionalRange[0];
6665

src/PhpSpreadsheet/Worksheet/Worksheet.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1422,7 +1422,7 @@ public function getConditionalStyles(string $coordinate): array
14221422

14231423
$cell = $this->getCell($coordinate);
14241424
foreach (array_keys($this->conditionalStylesCollection) as $conditionalRange) {
1425-
$cellBlocks = explode(' ', $conditionalRange);
1425+
$cellBlocks = explode(',', $conditionalRange);
14261426
foreach ($cellBlocks as $cellBlock) {
14271427
if ($cell->isInRange($cellBlock)) {
14281428
return $this->conditionalStylesCollection[$conditionalRange];
@@ -1438,7 +1438,7 @@ public function getConditionalRange(string $coordinate): ?string
14381438
$coordinate = strtoupper($coordinate);
14391439
$cell = $this->getCell($coordinate);
14401440
foreach (array_keys($this->conditionalStylesCollection) as $conditionalRange) {
1441-
$cellBlocks = explode(' ', $conditionalRange);
1441+
$cellBlocks = explode(',', $conditionalRange);
14421442
foreach ($cellBlocks as $cellBlock) {
14431443
if ($cell->isInRange($cellBlock)) {
14441444
return $conditionalRange;
@@ -1507,7 +1507,7 @@ public function getConditionalStylesCollection(): array
15071507
*/
15081508
public function setConditionalStyles(string $coordinate, array $styles): static
15091509
{
1510-
$this->conditionalStylesCollection[trim(strtoupper($coordinate))] = $styles;
1510+
$this->conditionalStylesCollection[strtoupper($coordinate)] = $styles;
15111511

15121512
return $this;
15131513
}

src/PhpSpreadsheet/Writer/Xls/Worksheet.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -492,7 +492,13 @@ private function writeConditionalFormatting(): void
492492
{
493493
$conditionalFormulaHelper = new ConditionalHelper($this->parser);
494494

495-
$arrConditionalStyles = $this->phpSheet->getConditionalStylesCollection();
495+
$arrConditionalStyles = [];
496+
foreach ($this->phpSheet->getConditionalStylesCollection() as $key => $value) {
497+
$keyExplode = explode(',', $key);
498+
foreach ($keyExplode as $exploded) {
499+
$arrConditionalStyles[$exploded] = $value;
500+
}
501+
}
496502
if (!empty($arrConditionalStyles)) {
497503
// Write ConditionalFormattingTable records
498504
foreach ($arrConditionalStyles as $cellCoordinate => $conditionalStyles) {

src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -815,7 +815,9 @@ private function writeConditionalFormatting(XMLWriter $objWriter, Phpspreadsheet
815815
// Loop through styles in the current worksheet
816816
foreach ($worksheet->getConditionalStylesCollection() as $cellCoordinate => $conditionalStyles) {
817817
$objWriter->startElement('conditionalFormatting');
818-
$objWriter->writeAttribute('sqref', $cellCoordinate);
818+
// N.B. In Excel UI, intersection is space and union is comma.
819+
// But in Xml, intersection is comma and union is space.
820+
$objWriter->writeAttribute('sqref', str_replace(['$', ' ', ',', '^'], ['', '^', ' ', ','], $cellCoordinate));
819821

820822
foreach ($conditionalStyles as $conditional) {
821823
// WHY was this again?

tests/PhpSpreadsheetTests/Reader/Xlsx/Issue4039Test.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public function testSplitRange(): void
1616
$spreadsheet = $reader->load(self::$testbook);
1717
$sheet = $spreadsheet->getSheetByNameOrThrow('cellIs Expression');
1818
$expected = [
19-
'A12:D17 A20', // split range
19+
'A12:D17,A20', // split range
2020
'A22:D27',
2121
'A2:E6',
2222
];
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpOffice\PhpSpreadsheetTests\Writer\Xls;
6+
7+
use PhpOffice\PhpSpreadsheet\Spreadsheet;
8+
use PhpOffice\PhpSpreadsheet\Style\Conditional;
9+
use PhpOffice\PhpSpreadsheetTests\Functional\AbstractFunctional;
10+
11+
class ConditionalUnionTest extends AbstractFunctional
12+
{
13+
public function testConditionalUnion(): void
14+
{
15+
$spreadsheet = new Spreadsheet();
16+
$sheet = $spreadsheet->getActiveSheet();
17+
$sheet->fromArray([
18+
[1, 2, 3, 4, 5],
19+
[2, 3, 4, 5, 6],
20+
[3, 4, 5, 6, 7],
21+
]);
22+
$condition1 = new Conditional();
23+
$condition1->setConditionType(Conditional::CONDITION_CELLIS);
24+
$condition1->setOperatorType(Conditional::OPERATOR_BETWEEN);
25+
$condition1->setConditions([2, 4]);
26+
$condition1->getStyle()->getFont()
27+
->setBold(true);
28+
$conditionalStyles = [$condition1];
29+
$sheet->setConditionalStyles('A1:A3,C1:E3', $conditionalStyles);
30+
31+
$robj = $this->writeAndReload($spreadsheet, 'Xls');
32+
$spreadsheet->disconnectWorksheets();
33+
$sheet0 = $robj->getActiveSheet();
34+
$conditionals = $sheet0->getConditionalStylesCollection();
35+
self::assertSame(['A1:A3', 'C1:E3'], array_keys($conditionals));
36+
$cond1 = $conditionals['A1:A3'][0];
37+
self::assertSame(Conditional::CONDITION_CELLIS, $cond1->getConditionType());
38+
self::assertSame(Conditional::OPERATOR_BETWEEN, $cond1->getOperatorType());
39+
self::assertSame([2, 4], $cond1->getConditions());
40+
$font1 = $cond1->getStyle()->getFont();
41+
self::assertTrue($font1->getBold());
42+
43+
$cond2 = $conditionals['C1:E3'][0];
44+
self::assertSame(Conditional::CONDITION_CELLIS, $cond2->getConditionType());
45+
self::assertSame(Conditional::OPERATOR_BETWEEN, $cond2->getOperatorType());
46+
self::assertSame([2, 4], $cond2->getConditions());
47+
$font2 = $cond2->getStyle()->getFont();
48+
self::assertTrue($font2->getBold());
49+
$robj->disconnectWorksheets();
50+
}
51+
}

0 commit comments

Comments
 (0)