Evaluate NamedRange and ArrayFunction in DataValidator

Fix #4206.
This commit is contained in:
oleibman
2025-01-02 22:17:57 -08:00
parent 441abf05d5
commit fb29a7630f
3 changed files with 77 additions and 17 deletions
+16 -16
View File
@@ -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 @@ class DataValidator
// 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);
}
return $result !== ExcelError::NA();
} catch (Exception) {
return false;
}
}
$calculation = Calculation::getInstance($cell->getWorksheet()->getParent());
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;
@@ -0,0 +1,38 @@
<?php
declare(strict_types=1);
namespace PhpOffice\PhpSpreadsheetTests\Cell;
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
use PhpOffice\PhpSpreadsheet\Cell\DataValidation;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit\Framework\TestCase;
class DataValidator3Test extends TestCase
{
public function testArrayFunctionAsList(): 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);
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();
}
}
@@ -5,6 +5,7 @@ declare(strict_types=1);
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 @@ class DataValidatorTest extends TestCase
$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 @@ class DataValidatorTest extends TestCase
$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();
}
}