Skip to content

Commit 3dcc5ca

Browse files
authored
Fix removing last row incorrect behavior
`$highestRow = $this->getHighestDataRow();` was calculated after `$this->getCellCollection()->removeRow($pRow + $r);` - this is the root reason for incorrect rows removal because removing last row will change '$this->getHighestDataRow()' value, but removing row from the middle will not change it. So, removing last row causes incorrect `$highestRow` value that is used for wiping out empty rows from the bottom of the table: ```php for ($r = 0; $r < $pNumRows; ++$r) { $this->getCellCollection()->removeRow($highestRow); --$highestRow; } ``` To prevent this incorrect behavior I've moved highest row calculation before row removal. But this still doesn't solve another problem when trying remove non existing rows: in this case the code above will remove `$pNumRows` rows from below of the table, e.g. if `$highestRow=4` and `$pNumRows=6`, than rows 4, 3, 2, 1, 0, -1 will be deleted. Obviously, this is not good, that is why I've added `$removedRowsCounter` to fix this issue. And finally, moved Exception to early if statement to get away from unnecessary 'if-else'. Fixes #1364 Closes #1365
1 parent 6e76d4e commit 3dcc5ca

File tree

3 files changed

+149
-11
lines changed

3 files changed

+149
-11
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org).
1515

