From 567b9601b030fab03f5e946d33cbcea7f8bb2d54 Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Sat, 21 May 2022 07:21:14 -0700 Subject: [PATCH] Allow Csv Reader to Store Null String in Spreadsheet (#2842) Fix #2840 (and also #2839 but that's Q&A, not an issue). Csv Reader does not populate cells which contain null string. This PR provides an option for the reader to store null strings as it does with any other string. --- docs/topics/reading-and-writing-to-file.md | 12 +++-- src/PhpSpreadsheet/Reader/Csv.php | 21 ++++++++- .../Reader/Csv/CsvIssue2840Test.php | 45 +++++++++++++++++++ 3 files changed, 72 insertions(+), 6 deletions(-) create mode 100644 tests/PhpSpreadsheetTests/Reader/Csv/CsvIssue2840Test.php diff --git a/docs/topics/reading-and-writing-to-file.md b/docs/topics/reading-and-writing-to-file.md index 19928f04..0bcc1909 100644 --- a/docs/topics/reading-and-writing-to-file.md +++ b/docs/topics/reading-and-writing-to-file.md @@ -449,8 +449,7 @@ $spreadsheet = $reader->loadSpreadsheetFromString($data); #### Setting CSV options Often, CSV files are not really "comma separated", or use semicolon (`;`) -as a separator. You can instruct -`\PhpOffice\PhpSpreadsheet\Reader\Csv` some options before reading a CSV +as a separator. You can set some options before reading a CSV file. The separator will be auto-detected, so in most cases it should not be necessary @@ -506,6 +505,12 @@ $reader->setSheetIndex(0); $spreadsheet = $reader->load('sample.csv'); ``` +The CSV reader will normally not load null strings into the spreadsheet. +To load them: +```php +$reader->setPreserveNullString(true); +``` + Finally, you can set a callback to be invoked when the constructor is executed, either through `new Csv()` or `IOFactory::load`, and have that callback set the customizable attributes to whatever @@ -584,8 +589,7 @@ $writer->save("05featuredemo.csv"); #### Setting CSV options Often, CSV files are not really "comma separated", or use semicolon (`;`) -as a separator. You can instruct -`\PhpOffice\PhpSpreadsheet\Writer\Csv` some options before writing a CSV +as a separator. You can set some options before writing a CSV file: ```php diff --git a/src/PhpSpreadsheet/Reader/Csv.php b/src/PhpSpreadsheet/Reader/Csv.php index b604ceef..65a71edb 100644 --- a/src/PhpSpreadsheet/Reader/Csv.php +++ b/src/PhpSpreadsheet/Reader/Csv.php @@ -103,6 +103,9 @@ class Csv extends BaseReader */ protected $preserveNumericFormatting = false; + /** @var bool */ + private $preserveNullString = false; + /** * Create a new CSV Reader instance. */ @@ -300,9 +303,11 @@ class Csv extends BaseReader } } - public function setTestAutoDetect(bool $value): void + public function setTestAutoDetect(bool $value): self { $this->testAutodetect = $value; + + return $this; } private function setAutoDetect(?string $value): ?string @@ -390,7 +395,7 @@ class Csv extends BaseReader foreach ($rowData as $rowDatum) { $this->convertBoolean($rowDatum, $preserveBooleanString); $numberFormatMask = $this->convertFormattedNumber($rowDatum); - if ($rowDatum !== '' && $this->readFilter->readCell($columnLetter, $currentRow)) { + if (($rowDatum !== '' || $this->preserveNullString) && $this->readFilter->readCell($columnLetter, $currentRow)) { if ($this->contiguous) { if ($noOutputYet) { $noOutputYet = false; @@ -625,4 +630,16 @@ class Csv extends BaseReader return ($encoding === '') ? $dflt : $encoding; } + + public function setPreserveNullString(bool $value): self + { + $this->preserveNullString = $value; + + return $this; + } + + public function getPreserveNullString(): bool + { + return $this->preserveNullString; + } } diff --git a/tests/PhpSpreadsheetTests/Reader/Csv/CsvIssue2840Test.php b/tests/PhpSpreadsheetTests/Reader/Csv/CsvIssue2840Test.php new file mode 100644 index 00000000..34d0a864 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Reader/Csv/CsvIssue2840Test.php @@ -0,0 +1,45 @@ +getPreserveNullString()); + $inputData = <<loadSpreadsheetFromString($inputData); + $sheet = $spreadsheet->getActiveSheet(); + self::assertSame($expected, $sheet->toArray()); + $spreadsheet->disconnectWorksheets(); + } + + public function testNullStringLoad(): void + { + $reader = new Csv(); + $reader->setPreserveNullString(true); + $inputData = <<loadSpreadsheetFromString($inputData); + $sheet = $spreadsheet->getActiveSheet(); + self::assertSame($expected, $sheet->toArray()); + $spreadsheet->disconnectWorksheets(); + } +}