diff --git a/CHANGELOG.md b/CHANGELOG.md index 290474a1..503f1121 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,10 @@ and this project adheres to [Semantic Versioning](https://semver.org). - Added Worksheet visibility in Ods Writer [PR #2850](https://github.com/PHPOffice/PhpSpreadsheet/pull/2850) - Allow Csv Reader to treat string as contents of file [Issue #1285](https://github.com/PHPOffice/PhpSpreadsheet/issues/1285) [PR #2792](https://github.com/PHPOffice/PhpSpreadsheet/pull/2792) - Allow Csv Reader to store null string rather than leave cell empty [Issue #2840](https://github.com/PHPOffice/PhpSpreadsheet/issues/2840) [PR #2842](https://github.com/PHPOffice/PhpSpreadsheet/pull/2842) +- Provide new Worksheet methods to identify if a row or column is "empty", making allowance for different definitions of "empty": + - Treat rows/columns containing no cell records as empty (default) + - Treat cells containing a null value as empty + - Treat cells containing an empty string as empty ### Changed diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 33a3ea69..0a131911 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -3655,11 +3655,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Worksheet/CellIterator.php - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Column\\:\\:\\$parent \\(PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/Column.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Drawing\\\\Shadow\\:\\:\\$color \\(PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Color\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Color\\|null\\.$#" count: 1 @@ -3685,11 +3680,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Worksheet/PageSetup.php - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Row\\:\\:\\$worksheet \\(PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/Row.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\SheetView\\:\\:\\$sheetViewTypes has no type specified\\.$#" count: 1 diff --git a/src/PhpSpreadsheet/Worksheet/CellIterator.php b/src/PhpSpreadsheet/Worksheet/CellIterator.php index 142639ce..17286f9c 100644 --- a/src/PhpSpreadsheet/Worksheet/CellIterator.php +++ b/src/PhpSpreadsheet/Worksheet/CellIterator.php @@ -12,6 +12,10 @@ use PhpOffice\PhpSpreadsheet\Collection\Cells; */ abstract class CellIterator implements Iterator { + public const TREAT_NULL_VALUE_AS_EMPTY_CELL = 1; + + public const TREAT_EMPTY_STRING_AS_EMPTY_CELL = 2; + /** * Worksheet to iterate. * diff --git a/src/PhpSpreadsheet/Worksheet/Column.php b/src/PhpSpreadsheet/Worksheet/Column.php index b6f30f1f..e6e332ae 100644 --- a/src/PhpSpreadsheet/Worksheet/Column.php +++ b/src/PhpSpreadsheet/Worksheet/Column.php @@ -9,7 +9,7 @@ class Column * * @var Worksheet */ - private $parent; + private $worksheet; /** * Column index. @@ -23,10 +23,10 @@ class Column * * @param string $columnIndex */ - public function __construct(?Worksheet $parent = null, $columnIndex = 'A') + public function __construct(Worksheet $worksheet, $columnIndex = 'A') { // Set parent and column index - $this->parent = $parent; + $this->worksheet = $worksheet; $this->columnIndex = $columnIndex; } @@ -36,7 +36,7 @@ class Column public function __destruct() { // @phpstan-ignore-next-line - $this->parent = null; + $this->worksheet = null; } /** @@ -57,6 +57,53 @@ class Column */ public function getCellIterator($startRow = 1, $endRow = null) { - return new ColumnCellIterator($this->parent, $this->columnIndex, $startRow, $endRow); + return new ColumnCellIterator($this->worksheet, $this->columnIndex, $startRow, $endRow); + } + + /** + * Returns a boolean true if the column contains no cells. By default, this means that no cell records exist in the + * collection for this column. false will be returned otherwise. + * This rule can be modified by passing a $definitionOfEmptyFlags value: + * 1 - CellIterator::TREAT_NULL_VALUE_AS_EMPTY_CELL If the only cells in the collection are null value + * cells, then the column will be considered empty. + * 2 - CellIterator::TREAT_EMPTY_STRING_AS_EMPTY_CELL If the only cells in the collection are empty + * string value cells, then the column will be considered empty. + * 3 - CellIterator::TREAT_NULL_VALUE_AS_EMPTY_CELL | CellIterator::TREAT_EMPTY_STRING_AS_EMPTY_CELL + * If the only cells in the collection are null value or empty string value cells, then the column + * will be considered empty. + * + * @param int $definitionOfEmptyFlags + * Possible Flag Values are: + * CellIterator::TREAT_NULL_VALUE_AS_EMPTY_CELL + * CellIterator::TREAT_EMPTY_STRING_AS_EMPTY_CELL + */ + public function isEmpty(int $definitionOfEmptyFlags = 0): bool + { + $nullValueCellIsEmpty = (bool) ($definitionOfEmptyFlags & CellIterator::TREAT_NULL_VALUE_AS_EMPTY_CELL); + $emptyStringCellIsEmpty = (bool) ($definitionOfEmptyFlags & CellIterator::TREAT_EMPTY_STRING_AS_EMPTY_CELL); + + $cellIterator = $this->getCellIterator(); + $cellIterator->setIterateOnlyExistingCells(true); + foreach ($cellIterator as $cell) { + $value = $cell->getValue(); + if ($value === null && $nullValueCellIsEmpty === true) { + continue; + } + if ($value === '' && $emptyStringCellIsEmpty === true) { + continue; + } + + return false; + } + + return true; + } + + /** + * Returns bound worksheet. + */ + public function getWorksheet(): Worksheet + { + return $this->worksheet; } } diff --git a/src/PhpSpreadsheet/Worksheet/Row.php b/src/PhpSpreadsheet/Worksheet/Row.php index a5f8f326..5c162752 100644 --- a/src/PhpSpreadsheet/Worksheet/Row.php +++ b/src/PhpSpreadsheet/Worksheet/Row.php @@ -23,7 +23,7 @@ class Row * * @param int $rowIndex */ - public function __construct(?Worksheet $worksheet = null, $rowIndex = 1) + public function __construct(Worksheet $worksheet, $rowIndex = 1) { // Set parent and row index $this->worksheet = $worksheet; @@ -59,6 +59,45 @@ class Row return new RowCellIterator($this->worksheet, $this->rowIndex, $startColumn, $endColumn); } + /** + * Returns a boolean true if the row contains no cells. By default, this means that no cell records exist in the + * collection for this row. false will be returned otherwise. + * This rule can be modified by passing a $definitionOfEmptyFlags value: + * 1 - CellIterator::TREAT_NULL_VALUE_AS_EMPTY_CELL If the only cells in the collection are null value + * cells, then the row will be considered empty. + * 2 - CellIterator::TREAT_EMPTY_STRING_AS_EMPTY_CELL If the only cells in the collection are empty + * string value cells, then the row will be considered empty. + * 3 - CellIterator::TREAT_NULL_VALUE_AS_EMPTY_CELL | CellIterator::TREAT_EMPTY_STRING_AS_EMPTY_CELL + * If the only cells in the collection are null value or empty string value cells, then the row + * will be considered empty. + * + * @param int $definitionOfEmptyFlags + * Possible Flag Values are: + * CellIterator::TREAT_NULL_VALUE_AS_EMPTY_CELL + * CellIterator::TREAT_EMPTY_STRING_AS_EMPTY_CELL + */ + public function isEmpty(int $definitionOfEmptyFlags = 0): bool + { + $nullValueCellIsEmpty = (bool) ($definitionOfEmptyFlags & CellIterator::TREAT_NULL_VALUE_AS_EMPTY_CELL); + $emptyStringCellIsEmpty = (bool) ($definitionOfEmptyFlags & CellIterator::TREAT_EMPTY_STRING_AS_EMPTY_CELL); + + $cellIterator = $this->getCellIterator(); + $cellIterator->setIterateOnlyExistingCells(true); + foreach ($cellIterator as $cell) { + $value = $cell->getValue(); + if ($value === null && $nullValueCellIsEmpty === true) { + continue; + } + if ($value === '' && $emptyStringCellIsEmpty === true) { + continue; + } + + return false; + } + + return true; + } + /** * Returns bound worksheet. */ diff --git a/src/PhpSpreadsheet/Worksheet/Worksheet.php b/src/PhpSpreadsheet/Worksheet/Worksheet.php index 4a441a93..54785bfa 100644 --- a/src/PhpSpreadsheet/Worksheet/Worksheet.php +++ b/src/PhpSpreadsheet/Worksheet/Worksheet.php @@ -3232,6 +3232,66 @@ class Worksheet implements IComparable return clone $this; } + /** + * Returns a boolean true if the specified row contains no cells. By default, this means that no cell records + * exist in the collection for this row. false will be returned otherwise. + * This rule can be modified by passing a $definitionOfEmptyFlags value: + * 1 - CellIterator::TREAT_NULL_VALUE_AS_EMPTY_CELL If the only cells in the collection are null value + * cells, then the row will be considered empty. + * 2 - CellIterator::TREAT_EMPTY_STRING_AS_EMPTY_CELL If the only cells in the collection are empty + * string value cells, then the row will be considered empty. + * 3 - CellIterator::TREAT_NULL_VALUE_AS_EMPTY_CELL | CellIterator::TREAT_EMPTY_STRING_AS_EMPTY_CELL + * If the only cells in the collection are null value or empty string value cells, then the row + * will be considered empty. + * + * @param int $definitionOfEmptyFlags + * Possible Flag Values are: + * CellIterator::TREAT_NULL_VALUE_AS_EMPTY_CELL + * CellIterator::TREAT_EMPTY_STRING_AS_EMPTY_CELL + */ + public function isEmptyRow(int $rowId, int $definitionOfEmptyFlags = 0): bool + { + try { + $iterator = new RowIterator($this, $rowId, $rowId); + $iterator->seek($rowId); + $row = $iterator->current(); + } catch (Exception $e) { + return true; + } + + return $row->isEmpty($definitionOfEmptyFlags); + } + + /** + * Returns a boolean true if the specified column contains no cells. By default, this means that no cell records + * exist in the collection for this column. false will be returned otherwise. + * This rule can be modified by passing a $definitionOfEmptyFlags value: + * 1 - CellIterator::TREAT_NULL_VALUE_AS_EMPTY_CELL If the only cells in the collection are null value + * cells, then the column will be considered empty. + * 2 - CellIterator::TREAT_EMPTY_STRING_AS_EMPTY_CELL If the only cells in the collection are empty + * string value cells, then the column will be considered empty. + * 3 - CellIterator::TREAT_NULL_VALUE_AS_EMPTY_CELL | CellIterator::TREAT_EMPTY_STRING_AS_EMPTY_CELL + * If the only cells in the collection are null value or empty string value cells, then the column + * will be considered empty. + * + * @param int $definitionOfEmptyFlags + * Possible Flag Values are: + * CellIterator::TREAT_NULL_VALUE_AS_EMPTY_CELL + * CellIterator::TREAT_EMPTY_STRING_AS_EMPTY_CELL + */ + public function isEmptyColumn(string $columnId, int $definitionOfEmptyFlags = 0): bool + { + try { + $iterator = new ColumnIterator($this, $columnId, $columnId); + $iterator->seek($columnId); + $column = $iterator->current(); + } catch (Exception $e) { + return true; + } + + return $column->isEmpty($definitionOfEmptyFlags); + } + /** * Implement PHP __clone to create a deep clone, not just a shallow copy. */ diff --git a/tests/PhpSpreadsheetTests/Worksheet/ColumnIteratorEmptyTest.php b/tests/PhpSpreadsheetTests/Worksheet/ColumnIteratorEmptyTest.php new file mode 100644 index 00000000..beb87028 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Worksheet/ColumnIteratorEmptyTest.php @@ -0,0 +1,154 @@ +getActiveSheet(); + $sheet->setCellValueExplicit('A1', 'Hello World', DataType::TYPE_STRING); + $sheet->setCellValueExplicit('C2', null, DataType::TYPE_NULL); + $sheet->setCellValueExplicit('D2', '', DataType::TYPE_STRING); + $sheet->setCellValueExplicit('E2', null, DataType::TYPE_NULL); + $sheet->setCellValueExplicit('E3', '', DataType::TYPE_STRING); + $sheet->setCellValueExplicit('F2', null, DataType::TYPE_NULL); + $sheet->setCellValueExplicit('F3', 'PHP', DataType::TYPE_STRING); + $sheet->setCellValueExplicit('G2', '', DataType::TYPE_STRING); + $sheet->setCellValueExplicit('G3', 'PHP', DataType::TYPE_STRING); + $sheet->setCellValueExplicit('H2', null, DataType::TYPE_NULL); + $sheet->setCellValueExplicit('H3', '', DataType::TYPE_STRING); + $sheet->setCellValueExplicit('H4', 'PHP', DataType::TYPE_STRING); + + return $sheet; + } + + /** + * @dataProvider emptyColumnBasic + */ + public function testIteratorEmptyColumn(string $columnId, bool $expectedEmpty): void + { + $spreadsheet = new Spreadsheet(); + $sheet = self::getPopulatedSheet($spreadsheet); + $iterator = new ColumnIterator($sheet, 'A', 'I'); + $iterator->seek($columnId); + $row = $iterator->current(); + $isEmpty = $row->isEmpty(); + self::assertSame($expectedEmpty, $isEmpty); + $spreadsheet->disconnectWorksheets(); + } + + public function emptyColumnBasic(): array + { + return [ + ['A', false], + ['B', true], + ['C', false], + ['D', false], + ['E', false], + ['F', false], + ['G', false], + ['H', false], + ['I', true], + ]; + } + + /** + * @dataProvider emptyColumnNullAsEmpty + */ + public function testIteratorEmptyColumnWithNull(string $columnId, bool $expectedEmpty): void + { + $spreadsheet = new Spreadsheet(); + $sheet = self::getPopulatedSheet($spreadsheet); + $iterator = new ColumnIterator($sheet, 'A', 'I'); + $iterator->seek($columnId); + $row = $iterator->current(); + $isEmpty = $row->isEmpty(CellIterator::TREAT_NULL_VALUE_AS_EMPTY_CELL); + self::assertSame($expectedEmpty, $isEmpty); + $spreadsheet->disconnectWorksheets(); + } + + public function emptyColumnNullAsEmpty(): array + { + return [ + ['A', false], + ['B', true], + ['C', true], + ['D', false], + ['E', false], + ['F', false], + ['G', false], + ['H', false], + ['I', true], + ]; + } + + /** + * @dataProvider emptyColumnEmptyStringAsEmpty + */ + public function testIteratorEmptyColumnWithEmptyString(string $columnId, bool $expectedEmpty): void + { + $spreadsheet = new Spreadsheet(); + $sheet = self::getPopulatedSheet($spreadsheet); + $iterator = new ColumnIterator($sheet, 'A', 'I'); + $iterator->seek($columnId); + $row = $iterator->current(); + $isEmpty = $row->isEmpty(CellIterator::TREAT_EMPTY_STRING_AS_EMPTY_CELL); + self::assertSame($expectedEmpty, $isEmpty); + $spreadsheet->disconnectWorksheets(); + } + + public function emptyColumnEmptyStringAsEmpty(): array + { + return [ + ['A', false], + ['B', true], + ['C', false], + ['D', true], + ['E', false], + ['F', false], + ['G', false], + ['H', false], + ['I', true], + ]; + } + + /** + * @dataProvider emptyColumnNullAndEmptyStringAsEmpty + */ + public function testIteratorEmptyColumnWithNullAndEmptyString(string $columnId, bool $expectedEmpty): void + { + $spreadsheet = new Spreadsheet(); + $sheet = self::getPopulatedSheet($spreadsheet); + $iterator = new ColumnIterator($sheet, 'A', 'I'); + $iterator->seek($columnId); + $row = $iterator->current(); + $isEmpty = $row->isEmpty( + CellIterator::TREAT_EMPTY_STRING_AS_EMPTY_CELL | CellIterator::TREAT_NULL_VALUE_AS_EMPTY_CELL + ); + self::assertSame($expectedEmpty, $isEmpty); + $spreadsheet->disconnectWorksheets(); + } + + public function emptyColumnNullAndEmptyStringAsEmpty(): array + { + return [ + ['A', false], + ['B', true], + ['C', true], + ['D', true], + ['E', true], + ['F', false], + ['G', false], + ['H', false], + ['I', true], + ]; + } +} diff --git a/tests/PhpSpreadsheetTests/Worksheet/RowIteratorEmptyTest.php b/tests/PhpSpreadsheetTests/Worksheet/RowIteratorEmptyTest.php new file mode 100644 index 00000000..9bee6b59 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Worksheet/RowIteratorEmptyTest.php @@ -0,0 +1,154 @@ +getActiveSheet(); + $sheet->setCellValueExplicit('A1', 'Hello World', DataType::TYPE_STRING); + $sheet->setCellValueExplicit('B3', null, DataType::TYPE_NULL); + $sheet->setCellValueExplicit('B4', '', DataType::TYPE_STRING); + $sheet->setCellValueExplicit('B5', null, DataType::TYPE_NULL); + $sheet->setCellValueExplicit('C5', '', DataType::TYPE_STRING); + $sheet->setCellValueExplicit('B6', null, DataType::TYPE_NULL); + $sheet->setCellValueExplicit('C6', 'PHP', DataType::TYPE_STRING); + $sheet->setCellValueExplicit('B7', '', DataType::TYPE_STRING); + $sheet->setCellValueExplicit('C7', 'PHP', DataType::TYPE_STRING); + $sheet->setCellValueExplicit('B8', null, DataType::TYPE_NULL); + $sheet->setCellValueExplicit('C8', '', DataType::TYPE_STRING); + $sheet->setCellValueExplicit('D8', 'PHP', DataType::TYPE_STRING); + + return $sheet; + } + + /** + * @dataProvider emptyRowBasic + */ + public function testIteratorEmptyRow(int $rowId, bool $expectedEmpty): void + { + $spreadsheet = new Spreadsheet(); + $sheet = self::getPopulatedSheet($spreadsheet); + $iterator = new RowIterator($sheet, 1, 9); + $iterator->seek($rowId); + $row = $iterator->current(); + $isEmpty = $row->isEmpty(); + self::assertSame($expectedEmpty, $isEmpty); + $spreadsheet->disconnectWorksheets(); + } + + public function emptyRowBasic(): array + { + return [ + [1, false], + [2, true], + [3, false], + [4, false], + [5, false], + [6, false], + [7, false], + [8, false], + [9, true], + ]; + } + + /** + * @dataProvider emptyRowNullAsEmpty + */ + public function testIteratorEmptyRowWithNull(int $rowId, bool $expectedEmpty): void + { + $spreadsheet = new Spreadsheet(); + $sheet = self::getPopulatedSheet($spreadsheet); + $iterator = new RowIterator($sheet, 1, 9); + $iterator->seek($rowId); + $row = $iterator->current(); + $isEmpty = $row->isEmpty(CellIterator::TREAT_NULL_VALUE_AS_EMPTY_CELL); + self::assertSame($expectedEmpty, $isEmpty); + $spreadsheet->disconnectWorksheets(); + } + + public function emptyRowNullAsEmpty(): array + { + return [ + [1, false], + [2, true], + [3, true], + [4, false], + [5, false], + [6, false], + [7, false], + [8, false], + [9, true], + ]; + } + + /** + * @dataProvider emptyRowEmptyStringAsEmpty + */ + public function testIteratorEmptyRowWithEmptyString(int $rowId, bool $expectedEmpty): void + { + $spreadsheet = new Spreadsheet(); + $sheet = self::getPopulatedSheet($spreadsheet); + $iterator = new RowIterator($sheet, 1, 9); + $iterator->seek($rowId); + $row = $iterator->current(); + $isEmpty = $row->isEmpty(CellIterator::TREAT_EMPTY_STRING_AS_EMPTY_CELL); + self::assertSame($expectedEmpty, $isEmpty); + $spreadsheet->disconnectWorksheets(); + } + + public function emptyRowEmptyStringAsEmpty(): array + { + return [ + [1, false], + [2, true], + [3, false], + [4, true], + [5, false], + [6, false], + [7, false], + [8, false], + [9, true], + ]; + } + + /** + * @dataProvider emptyRowNullAndEmptyStringAsEmpty + */ + public function testIteratorEmptyRowWithNullAndEmptyString(int $rowId, bool $expectedEmpty): void + { + $spreadsheet = new Spreadsheet(); + $sheet = self::getPopulatedSheet($spreadsheet); + $iterator = new RowIterator($sheet, 1, 9); + $iterator->seek($rowId); + $row = $iterator->current(); + $isEmpty = $row->isEmpty( + CellIterator::TREAT_EMPTY_STRING_AS_EMPTY_CELL | CellIterator::TREAT_NULL_VALUE_AS_EMPTY_CELL + ); + self::assertSame($expectedEmpty, $isEmpty); + $spreadsheet->disconnectWorksheets(); + } + + public function emptyRowNullAndEmptyStringAsEmpty(): array + { + return [ + [1, false], + [2, true], + [3, true], + [4, true], + [5, true], + [6, false], + [7, false], + [8, false], + [9, true], + ]; + } +} diff --git a/tests/PhpSpreadsheetTests/Worksheet/WorksheetTest.php b/tests/PhpSpreadsheetTests/Worksheet/WorksheetTest.php index 5377444d..17de5c32 100644 --- a/tests/PhpSpreadsheetTests/Worksheet/WorksheetTest.php +++ b/tests/PhpSpreadsheetTests/Worksheet/WorksheetTest.php @@ -3,7 +3,9 @@ namespace PhpOffice\PhpSpreadsheetTests\Worksheet; use Exception; +use PhpOffice\PhpSpreadsheet\Cell\DataType; use PhpOffice\PhpSpreadsheet\Spreadsheet; +use PhpOffice\PhpSpreadsheet\Worksheet\CellIterator; use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; use PHPUnit\Framework\TestCase; @@ -405,4 +407,100 @@ class WorksheetTest extends TestCase self::assertSame($expectedData, $worksheet->toArray()); self::assertSame($expectedHighestRow, $worksheet->getHighestRow()); } + + private static function getPopulatedSheetForEmptyRowTest(Spreadsheet $spreadsheet): Worksheet + { + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValueExplicit('A1', 'Hello World', DataType::TYPE_STRING); + $sheet->setCellValueExplicit('B3', null, DataType::TYPE_NULL); + $sheet->setCellValueExplicit('B4', '', DataType::TYPE_STRING); + $sheet->setCellValueExplicit('B5', null, DataType::TYPE_NULL); + $sheet->setCellValueExplicit('C5', '', DataType::TYPE_STRING); + $sheet->setCellValueExplicit('B6', null, DataType::TYPE_NULL); + $sheet->setCellValueExplicit('C6', 'PHP', DataType::TYPE_STRING); + $sheet->setCellValueExplicit('B7', '', DataType::TYPE_STRING); + $sheet->setCellValueExplicit('C7', 'PHP', DataType::TYPE_STRING); + $sheet->setCellValueExplicit('B8', null, DataType::TYPE_NULL); + $sheet->setCellValueExplicit('C8', '', DataType::TYPE_STRING); + $sheet->setCellValueExplicit('D8', 'PHP', DataType::TYPE_STRING); + + return $sheet; + } + + private static function getPopulatedSheetForEmptyColumnTest(Spreadsheet $spreadsheet): Worksheet + { + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValueExplicit('A1', 'Hello World', DataType::TYPE_STRING); + $sheet->setCellValueExplicit('C2', null, DataType::TYPE_NULL); + $sheet->setCellValueExplicit('D2', '', DataType::TYPE_STRING); + $sheet->setCellValueExplicit('E2', null, DataType::TYPE_NULL); + $sheet->setCellValueExplicit('E3', '', DataType::TYPE_STRING); + $sheet->setCellValueExplicit('F2', null, DataType::TYPE_NULL); + $sheet->setCellValueExplicit('F3', 'PHP', DataType::TYPE_STRING); + $sheet->setCellValueExplicit('G2', '', DataType::TYPE_STRING); + $sheet->setCellValueExplicit('G3', 'PHP', DataType::TYPE_STRING); + $sheet->setCellValueExplicit('H2', null, DataType::TYPE_NULL); + $sheet->setCellValueExplicit('H3', '', DataType::TYPE_STRING); + $sheet->setCellValueExplicit('H4', 'PHP', DataType::TYPE_STRING); + + return $sheet; + } + + /** + * @dataProvider emptyRowProvider + */ + public function testIsEmptyRow(int $rowId, bool $expectedEmpty): void + { + $spreadsheet = new Spreadsheet(); + $sheet = self::getPopulatedSheetForEmptyRowTest($spreadsheet); + + $isEmpty = $sheet->isEmptyRow($rowId, CellIterator::TREAT_EMPTY_STRING_AS_EMPTY_CELL | CellIterator::TREAT_NULL_VALUE_AS_EMPTY_CELL); + + self::assertSame($expectedEmpty, $isEmpty); + $spreadsheet->disconnectWorksheets(); + } + + public function emptyRowProvider(): array + { + return [ + [1, false], + [2, true], + [3, true], + [4, true], + [5, true], + [6, false], + [7, false], + [8, false], + [9, true], + ]; + } + + /** + * @dataProvider emptyColumnProvider + */ + public function testIsEmptyColumn(string $columnId, bool $expectedEmpty): void + { + $spreadsheet = new Spreadsheet(); + $sheet = self::getPopulatedSheetForEmptyColumnTest($spreadsheet); + + $isEmpty = $sheet->isEmptyColumn($columnId, CellIterator::TREAT_EMPTY_STRING_AS_EMPTY_CELL | CellIterator::TREAT_NULL_VALUE_AS_EMPTY_CELL); + + self::assertSame($expectedEmpty, $isEmpty); + $spreadsheet->disconnectWorksheets(); + } + + public function emptyColumnProvider(): array + { + return [ + ['A', false], + ['B', true], + ['C', true], + ['D', true], + ['E', true], + ['F', false], + ['G', false], + ['H', false], + ['I', true], + ]; + } }