Skip to content

Commit

Permalink
Calculate row range for a single-row AutoFilter range
Browse files Browse the repository at this point in the history
  • Loading branch information
MarkBaker committed Oct 8, 2022
1 parent 339a593 commit 720b98a
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 4 deletions.
32 changes: 28 additions & 4 deletions src/PhpSpreadsheet/Worksheet/AutoFilter.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
use PhpOffice\PhpSpreadsheet\Cell\AddressRange;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\Exception;
use PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException;
use PhpOffice\PhpSpreadsheet\Shared\Date;
use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule;

Expand Down Expand Up @@ -176,13 +175,13 @@ public function getColumns()
public function testColumnInRange($column)
{
if (empty($this->range)) {
throw new PhpSpreadsheetException('No autofilter range is defined.');
throw new Exception('No autofilter range is defined.');
}

$columnIndex = Coordinate::columnIndexFromString($column);
[$rangeStart, $rangeEnd] = Coordinate::rangeBoundaries($this->range);
if (($rangeStart[0] > $columnIndex) || ($rangeEnd[0] < $columnIndex)) {
throw new PhpSpreadsheetException('Column is outside of current autofilter range.');
throw new Exception('Column is outside of current autofilter range.');
}

return $columnIndex - $rangeStart[0];
Expand Down Expand Up @@ -249,7 +248,7 @@ public function setColumn($columnObjectOrString)
} elseif (is_object($columnObjectOrString) && ($columnObjectOrString instanceof AutoFilter\Column)) {
$column = $columnObjectOrString->getColumnIndex();
} else {
throw new PhpSpreadsheetException('Column is not within the autofilter range.');
throw new Exception('Column is not within the autofilter range.');
}
$this->testColumnInRange($column);

Expand Down Expand Up @@ -1033,6 +1032,8 @@ public function showHideRows()
}
}

$rangeEnd[1] = $this->autoExtendRange($rangeStart[1], $rangeEnd[1]);

// Execute the column tests for each row in the autoFilter range to determine show/hide,
for ($row = $rangeStart[1] + 1; $row <= $rangeEnd[1]; ++$row) {
$result = true;
Expand All @@ -1055,6 +1056,29 @@ public function showHideRows()
return $this;
}

/**
* Magic Range Auto-sizing.
* For a single row rangeSet, we follow MS Excel rules, and search for the first empty row to determine our range.
*/
public function autoExtendRange(int $startRow, int $endRow): int
{
if ($startRow === $endRow && $this->workSheet !== null) {
try {
$rowIterator = $this->workSheet->getRowIterator($startRow + 1);
} catch (Exception $e) {
// If there are no rows below $startRow
return $startRow;
}
foreach ($rowIterator as $row) {
if ($row->isEmpty(CellIterator::TREAT_NULL_VALUE_AS_EMPTY_CELL | CellIterator::TREAT_EMPTY_STRING_AS_EMPTY_CELL) === true) {
return $row->getRowIndex() - 1;
}
}
}

return $endRow;
}

/**
* Implement PHP __clone to create a deep clone, not just a shallow copy.
*/
Expand Down
22 changes: 22 additions & 0 deletions tests/PhpSpreadsheetTests/Worksheet/AutoFilter/AutoFilterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -510,4 +510,26 @@ public function testClearColumn(): void
self::assertArrayHasKey('K', $columns);
self::assertArrayHasKey('M', $columns);
}

public function testAutoExtendRange(): void
{
$spreadsheet = $this->getSpreadsheet();
$worksheet = $spreadsheet->addSheet(new Worksheet($spreadsheet, 'Autosized AutoFilter'));

$worksheet->getCell('A1')->setValue('Col 1');
$worksheet->getCell('B1')->setValue('Col 2');

$worksheet->setAutoFilter('A1:B1');
$lastRow = $worksheet->getAutoFilter()->autoExtendRange(1, 1);
self::assertSame(1, $lastRow, 'No data below AutoFilter, so there should ne no resize');

$lastRow = $worksheet->getAutoFilter()->autoExtendRange(1, 999);
self::assertSame(999, $lastRow, 'Filter range is already correctly sized');

$data = [['A', 'A'], ['B', 'A'], ['A', 'B'], ['C', 'B'], ['B', null], [null, null], ['D', 'D'], ['E', 'E']];
$worksheet->fromArray($data, null, 'A2', true);

$lastRow = $worksheet->getAutoFilter()->autoExtendRange(1, 1);
self::assertSame(6, $lastRow, 'Filter range has been re-sized incorrectly');
}
}

0 comments on commit 720b98a

Please sign in to comment.