Bugfix/remove column out of range (#1197)

* Call garbage collector after removing a column

Otherwise callers of getHighestColumn get stale values

* Update changelog

* Fix remove a column out of range removes the last column

Given:
+---+---+
| A | B |
+---+---+
Attempting to remove 'D', should not alter the worksheet

* Avoid side effects when trying to remove more columns than exists
This commit is contained in:
David Arenas 2019-10-28 17:52:06 +00:00 committed by Mark Baker
parent b82afe37dc
commit 89066d2568
3 changed files with 54 additions and 12 deletions

View File

@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org).
### Fixed ### Fixed
- Call garbage collector after removing a column to prevent stale cached values - Call garbage collector after removing a column to prevent stale cached values
- Trying to remove a column that doesn't exist deletes the latest column
## [1.9.0] - 2019-08-17 ## [1.9.0] - 2019-08-17

View File

@ -2145,19 +2145,30 @@ class Worksheet implements IComparable
*/ */
public function removeColumn($pColumn, $pNumCols = 1) public function removeColumn($pColumn, $pNumCols = 1)
{ {
if (!is_numeric($pColumn)) { if (is_numeric($pColumn)) {
throw new Exception('Column references should not be numeric.');
}
$highestColumn = $this->getHighestDataColumn(); $highestColumn = $this->getHighestDataColumn();
$pColumn = Coordinate::stringFromColumnIndex(Coordinate::columnIndexFromString($pColumn) + $pNumCols); $highestColumnIndex = Coordinate::columnIndexFromString($highestColumn);
$pColumnIndex = Coordinate::columnIndexFromString($pColumn);
if ($pColumnIndex > $highestColumnIndex) {
return $this;
}
$pColumn = Coordinate::stringFromColumnIndex($pColumnIndex + $pNumCols);
$objReferenceHelper = ReferenceHelper::getInstance(); $objReferenceHelper = ReferenceHelper::getInstance();
$objReferenceHelper->insertNewBefore($pColumn . '1', -$pNumCols, 0, $this); $objReferenceHelper->insertNewBefore($pColumn . '1', -$pNumCols, 0, $this);
for ($c = 0; $c < $pNumCols; ++$c) {
$maxPossibleColumnsToBeRemoved = $highestColumnIndex - $pColumnIndex + 1;
for ($c = 0, $n = min($maxPossibleColumnsToBeRemoved, $pNumCols); $c < $n; ++$c) {
$this->getCellCollection()->removeColumn($highestColumn); $this->getCellCollection()->removeColumn($highestColumn);
$highestColumn = Coordinate::stringFromColumnIndex(Coordinate::columnIndexFromString($highestColumn) - 1); $highestColumn = Coordinate::stringFromColumnIndex(Coordinate::columnIndexFromString($highestColumn) - 1);
} }
$this->garbageCollect(); $this->garbageCollect();
} else {
throw new Exception('Column references should not be numeric.');
}
return $this; return $this;
} }

View File

@ -191,6 +191,7 @@ class WorksheetTest extends TestCase
['A2', 'B2', 'C2'], ['A2', 'B2', 'C2'],
], ],
'A', 'A',
1,
[ [
['B1', 'C1'], ['B1', 'C1'],
['B2', 'C2'], ['B2', 'C2'],
@ -203,6 +204,7 @@ class WorksheetTest extends TestCase
['A2', 'B2', 'C2'], ['A2', 'B2', 'C2'],
], ],
'B', 'B',
1,
[ [
['A1', 'C1'], ['A1', 'C1'],
['A2', 'C2'], ['A2', 'C2'],
@ -215,12 +217,39 @@ class WorksheetTest extends TestCase
['A2', 'B2', 'C2'], ['A2', 'B2', 'C2'],
], ],
'C', 'C',
1,
[ [
['A1', 'B1'], ['A1', 'B1'],
['A2', 'B2'], ['A2', 'B2'],
], ],
'B', 'B',
], ],
'Remove a column out of range' => [
[
['A1', 'B1', 'C1'],
['A2', 'B2', 'C2'],
],
'D',
1,
[
['A1', 'B1', 'C1'],
['A2', 'B2', 'C2'],
],
'C',
],
'Remove multiple columns' => [
[
['A1', 'B1', 'C1'],
['A2', 'B2', 'C2'],
],
'B',
5,
[
['A1'],
['A2'],
],
'A',
],
]; ];
} }
@ -230,6 +259,7 @@ class WorksheetTest extends TestCase
public function testRemoveColumn( public function testRemoveColumn(
array $initialData, array $initialData,
string $columnToBeRemoved, string $columnToBeRemoved,
int $columnsToBeRemoved,
array $expectedData, array $expectedData,
string $expectedHighestColumn string $expectedHighestColumn
) { ) {
@ -237,7 +267,7 @@ class WorksheetTest extends TestCase
$worksheet = $spreadsheet->getActiveSheet(); $worksheet = $spreadsheet->getActiveSheet();
$worksheet->fromArray($initialData); $worksheet->fromArray($initialData);
$worksheet->removeColumn($columnToBeRemoved); $worksheet->removeColumn($columnToBeRemoved, $columnsToBeRemoved);
self::assertSame($expectedHighestColumn, $worksheet->getHighestColumn()); self::assertSame($expectedHighestColumn, $worksheet->getHighestColumn());
self::assertSame($expectedData, $worksheet->toArray()); self::assertSame($expectedData, $worksheet->toArray());