1616
- Fix ROUNDUP and ROUNDDOWN for floating-point rounding error [#1404](https://github.com/PHPOffice/PhpSpreadsheet/pull/1404)
1717
- Fix loading styles from vmlDrawings when containing whitespace [#1347](https://github.com/PHPOffice/PhpSpreadsheet/issues/1347)
18+
- Fix incorrect behavior when removing last row [#1365](https://github.com/PHPOffice/PhpSpreadsheet/pull/1365)
1819

1920
## [1.11.0] - 2020-03-02
2021

src/PhpSpreadsheet/Worksheet/Worksheet.php

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2114,20 +2114,25 @@ public function insertNewColumnBeforeByIndex($beforeColumnIndex, $pNumCols = 1)
21142114
*/
21152115
public function removeRow($pRow, $pNumRows = 1)
21162116
{
2117-
if ($pRow >= 1) {
2118-
for ($r = 0; $r < $pNumRows; ++$r) {
2117+
if ($pRow < 1) {
2118+
throw new Exception('Rows to be deleted should at least start from row 1.');
2119+
}
2120+
2121+
$highestRow = $this->getHighestDataRow();
2122+
$removedRowsCounter = 0;
2123+
2124+
for ($r = 0; $r < $pNumRows; ++$r) {
2125+
if ($pRow + $r <= $highestRow) {
21192126
$this->getCellCollection()->removeRow($pRow + $r);
2127+
++$removedRowsCounter;
21202128
}
2129+
}
21212130

2122-
$highestRow = $this->getHighestDataRow();
2123-
$objReferenceHelper = ReferenceHelper::getInstance();
2124-
$objReferenceHelper->insertNewBefore('A' . ($pRow + $pNumRows), 0, -$pNumRows, $this);
2125-
for ($r = 0; $r < $pNumRows; ++$r) {
2126-
$this->getCellCollection()->removeRow($highestRow);
2127-
--$highestRow;
2128-
}
2129-
} else {
2130-
throw new Exception('Rows to be deleted should at least start from row 1.');
2131+
$objReferenceHelper = ReferenceHelper::getInstance();
2132+
$objReferenceHelper->insertNewBefore('A' . ($pRow + $pNumRows), 0, -$pNumRows, $this);
2133+
for ($r = 0; $r < $removedRowsCounter; ++$r) {
2134+
$this->getCellCollection()->removeRow($highestRow);
2135+
--$highestRow;
21312136
}
21322137

21332138
return $this;

tests/PhpSpreadsheetTests/Worksheet/WorksheetTest.php

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,4 +272,136 @@ public function testRemoveColumn(
272272
self::assertSame($expectedHighestColumn, $worksheet->getHighestColumn());
273273
self::assertSame($expectedData, $worksheet->toArray());
274274
}
275+
276+
public function removeRowsProvider()
277+
{
278+
return [
279+
'Remove all rows except first one' => [
280+
[
281+
['A1', 'B1', 'C1'],
282+
['A2', 'B2', 'C2'],
283+
['A3', 'B3', 'C3'],
284+
['A4', 'B4', 'C4'],
285+
],
286+
2,
287+
3,
288+
[
289+
['A1', 'B1', 'C1'],
290+
],
291+
1,
292+
],
293+
'Remove all rows except last one' => [
294+
[
295+
['A1', 'B1', 'C1'],
296+
['A2', 'B2', 'C2'],
297+
['A3', 'B3', 'C3'],
298+
['A4', 'B4', 'C4'],
299+
],
300+
1,
301+
3,
302+
[
303+
['A4', 'B4', 'C4'],
304+
],
305+
1,
306+
],
307+
'Remove last row' => [
308+
[
309+
['A1', 'B1', 'C1'],
310+
['A2', 'B2', 'C2'],
311+
['A3', 'B3', 'C3'],
312+
['A4', 'B4', 'C4'],
313+
],
314+
4,
315+
1,
316+
[
317+
['A1', 'B1', 'C1'],
318+
['A2', 'B2', 'C2'],
319+
['A3', 'B3', 'C3'],
320+
],
321+
3,
322+
],
323+
'Remove first row' => [
324+
[
325+
['A1', 'B1', 'C1'],
326+
['A2', 'B2', 'C2'],
327+
['A3', 'B3', 'C3'],
328+
['A4', 'B4', 'C4'],
329+
],
330+
1,
331+
1,
332+
[
333+
['A2', 'B2', 'C2'],
334+
['A3', 'B3', 'C3'],
335+
['A4', 'B4', 'C4'],
336+
],
337+
3,
338+
],
339+
'Remove all rows except first and last' => [
340+
[
341+
['A1', 'B1', 'C1'],
342+
['A2', 'B2', 'C2'],
343+
['A3', 'B3', 'C3'],
344+
['A4', 'B4', 'C4'],
345+
],
346+
2,
347+
2,
348+
[
349+
['A1', 'B1', 'C1'],
350+
['A4', 'B4', 'C4'],
351+
],
352+
2,
353+
],
354+
'Remove non existing rows' => [
355+
[
356+
['A1', 'B1', 'C1'],
357+
['A2', 'B2', 'C2'],
358+
['A3', 'B3', 'C3'],
359+
['A4', 'B4', 'C4'],
360+
],
361+
2,
362+
10,
363+
[
364+
['A1', 'B1', 'C1'],
365+
],
366+
1,
367+
],
368+
'Remove only non existing rows' => [
369+
[
370+
['A1', 'B1', 'C1'],
371+
['A2', 'B2', 'C2'],
372+
['A3', 'B3', 'C3'],
373+
['A4', 'B4', 'C4'],
374+
],
375+
5,
376+
10,
377+
[
378+
['A1', 'B1', 'C1'],
379+
['A2', 'B2', 'C2'],
380+
['A3', 'B3', 'C3'],
381+
['A4', 'B4', 'C4'],
382+
],
383+
4,
384+
],
385+
];
386+
}
387+
388+
/**
389+
* @dataProvider removeRowsProvider
390+
*/
391+
public function testRemoveRows(
392+
array $initialData,
393+
int $rowToRemove,
394+
int $rowsQtyToRemove,
395+
array $expectedData,
396+
int $expectedHighestRow
397+
) {
398+
$workbook = new Spreadsheet();
399+
$worksheet = $workbook->getActiveSheet();
400+
$worksheet->fromArray($initialData);
401+
402+
$worksheet->removeRow($rowToRemove, $rowsQtyToRemove);
403+
404+
self::assertSame($expectedData, $worksheet->toArray());
405+
self::assertSame($expectedHighestRow, $worksheet->getHighestRow());
406+
}
275407
}

0 commit comments

Comments
 (0)