Skip to content

Commit 567b960

Browse files
authored
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.
1 parent ef031e7 commit 567b960

File tree

3 files changed

+72
-6
lines changed

3 files changed

+72
-6
lines changed

docs/topics/reading-and-writing-to-file.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -449,8 +449,7 @@ $spreadsheet = $reader->loadSpreadsheetFromString($data);
449449
#### Setting CSV options
450450

451451
Often, CSV files are not really "comma separated", or use semicolon (`;`)
452-
as a separator. You can instruct
453-
`\PhpOffice\PhpSpreadsheet\Reader\Csv` some options before reading a CSV
452+
as a separator. You can set some options before reading a CSV
454453
file.
455454

456455
The separator will be auto-detected, so in most cases it should not be necessary
@@ -506,6 +505,12 @@ $reader->setSheetIndex(0);
506505
$spreadsheet = $reader->load('sample.csv');
507506
```
508507

508+
The CSV reader will normally not load null strings into the spreadsheet.
509+
To load them:
510+
```php
511+
$reader->setPreserveNullString(true);
512+
```
513+
509514
Finally, you can set a callback to be invoked when the constructor is executed,
510515
either through `new Csv()` or `IOFactory::load`,
511516
and have that callback set the customizable attributes to whatever
@@ -584,8 +589,7 @@ $writer->save("05featuredemo.csv");
584589
#### Setting CSV options
585590

586591
Often, CSV files are not really "comma separated", or use semicolon (`;`)
587-
as a separator. You can instruct
588-
`\PhpOffice\PhpSpreadsheet\Writer\Csv` some options before writing a CSV
592+
as a separator. You can set some options before writing a CSV
589593
file:
590594

591595
```php

src/PhpSpreadsheet/Reader/Csv.php

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,9 @@ class Csv extends BaseReader
103103
*/
104104
protected $preserveNumericFormatting = false;
105105

106+
/** @var bool */
107+
private $preserveNullString = false;
108+
106109
/**
107110
* Create a new CSV Reader instance.
108111
*/
@@ -300,9 +303,11 @@ private function openFileOrMemory(string $filename): void
300303
}
301304
}
302305

303-
public function setTestAutoDetect(bool $value): void
306+
public function setTestAutoDetect(bool $value): self
304307
{
305308
$this->testAutodetect = $value;
309+
310+
return $this;
306311
}
307312

308313
private function setAutoDetect(?string $value): ?string
@@ -390,7 +395,7 @@ private function loadStringOrFile(string $filename, Spreadsheet $spreadsheet, bo
390395
foreach ($rowData as $rowDatum) {
391396
$this->convertBoolean($rowDatum, $preserveBooleanString);
392397
$numberFormatMask = $this->convertFormattedNumber($rowDatum);
393-
if ($rowDatum !== '' && $this->readFilter->readCell($columnLetter, $currentRow)) {
398+
if (($rowDatum !== '' || $this->preserveNullString) && $this->readFilter->readCell($columnLetter, $currentRow)) {
394399
if ($this->contiguous) {
395400
if ($noOutputYet) {
396401
$noOutputYet = false;
@@ -625,4 +630,16 @@ public static function guessEncoding(string $filename, string $dflt = self::DEFA
625630

626631
return ($encoding === '') ? $dflt : $encoding;
627632
}
633+
634+
public function setPreserveNullString(bool $value): self
635+
{
636+
$this->preserveNullString = $value;
637+
638+
return $this;
639+
}
640+
641+
public function getPreserveNullString(): bool
642+
{
643+
return $this->preserveNullString;
644+
}
628645
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
3+
namespace PhpOffice\PhpSpreadsheetTests\Reader\Csv;
4+
5+
use PhpOffice\PhpSpreadsheet\Reader\Csv;
6+
use PHPUnit\Framework\TestCase;
7+
8+
class CsvIssue2840Test extends TestCase
9+
{
10+
public function testNullStringIgnore(): void
11+
{
12+
$reader = new Csv();
13+
self::assertFalse($reader->getPreserveNullString());
14+
$inputData = <<<EOF
15+
john,,doe,,
16+
mary,,jane,,
17+
EOF;
18+
$expected = [
19+
['john', null, 'doe'],
20+
['mary', null, 'jane'],
21+
];
22+
$spreadsheet = $reader->loadSpreadsheetFromString($inputData);
23+
$sheet = $spreadsheet->getActiveSheet();
24+
self::assertSame($expected, $sheet->toArray());
25+
$spreadsheet->disconnectWorksheets();
26+
}
27+
28+
public function testNullStringLoad(): void
29+
{
30+
$reader = new Csv();
31+
$reader->setPreserveNullString(true);
32+
$inputData = <<<EOF
33+
john,,doe,,
34+
mary,,jane,,
35+
EOF;
36+
$expected = [
37+
['john', '', 'doe', '', ''],
38+
['mary', '', 'jane', '', ''],
39+
];
40+
$spreadsheet = $reader->loadSpreadsheetFromString($inputData);
41+
$sheet = $spreadsheet->getActiveSheet();
42+
self::assertSame($expected, $sheet->toArray());
43+
$spreadsheet->disconnectWorksheets();
44+
}
45+
}

0 commit comments

Comments
 (0)