Allow Multiple Ranges

This commit is contained in:
oleibman
2024-12-29 08:42:07 -08:00
parent 222bf51cdf
commit f943e2d416
7 changed files with 103 additions and 51 deletions
@@ -37,26 +37,23 @@ class DataValidations
foreach ($this->worksheetXml->dataValidations->dataValidation as $dataValidation) {
// Uppercase coordinate
$range = strtoupper((string) $dataValidation['sqref']);
$rangeSet = explode(' ', $range);
foreach ($rangeSet as $range) {
$docValidation = new DataValidation();
$docValidation->setType((string) $dataValidation['type']);
$docValidation->setErrorStyle((string) $dataValidation['errorStyle']);
$docValidation->setOperator((string) $dataValidation['operator']);
$docValidation->setAllowBlank(filter_var($dataValidation['allowBlank'], FILTER_VALIDATE_BOOLEAN));
// showDropDown is inverted (works as hideDropDown if true)
$docValidation->setShowDropDown(!filter_var($dataValidation['showDropDown'], FILTER_VALIDATE_BOOLEAN));
$docValidation->setShowInputMessage(filter_var($dataValidation['showInputMessage'], FILTER_VALIDATE_BOOLEAN));
$docValidation->setShowErrorMessage(filter_var($dataValidation['showErrorMessage'], FILTER_VALIDATE_BOOLEAN));
$docValidation->setErrorTitle((string) $dataValidation['errorTitle']);
$docValidation->setError((string) $dataValidation['error']);
$docValidation->setPromptTitle((string) $dataValidation['promptTitle']);
$docValidation->setPrompt((string) $dataValidation['prompt']);
$docValidation->setFormula1(Xlsx::replacePrefixes((string) $dataValidation->formula1));
$docValidation->setFormula2(Xlsx::replacePrefixes((string) $dataValidation->formula2));
$docValidation->setSqref($range);
$this->worksheet->setDataValidation($range, $docValidation);
}
$docValidation = new DataValidation();
$docValidation->setType((string) $dataValidation['type']);
$docValidation->setErrorStyle((string) $dataValidation['errorStyle']);
$docValidation->setOperator((string) $dataValidation['operator']);
$docValidation->setAllowBlank(filter_var($dataValidation['allowBlank'], FILTER_VALIDATE_BOOLEAN));
// showDropDown is inverted (works as hideDropDown if true)
$docValidation->setShowDropDown(!filter_var($dataValidation['showDropDown'], FILTER_VALIDATE_BOOLEAN));
$docValidation->setShowInputMessage(filter_var($dataValidation['showInputMessage'], FILTER_VALIDATE_BOOLEAN));
$docValidation->setShowErrorMessage(filter_var($dataValidation['showErrorMessage'], FILTER_VALIDATE_BOOLEAN));
$docValidation->setErrorTitle((string) $dataValidation['errorTitle']);
$docValidation->setError((string) $dataValidation['error']);
$docValidation->setPromptTitle((string) $dataValidation['promptTitle']);
$docValidation->setPrompt((string) $dataValidation['prompt']);
$docValidation->setFormula1(Xlsx::replacePrefixes((string) $dataValidation->formula1));
$docValidation->setFormula2(Xlsx::replacePrefixes((string) $dataValidation->formula2));
$docValidation->setSqref($range);
$this->worksheet->setDataValidation($range, $docValidation);
}
}
}
+7 -1
View File
@@ -282,7 +282,13 @@ class ReferenceHelper
)
);
}
$newReference = $this->updateCellReference($cellAddress);
$addressParts = explode(' ', $cellAddress);
$newReference = '';
$separator = '';
foreach ($addressParts as $addressPart) {
$newReference .= $separator . $this->updateCellReference($addressPart);
$separator = ' ';
}
if ($cellAddress !== $newReference) {
$dataValidation->setSqref($newReference);
$worksheet->setDataValidation($newReference, $dataValidation);
+35 -12
View File
@@ -296,6 +296,7 @@ class Worksheet
/**
* Data validation objects. Indexed by cell coordinate, e.g. 'A1'.
* Index can include ranges, and multiple cells/ranges.
*/
private array $dataValidationCollection = [];
@@ -3261,23 +3262,30 @@ class Worksheet
*/
public function getDataValidation(string $cellCoordinate): DataValidation
{
// return data validation if we already have one
if (isset($this->dataValidationCollection[$cellCoordinate])) {
return $this->dataValidationCollection[$cellCoordinate];
}
foreach ($this->dataValidationCollection as $dataValidation) {
$sqref = $dataValidation->getSqref() ?? '';
if (str_contains($sqref, ':')) {
if (Coordinate::coordinateIsInsideRange($sqref, $cellCoordinate)) {
foreach ($this->dataValidationCollection as $key => $dataValidation) {
$keyParts = explode(' ', $key);
foreach ($keyParts as $keyPart) {
if ($keyPart === $cellCoordinate) {
return $dataValidation;
}
if (str_contains($keyPart, ':')) {
if (Coordinate::coordinateIsInsideRange($keyPart, $cellCoordinate)) {
return $dataValidation;
}
}
}
}
// else create data validation
$this->dataValidationCollection[$cellCoordinate] = new DataValidation();
$dataValidation = new DataValidation();
$dataValidation->setSqref($cellCoordinate);
$this->dataValidationCollection[$cellCoordinate] = $dataValidation;
return $this->dataValidationCollection[$cellCoordinate];
return $dataValidation;
}
/**
@@ -3308,12 +3316,17 @@ class Worksheet
if (isset($this->dataValidationCollection[$coordinate])) {
return true;
}
foreach ($this->dataValidationCollection as $dataValidation) {
$sqref = $dataValidation->getSqref() ?? '';
if (str_contains($sqref, ':')) {
if (Coordinate::coordinateIsInsideRange($sqref, $coordinate)) {
foreach ($this->dataValidationCollection as $key => $dataValidation) {
$keyParts = explode(' ', $key);
foreach ($keyParts as $keyPart) {
if ($keyPart === $coordinate) {
return true;
}
if (str_contains($keyPart, ':')) {
if (Coordinate::coordinateIsInsideRange($keyPart, $coordinate)) {
return true;
}
}
}
}
@@ -3327,7 +3340,17 @@ class Worksheet
*/
public function getDataValidationCollection(): array
{
return $this->dataValidationCollection;
$collectionCells = [];
$collectionRanges = [];
foreach ($this->dataValidationCollection as $key => $dataValidation) {
if (preg_match('/[: ]/', $key) === 1) {
$collectionRanges[$key] = $dataValidation;
} else {
$collectionCells[$key] = $dataValidation;
}
}
return array_merge($collectionCells, $collectionRanges);
}
/**
+8 -1
View File
@@ -2605,7 +2605,14 @@ class Worksheet extends BIFFwriter
private function writeDataValidity(): void
{
// Datavalidation collection
$dataValidationCollection = $this->phpSheet->getDataValidationCollection();
$dataValidationCollection1 = $this->phpSheet->getDataValidationCollection();
$dataValidationCollection = [];
foreach ($dataValidationCollection1 as $key => $dataValidation) {
$keyParts = explode(' ', $key);
foreach ($keyParts as $keyPart) {
$dataValidationCollection[$keyPart] = $dataValidation;
}
}
// Write data validations?
if (!empty($dataValidationCollection)) {
@@ -943,7 +943,6 @@ class Worksheet extends WriterPart
// Write data validations?
if (!empty($dataValidationCollection)) {
$dataValidationCollection = Coordinate::mergeRangesInCollection($dataValidationCollection);
$objWriter->startElement('dataValidations');
$objWriter->writeAttribute('count', (string) count($dataValidationCollection));
@@ -130,4 +130,38 @@ class ReferenceHelperDVTest extends TestCase
$validation->setPrompt('Please pick a value from the drop-down list.');
$validation->setFormula1('$A$5:$A$8');
}
public function testMultipleRanges(): void
{
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$sheet->getCell('B1')->setValue(1);
$sheet->getCell('B2')->setValue(2);
$sheet->getCell('B3')->setValue(3);
$dv = $sheet->getDataValidation('A1:A4 C5 D6:D7');
$dv->setType(DataValidation::TYPE_LIST)
->setShowDropDown(true)
->setFormula1('$B$1:$B$3')
->setErrorStyle(DataValidation::STYLE_STOP)
->setShowErrorMessage(true)
->setErrorTitle('Input Error')
->setError('Value is not a member of allowed list');
$sheet->insertNewColumnBefore('A');
$dvs = $sheet->getDataValidationCollection();
self::assertCount(1, $dvs);
$expected = 'B1:B4 D5 E6:E7';
self::assertSame([$expected], array_keys($dvs));
$dv = $dvs[$expected];
self::assertSame($expected, $dv->getSqref());
self::assertSame('$C$1:$C$3', $dv->getFormula1());
$sheet->getCell('B2')->setValue(3);
self::assertTrue($sheet->getCell('B2')->hasValidValue());
$sheet->getCell('D5')->setValue(7);
self::assertFalse($sheet->getCell('D5')->hasValidValue());
$sheet->getCell('E6')->setValue(7);
self::assertFalse($sheet->getCell('E6')->hasValidValue());
$sheet->getCell('E7')->setValue(1);
self::assertTrue($sheet->getCell('E7')->hasValidValue());
$spreadsheet->disconnectWorksheets();
}
}
@@ -46,14 +46,7 @@ class Issue2368Test extends AbstractFunctional
$spreadsheet = $reader->load($filename);
$sheet = $spreadsheet->getActiveSheet();
$validations = $sheet->getDataValidationCollection();
/** @var string[] */
$ranges = [];
foreach ($validations as $validation) {
$ranges[] = $validation->getSqref();
}
self::assertContains('A1:A5', $ranges);
self::assertContains('A10:A14', $ranges);
self::assertContains('A20:A24', $ranges);
self::assertSame(['A1:A5 A10:A14 A20:A24'], array_keys($validations));
self::assertSame('"yes,no"', $sheet->getCell('A3')->getDataValidation()->getFormula1());
self::assertSame('"yes,no"', $sheet->getCell('A10')->getDataValidation()->getFormula1());
self::assertSame('"yes,no"', $sheet->getCell('A24')->getDataValidation()->getFormula1());
@@ -63,14 +56,7 @@ class Issue2368Test extends AbstractFunctional
$sheet2 = $reloadedSpreadsheet->getActiveSheet();
$validation2 = $sheet2->getDataValidationCollection();
/** @var string[] */
$range2 = [];
foreach ($validation2 as $validation) {
$range2[] = $validation->getSqref();
}
self::assertContains('A1:A5', $range2);
self::assertContains('A10:A14', $range2);
self::assertContains('A20:A24', $range2);
self::assertSame(['A1:A5 A10:A14 A20:A24'], array_keys($validation2));
self::assertSame('"yes,no"', $sheet2->getCell('A3')->getDataValidation()->getFormula1());
self::assertSame('"yes,no"', $sheet2->getCell('A10')->getDataValidation()->getFormula1());
self::assertSame('"yes,no"', $sheet2->getCell('A24')->getDataValidation()->getFormula1());