Skip to content

Commit

Permalink
Fix for issue PHPOffice#131, merge data-validation collections togeth…
Browse files Browse the repository at this point in the history
…er to reduce the size of outputted worksheet.
  • Loading branch information
billblume committed Jul 31, 2017
1 parent 0b03571 commit b458d41
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 0 deletions.
80 changes: 80 additions & 0 deletions src/PhpSpreadsheet/Cell.php
Original file line number Diff line number Diff line change
Expand Up @@ -948,6 +948,86 @@ public static function extractAllCellReferencesInRange($pRange)
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.
*
Expand Down
1 change: 1 addition & 0 deletions src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,7 @@ private function writeDataValidations(XMLWriter $objWriter, PhpspreadsheetWorksh

// Write data validations?
if (!empty($dataValidationCollection)) {
$dataValidationCollection = Cell::mergeRangesInCollection($dataValidationCollection);
$objWriter->startElement('dataValidations');
$objWriter->writeAttribute('count', count($dataValidationCollection));

Expand Down
16 changes: 16 additions & 0 deletions tests/PhpSpreadsheetTests/CellTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -300,4 +300,20 @@ public function providerExtractAllCellReferencesInRange()
{
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';
}
}
58 changes: 58 additions & 0 deletions tests/data/CellMergeRangesInCollection.php
Original file line number Diff line number Diff line change
@@ -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',
],
],
];

0 comments on commit b458d41

Please sign in to comment.