Skip to content

Commit 44014f8

Browse files
authored
Merge pull request #4152 from oleibman/issue3185
Xls Writer Conditional Rules Applied to Whole Rows or Columns
2 parents 9c8a743 + 9498c03 commit 44014f8

File tree

3 files changed

+117
-3
lines changed

3 files changed

+117
-3
lines changed

src/PhpSpreadsheet/Writer/Xls/ConditionalHelper.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ public function processCondition(mixed $condition, string $cellRange): void
3030
$this->condition = $condition;
3131
$this->cellRange = $cellRange;
3232

33-
if (is_int($condition) || is_float($condition)) {
34-
$this->size = ($condition <= 65535 ? 3 : 0x0000);
33+
if (is_int($condition) && $condition >= 0 && $condition <= 65535) {
34+
$this->size = 3;
3535
$this->tokens = pack('Cv', 0x1E, $condition);
3636
} else {
3737
try {

src/PhpSpreadsheet/Writer/Xls/Worksheet.php

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,31 @@ public function close(): void
489489
$this->storeEof();
490490
}
491491

492+
public const MAX_XLS_COLUMN = 256;
493+
public const MAX_XLS_COLUMN_STRING = 'IV';
494+
public const MAX_XLS_ROW = 65536;
495+
496+
private static function limitRange(string $exploded): string
497+
{
498+
$retVal = '';
499+
$ranges = Coordinate::getRangeBoundaries($exploded);
500+
$firstCol = Coordinate::columnIndexFromString($ranges[0][0]);
501+
$firstRow = (int) $ranges[0][1];
502+
if ($firstCol <= self::MAX_XLS_COLUMN && $firstRow <= self::MAX_XLS_ROW) {
503+
$retVal = $exploded;
504+
if (str_contains($exploded, ':')) {
505+
$lastCol = Coordinate::columnIndexFromString($ranges[1][0]);
506+
$ranges[1][1] = min(self::MAX_XLS_ROW, (int) $ranges[1][1]);
507+
if ($lastCol > self::MAX_XLS_COLUMN) {
508+
$ranges[1][0] = self::MAX_XLS_COLUMN_STRING;
509+
}
510+
$retVal = "{$ranges[0][0]}{$ranges[0][1]}:{$ranges[1][0]}{$ranges[1][1]}";
511+
}
512+
}
513+
514+
return $retVal;
515+
}
516+
492517
private function writeConditionalFormatting(): void
493518
{
494519
$conditionalFormulaHelper = new ConditionalHelper($this->parser);
@@ -497,7 +522,10 @@ private function writeConditionalFormatting(): void
497522
foreach ($this->phpSheet->getConditionalStylesCollection() as $key => $value) {
498523
$keyExplode = explode(',', Coordinate::resolveUnionAndIntersection($key));
499524
foreach ($keyExplode as $exploded) {
500-
$arrConditionalStyles[$exploded] = $value;
525+
$range = self::limitRange($exploded);
526+
if ($range !== '') {
527+
$arrConditionalStyles[$range] = $value;
528+
}
501529
}
502530
}
503531
if (!empty($arrConditionalStyles)) {
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
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\Color;
9+
use PhpOffice\PhpSpreadsheet\Style\Conditional;
10+
use PhpOffice\PhpSpreadsheet\Style\Style;
11+
use PhpOffice\PhpSpreadsheetTests\Functional\AbstractFunctional;
12+
13+
class ConditionalLimitsTest extends AbstractFunctional
14+
{
15+
public function testLimits(): void
16+
{
17+
$spreadsheet = new Spreadsheet();
18+
$sheet = $spreadsheet->getActiveSheet();
19+
$sheet->fromArray(
20+
[
21+
['Cell', 0, null, null, 'Col Rng', -2, -1],
22+
[null, null, null, null, null, 0, 1],
23+
['Cell Rng', -2, -1, 0, null, 2, 3],
24+
[null, 1, 2, 3, null, 4, -1],
25+
[],
26+
['Row Rng'],
27+
[-2, -1, 0],
28+
[1, 2, 3],
29+
],
30+
strictNullComparison: true
31+
);
32+
$redStyle = new Style(false, true);
33+
$redStyle->getFont()->setColor(new Color(Color::COLOR_RED));
34+
35+
$condition1 = new Conditional();
36+
$condition1->setConditionType(Conditional::CONDITION_CELLIS)
37+
->setOperatorType(Conditional::OPERATOR_BETWEEN)
38+
->addCondition(-1)
39+
->addCondition(1)
40+
->setStyle($redStyle);
41+
$conditionalStyles = [$condition1];
42+
$cellRange = 'B1';
43+
$sheet->getStyle($cellRange)->setConditionalStyles($conditionalStyles);
44+
45+
$condition2 = new Conditional();
46+
$condition2->setConditionType(Conditional::CONDITION_CELLIS)
47+
->setOperatorType(Conditional::OPERATOR_BETWEEN)
48+
->addCondition(-1.5)
49+
->addCondition(1.5)
50+
->setStyle($redStyle);
51+
$conditionalStyles = [$condition2];
52+
$cellRange = 'F:G';
53+
$sheet->getStyle($cellRange)->setConditionalStyles($conditionalStyles);
54+
55+
$condition3 = new Conditional();
56+
$condition3->setConditionType(Conditional::CONDITION_CELLIS)
57+
->setOperatorType(Conditional::OPERATOR_BETWEEN)
58+
->addCondition(-1)
59+
->addCondition(70000)
60+
->setStyle($redStyle);
61+
$conditionalStyles = [$condition3];
62+
$cellRange = '7:8';
63+
$sheet->getStyle($cellRange)->setConditionalStyles($conditionalStyles);
64+
65+
$cellRange = 'B3:D4';
66+
$sheet->getStyle($cellRange)->setConditionalStyles($conditionalStyles);
67+
$sheet->setSelectedCells('A1');
68+
$keys = array_keys($sheet->getConditionalStylesCollection());
69+
self::assertSame(['B1', 'F1:G1048576', 'A7:XFD8', 'B3:D4'], $keys);
70+
71+
$robj = $this->writeAndReload($spreadsheet, 'Xls');
72+
$spreadsheet->disconnectWorksheets();
73+
$sheet0 = $robj->getActiveSheet();
74+
$conditionals = $sheet0->getConditionalStylesCollection();
75+
self::assertSame(['B1', 'F1:G65536', 'A7:IV8', 'B3:D4'], array_keys($conditionals));
76+
$b1 = $conditionals['B1'][0];
77+
self::assertSame([-1, 1], $b1->getConditions());
78+
$b1 = $conditionals['F1:G65536'][0];
79+
self::assertSame([-1.5, 1.5], $b1->getConditions());
80+
$b1 = $conditionals['A7:IV8'][0];
81+
self::assertSame([-1, 70000], $b1->getConditions());
82+
$b1 = $conditionals['B3:D4'][0];
83+
self::assertSame([-1, 70000], $b1->getConditions());
84+
$robj->disconnectWorksheets();
85+
}
86+
}

0 commit comments

Comments
 (0)