Skip to content

Commit fb29a76

Browse files
committed
Evaluate NamedRange and ArrayFunction in DataValidator
Fix #4206.
1 parent 441abf0 commit fb29a76

File tree

3 files changed

+75
-15
lines changed

3 files changed

+75
-15
lines changed

src/PhpSpreadsheet/Cell/DataValidator.php

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
namespace PhpOffice\PhpSpreadsheet\Cell;
44

55
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
6-
use PhpOffice\PhpSpreadsheet\Calculation\Information\ExcelError;
6+
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
77
use PhpOffice\PhpSpreadsheet\Exception;
88

99
/**
@@ -118,22 +118,22 @@ private function isValueInList(Cell $cell): bool
118118
// inline values list
119119
if ($formula1[0] === '"') {
120120
return in_array(strtolower($cellValueString), explode(',', strtolower(trim($formula1, '"'))), true);
121-
} elseif (strpos($formula1, ':') > 0) {
122-
// values list cells
123-
$matchFormula = '=MATCH(' . $cell->getCoordinate() . ', ' . $formula1 . ', 0)';
124-
$calculation = Calculation::getInstance($cell->getWorksheet()->getParent());
125-
126-
try {
127-
$result = $calculation->calculateFormula($matchFormula, $cell->getCoordinate(), $cell);
128-
while (is_array($result)) {
129-
$result = array_pop($result);
130-
}
121+
}
122+
$calculation = Calculation::getInstance($cell->getWorksheet()->getParent());
131123

132-
return $result !== ExcelError::NA();
133-
} catch (Exception) {
134-
return false;
124+
try {
125+
$result = $calculation->calculateFormula("=$formula1", $cell->getCoordinate(), $cell);
126+
$result = is_array($result) ? Functions::flattenArray($result) : [$result];
127+
foreach ($result as $oneResult) {
128+
if (is_scalar($oneResult) && strcasecmp((string) $oneResult, $cellValueString) === 0) {
129+
return true;
130+
}
135131
}
132+
} catch (Exception) {
133+
// do nothing
136134
}
135+
136+
return false;
137137
}
138138

139139
return true;
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpOffice\PhpSpreadsheetTests\Cell;
6+
7+
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
8+
use PhpOffice\PhpSpreadsheet\Cell\DataValidation;
9+
use PhpOffice\PhpSpreadsheet\Spreadsheet;
10+
use PHPUnit\Framework\TestCase;
11+
12+
class DataValidator3Test extends TestCase
13+
{
14+
public function testArrayFunctionAsList(): void
15+
{
16+
$spreadsheet = new Spreadsheet();
17+
$sheet = $spreadsheet->getActiveSheet();
18+
$sheet->getCell('A1')->setValue(1);
19+
$sheet->getCell('A2')->setValue(3);
20+
$sheet->getCell('A3')->setValue(5);
21+
$sheet->getCell('A4')->setValue(7);
22+
Calculation::getInstance($spreadsheet)
23+
->setInstanceArrayReturnType(
24+
Calculation::RETURN_ARRAY_AS_ARRAY
25+
);
26+
27+
$sheet->getCell('G1')->setValue('=UNIQUE(A1:A4)');
28+
$validation = $sheet->getCell('H4')->getDataValidation();
29+
$validation->setType(DataValidation::TYPE_LIST)
30+
->setFormula1('ANCHORARRAY(G1)');
31+
$sheet->getCell('H4')->setValue(2);
32+
self::assertFalse($sheet->getCell('H4')->hasValidValue());
33+
$sheet->getCell('H4')->setValue(3);
34+
self::assertTrue($sheet->getCell('H4')->hasValidValue());
35+
36+
$spreadsheet->disconnectWorksheets();
37+
}
38+
}

tests/PhpSpreadsheetTests/Cell/DataValidatorTest.php

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace PhpOffice\PhpSpreadsheetTests\Cell;
66

77
use PhpOffice\PhpSpreadsheet\Cell\DataValidation;
8+
use PhpOffice\PhpSpreadsheet\NamedRange;
89
use PhpOffice\PhpSpreadsheet\Spreadsheet;
910
use PHPUnit\Framework\TestCase;
1011

@@ -62,7 +63,7 @@ public function testList(): void
6263
$sheet->getCell('B2')->setValue(6);
6364
$sheet->getCell('B3')->setValue(7);
6465
$testCell = $sheet->getCell('A1'); // redefine $testCell, because it has broken coordinates after using other cells
65-
$validation->setFormula1('B1:B3');
66+
$validation->setFormula1('$B$1:$B$3');
6667
$testCell->setValue('10');
6768
self::assertFalse($testCell->hasValidValue(), "cell value ('10') is not allowed");
6869
$testCell = $sheet->getCell('A1'); // redefine $testCell, because it has broken coordinates after using other cells
@@ -93,4 +94,25 @@ public function testInvalidNumeric(): void
9394

9495
$spreadsheet->disconnectWorksheets();
9596
}
97+
98+
public function testDefinedNameAsList(): void
99+
{
100+
$spreadsheet = new Spreadsheet();
101+
$sheet = $spreadsheet->getActiveSheet();
102+
$sheet->getCell('A1')->setValue(1);
103+
$sheet->getCell('A2')->setValue(3);
104+
$sheet->getCell('A3')->setValue(5);
105+
$sheet->getCell('A4')->setValue(7);
106+
$spreadsheet->addNamedRange(new NamedRange('listvalues', $sheet, '$A$1:$A$4'));
107+
108+
$validation = $sheet->getCell('D4')->getDataValidation();
109+
$validation->setType(DataValidation::TYPE_LIST)
110+
->setFormula1('listvalues');
111+
$sheet->getCell('D4')->setValue(2);
112+
self::assertFalse($sheet->getCell('D4')->hasValidValue());
113+
$sheet->getCell('D4')->setValue(3);
114+
self::assertTrue($sheet->getCell('D4')->hasValidValue());
115+
116+
$spreadsheet->disconnectWorksheets();
117+
}
96118
}

0 commit comments

Comments
 (0)