From fb29a7630fc94c480ed7abafd8dce064b3b91be6 Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Thu, 2 Jan 2025 22:17:57 -0800 Subject: [PATCH] Evaluate NamedRange and ArrayFunction in DataValidator Fix #4206. --- src/PhpSpreadsheet/Cell/DataValidator.php | 28 +++++++------- .../Cell/DataValidator3Test.php | 38 +++++++++++++++++++ .../Cell/DataValidatorTest.php | 24 +++++++++++- 3 files changed, 75 insertions(+), 15 deletions(-) create mode 100644 tests/PhpSpreadsheetTests/Cell/DataValidator3Test.php diff --git a/src/PhpSpreadsheet/Cell/DataValidator.php b/src/PhpSpreadsheet/Cell/DataValidator.php index 8d1b904f6a..dcee049351 100644 --- a/src/PhpSpreadsheet/Cell/DataValidator.php +++ b/src/PhpSpreadsheet/Cell/DataValidator.php @@ -3,7 +3,7 @@ namespace PhpOffice\PhpSpreadsheet\Cell; use PhpOffice\PhpSpreadsheet\Calculation\Calculation; -use PhpOffice\PhpSpreadsheet\Calculation\Information\ExcelError; +use PhpOffice\PhpSpreadsheet\Calculation\Functions; use PhpOffice\PhpSpreadsheet\Exception; /** @@ -118,22 +118,22 @@ private function isValueInList(Cell $cell): bool // inline values list if ($formula1[0] === '"') { return in_array(strtolower($cellValueString), explode(',', strtolower(trim($formula1, '"'))), true); - } elseif (strpos($formula1, ':') > 0) { - // values list cells - $matchFormula = '=MATCH(' . $cell->getCoordinate() . ', ' . $formula1 . ', 0)'; - $calculation = Calculation::getInstance($cell->getWorksheet()->getParent()); - - try { - $result = $calculation->calculateFormula($matchFormula, $cell->getCoordinate(), $cell); - while (is_array($result)) { - $result = array_pop($result); - } + } + $calculation = Calculation::getInstance($cell->getWorksheet()->getParent()); - return $result !== ExcelError::NA(); - } catch (Exception) { - return false; + try { + $result = $calculation->calculateFormula("=$formula1", $cell->getCoordinate(), $cell); + $result = is_array($result) ? Functions::flattenArray($result) : [$result]; + foreach ($result as $oneResult) { + if (is_scalar($oneResult) && strcasecmp((string) $oneResult, $cellValueString) === 0) { + return true; + } } + } catch (Exception) { + // do nothing } + + return false; } return true; diff --git a/tests/PhpSpreadsheetTests/Cell/DataValidator3Test.php b/tests/PhpSpreadsheetTests/Cell/DataValidator3Test.php new file mode 100644 index 0000000000..6bb376c57c --- /dev/null +++ b/tests/PhpSpreadsheetTests/Cell/DataValidator3Test.php @@ -0,0 +1,38 @@ +getActiveSheet(); + $sheet->getCell('A1')->setValue(1); + $sheet->getCell('A2')->setValue(3); + $sheet->getCell('A3')->setValue(5); + $sheet->getCell('A4')->setValue(7); + Calculation::getInstance($spreadsheet) + ->setInstanceArrayReturnType( + Calculation::RETURN_ARRAY_AS_ARRAY + ); + + $sheet->getCell('G1')->setValue('=UNIQUE(A1:A4)'); + $validation = $sheet->getCell('H4')->getDataValidation(); + $validation->setType(DataValidation::TYPE_LIST) + ->setFormula1('ANCHORARRAY(G1)'); + $sheet->getCell('H4')->setValue(2); + self::assertFalse($sheet->getCell('H4')->hasValidValue()); + $sheet->getCell('H4')->setValue(3); + self::assertTrue($sheet->getCell('H4')->hasValidValue()); + + $spreadsheet->disconnectWorksheets(); + } +} diff --git a/tests/PhpSpreadsheetTests/Cell/DataValidatorTest.php b/tests/PhpSpreadsheetTests/Cell/DataValidatorTest.php index 680ce8e5e5..b58870ef3e 100644 --- a/tests/PhpSpreadsheetTests/Cell/DataValidatorTest.php +++ b/tests/PhpSpreadsheetTests/Cell/DataValidatorTest.php @@ -5,6 +5,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Cell; use PhpOffice\PhpSpreadsheet\Cell\DataValidation; +use PhpOffice\PhpSpreadsheet\NamedRange; use PhpOffice\PhpSpreadsheet\Spreadsheet; use PHPUnit\Framework\TestCase; @@ -62,7 +63,7 @@ public function testList(): void $sheet->getCell('B2')->setValue(6); $sheet->getCell('B3')->setValue(7); $testCell = $sheet->getCell('A1'); // redefine $testCell, because it has broken coordinates after using other cells - $validation->setFormula1('B1:B3'); + $validation->setFormula1('$B$1:$B$3'); $testCell->setValue('10'); self::assertFalse($testCell->hasValidValue(), "cell value ('10') is not allowed"); $testCell = $sheet->getCell('A1'); // redefine $testCell, because it has broken coordinates after using other cells @@ -93,4 +94,25 @@ public function testInvalidNumeric(): void $spreadsheet->disconnectWorksheets(); } + + public function testDefinedNameAsList(): void + { + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->getCell('A1')->setValue(1); + $sheet->getCell('A2')->setValue(3); + $sheet->getCell('A3')->setValue(5); + $sheet->getCell('A4')->setValue(7); + $spreadsheet->addNamedRange(new NamedRange('listvalues', $sheet, '$A$1:$A$4')); + + $validation = $sheet->getCell('D4')->getDataValidation(); + $validation->setType(DataValidation::TYPE_LIST) + ->setFormula1('listvalues'); + $sheet->getCell('D4')->setValue(2); + self::assertFalse($sheet->getCell('D4')->hasValidValue()); + $sheet->getCell('D4')->setValue(3); + self::assertTrue($sheet->getCell('D4')->hasValidValue()); + + $spreadsheet->disconnectWorksheets(); + } }