Merge data-validation collections to reduce the final file size
Closes #131 Closes #193
This commit is contained in:
parent
004a192922
commit
2761773b3d
|
@ -10,6 +10,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
- Merge data-validations to reduce written worksheet size - @billblume [#131](https://github.com/PHPOffice/PhpSpreadSheet/issues/131)
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -948,6 +948,86 @@ class Cell
|
||||||
return array_values($sortKeys);
|
return array_values($sortKeys);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert an associative array of single cell coordinates to values to an associative array
|
||||||
|
* of cell ranges to values. Only adjacent cell coordinates with the same
|
||||||
|
* value will be merged. If the value is an object, it must implement the method getHashCode().
|
||||||
|
*
|
||||||
|
* For example, this function converts:
|
||||||
|
*
|
||||||
|
* [ 'A1' => 'x', 'A2' => 'x', 'A3' => 'x', 'A4' => 'y' ]
|
||||||
|
*
|
||||||
|
* to:
|
||||||
|
*
|
||||||
|
* [ 'A1:A3' => 'x', 'A4' => 'y' ]
|
||||||
|
*
|
||||||
|
* @param array $pCoordCollection associative array mapping coordinates to values
|
||||||
|
*
|
||||||
|
* @return array associative array mapping coordinate ranges to valuea
|
||||||
|
*/
|
||||||
|
public static function mergeRangesInCollection(array $pCoordCollection)
|
||||||
|
{
|
||||||
|
$hashedValues = [];
|
||||||
|
|
||||||
|
foreach ($pCoordCollection as $coord => $value) {
|
||||||
|
list($column, $row) = self::coordinateFromString($coord);
|
||||||
|
$row = (int) (ltrim($row, '$'));
|
||||||
|
$hashCode = $column . '-' . (is_object($value) ? $value->getHashCode() : $value);
|
||||||
|
|
||||||
|
if (!isset($hashedValues[$hashCode])) {
|
||||||
|
$hashedValues[$hashCode] = (object) [
|
||||||
|
'value' => $value,
|
||||||
|
'col' => $column,
|
||||||
|
'rows' => [$row],
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
$hashedValues[$hashCode]->rows[] = $row;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$mergedCoordCollection = [];
|
||||||
|
ksort($hashedValues);
|
||||||
|
|
||||||
|
foreach ($hashedValues as $hashedValue) {
|
||||||
|
sort($hashedValue->rows);
|
||||||
|
$rowStart = null;
|
||||||
|
$rowEnd = null;
|
||||||
|
$ranges = [];
|
||||||
|
|
||||||
|
foreach ($hashedValue->rows as $row) {
|
||||||
|
if ($rowStart === null) {
|
||||||
|
$rowStart = $row;
|
||||||
|
$rowEnd = $row;
|
||||||
|
} elseif ($rowEnd === $row - 1) {
|
||||||
|
$rowEnd = $row;
|
||||||
|
} else {
|
||||||
|
if ($rowStart == $rowEnd) {
|
||||||
|
$ranges[] = $hashedValue->col . $rowStart;
|
||||||
|
} else {
|
||||||
|
$ranges[] = $hashedValue->col . $rowStart . ':' . $hashedValue->col . $rowEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
$rowStart = $row;
|
||||||
|
$rowEnd = $row;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($rowStart !== null) {
|
||||||
|
if ($rowStart == $rowEnd) {
|
||||||
|
$ranges[] = $hashedValue->col . $rowStart;
|
||||||
|
} else {
|
||||||
|
$ranges[] = $hashedValue->col . $rowStart . ':' . $hashedValue->col . $rowEnd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($ranges as $range) {
|
||||||
|
$mergedCoordCollection[$range] = $hashedValue->value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $mergedCoordCollection;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compare 2 cells.
|
* Compare 2 cells.
|
||||||
*
|
*
|
||||||
|
|
|
@ -565,6 +565,7 @@ class Worksheet extends WriterPart
|
||||||
|
|
||||||
// Write data validations?
|
// Write data validations?
|
||||||
if (!empty($dataValidationCollection)) {
|
if (!empty($dataValidationCollection)) {
|
||||||
|
$dataValidationCollection = Cell::mergeRangesInCollection($dataValidationCollection);
|
||||||
$objWriter->startElement('dataValidations');
|
$objWriter->startElement('dataValidations');
|
||||||
$objWriter->writeAttribute('count', count($dataValidationCollection));
|
$objWriter->writeAttribute('count', count($dataValidationCollection));
|
||||||
|
|
||||||
|
|
|
@ -300,4 +300,20 @@ class CellTest extends PHPUnit_Framework_TestCase
|
||||||
{
|
{
|
||||||
return require 'data/CellExtractAllCellReferencesInRange.php';
|
return require 'data/CellExtractAllCellReferencesInRange.php';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider providerMergeRangesInCollection
|
||||||
|
*
|
||||||
|
* @param mixed $expectedResult
|
||||||
|
*/
|
||||||
|
public function testMergeRangesInCollection($expectedResult, ...$args)
|
||||||
|
{
|
||||||
|
$result = Cell::mergeRangesInCollection(...$args);
|
||||||
|
$this->assertEquals($expectedResult, $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function providerMergeRangesInCollection()
|
||||||
|
{
|
||||||
|
return require 'data/CellMergeRangesInCollection.php';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
[
|
||||||
|
'A1:A3' => 'x',
|
||||||
|
'A4' => 'y',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'A1' => 'x',
|
||||||
|
'A2' => 'x',
|
||||||
|
'A3' => 'x',
|
||||||
|
'A4' => 'y',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[
|
||||||
|
'A1:A4' => 'x',
|
||||||
|
'A6:A7' => 'x',
|
||||||
|
'A9' => 'x',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'A7' => 'x',
|
||||||
|
'A1' => 'x',
|
||||||
|
'A4' => 'x',
|
||||||
|
'A6' => 'x',
|
||||||
|
'A2' => 'x',
|
||||||
|
'A9' => 'x',
|
||||||
|
'A3' => 'x',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[
|
||||||
|
'A1:A3' => 'x',
|
||||||
|
'B1:B3' => 'x',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'A1' => 'x',
|
||||||
|
'B3' => 'x',
|
||||||
|
'A2' => 'x',
|
||||||
|
'B2' => 'x',
|
||||||
|
'A3' => 'x',
|
||||||
|
'B1' => 'x',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[
|
||||||
|
'A1' => 'x',
|
||||||
|
'A2' => 'y',
|
||||||
|
'A3' => 'z',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'A1' => 'x',
|
||||||
|
'A2' => 'y',
|
||||||
|
'A3' => 'z',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
Loading…
Reference in New Issue