diff --git a/README.md b/README.md index a4c443d..58beb31 100644 --- a/README.md +++ b/README.md @@ -135,7 +135,7 @@ $rows = SimpleExcelReader::create($pathToXlsx) If you want to check if a sheet exists, use the `hasSheet()` method. -```php +```php $hasSheet = SimpleExcelReader::create($pathToXlsx) ->hasSheet("sheet1"); ``` @@ -159,7 +159,7 @@ If your file has headers that are not on the first line, you can use the `header to indicate the line at which the headers are present. Any data above this line will be discarded from the result. -`headerOnRow` accepts the line number as an argument, starting at 0. Blank lines are not counted. +`headerOnRow` accepts the line number as an argument, starting at 0. Blank lines are not counted. Since blank lines will not be counted, this method is mostly useful for files that include formatting above the actual dataset, which can be the case with Excel files. @@ -291,6 +291,26 @@ $rows = SimpleExcelReader::create($pathToXlsx) ->getRows(); ``` +#### Preserve date formatting + +By default, when reading a spreadsheet with dates or times, the values are returned as `DateTimeImmutable` objects. To return a formatted date (e.g., “9/20/2024”) instead, use the `preserveDateTimeFormatting` method. The date format will match what’s specified in the spreadsheet. + +```php +$rows = SimpleExcelReader::create($pathToXlsx) + ->preserveDateTimeFormatting() + ->getRows(); +``` + +#### Preserve empty rows + +You can preserve empty rows by using the `preserveEmptyRows` method. + +```php +$rows = SimpleExcelReader::create($pathToXlsx) + ->preserveEmptyRows() + ->getRows(); +``` + ### Writing files Here's how you can write a CSV file: @@ -367,12 +387,12 @@ foreach (range(1, 10_000) as $i) { 'first_name' => 'John', 'last_name' => 'Doe', ]); - + if ($i % 1000 === 0) { flush(); // Flush the buffer every 1000 rows } } - + $writer->toBrowser(); ``` @@ -383,7 +403,7 @@ use Spatie\SimpleExcel\SimpleExcelWriter; use OpenSpout\Common\Entity\Row; $writer = SimpleExcelWriter::streamDownload('user-list.xlsx', function ($writerCallback, $downloadName) { - + $writerCallback->openToBrowser($downloadName); $writerCallback->addRow(Row::fromValues([ @@ -467,7 +487,7 @@ $border = new Border( new BorderPart(Border::RIGHT, Color::LIGHT_BLUE, Border::WIDTH_THIN, Border::STYLE_SOLID), new BorderPart(Border::TOP, Color::LIGHT_BLUE, Border::WIDTH_THIN, Border::STYLE_SOLID) ); - + $style = (new Style()) ->setFontBold() ->setFontSize(15) @@ -514,14 +534,14 @@ $writer = SimpleExcelWriter::create($pathToXlsx); Posts::all()->each(function (Post $post) use ($writer) { $writer->nameCurrentSheet($post->title); - + $post->comments->each(function (Comment $comment) use ($writer) { $writer->addRow([ 'comment' => $comment->comment, 'author' => $comment->author, ]); }); - + if(!$post->is($posts->last())) { $writer->addNewSheetAndMakeItCurrent(); } diff --git a/src/SimpleExcelReader.php b/src/SimpleExcelReader.php index 4269657..c897ec0 100644 --- a/src/SimpleExcelReader.php +++ b/src/SimpleExcelReader.php @@ -12,6 +12,8 @@ use OpenSpout\Reader\ReaderInterface; use OpenSpout\Reader\RowIteratorInterface; use OpenSpout\Reader\SheetInterface; +use OpenSpout\Reader\XLSX\Reader as XLSXReader; +use OpenSpout\Reader\XLSX\Options as XLSXOptions; class SimpleExcelReader { @@ -33,6 +35,7 @@ class SimpleExcelReader protected int $limit = 0; protected bool $useLimit = false; protected CSVOptions $csvOptions; + protected XLSXOptions $xlsxOptions; public static function create(string $file, string $type = ''): static { @@ -42,6 +45,7 @@ public static function create(string $file, string $type = ''): static public function __construct(protected string $path, protected string $type = '') { $this->csvOptions = new CSVOptions(); + $this->xlsxOptions = new XLSXOptions(); $this->reader = $this->type ? ReaderFactory::createFromType($this->type) : @@ -52,7 +56,11 @@ public function __construct(protected string $path, protected string $type = '') protected function setReader(): void { - $options = $this->reader instanceof CSVReader ? $this->csvOptions : null; + $options = match (true) { + $this->reader instanceof CSVReader => $this->csvOptions, + $this->reader instanceof XLSXReader => $this->xlsxOptions, + default => null, + }; $this->reader = empty($this->type) ? ReaderFactory::createFromFile($this->path, $options) : @@ -112,6 +120,24 @@ public function useEncoding(string $encoding): self return $this; } + public function preserveDateTimeFormatting(): self + { + if ($this->reader instanceof XLSXReader) { + $this->xlsxOptions->SHOULD_FORMAT_DATES = true; + } + + return $this; + } + + public function preserveEmptyRows(): self + { + if ($this->reader instanceof XLSXReader) { + $this->xlsxOptions->SHOULD_PRESERVE_EMPTY_ROWS = true; + } + + return $this; + } + public function trimHeaderRow(string $characters = null): self { $this->trimHeader = true; diff --git a/tests/SimpleExcelReaderTest.php b/tests/SimpleExcelReaderTest.php index 7d6505f..e3916f2 100644 --- a/tests/SimpleExcelReaderTest.php +++ b/tests/SimpleExcelReaderTest.php @@ -618,3 +618,28 @@ function () { ['お名前' => '太郎', 'お名前(フリガナ)' => 'タロウ'], ]); }); + +it('can preserve date formatting', function () { + $reader = SimpleExcelReader::create(getStubPath('formatted_dates.xlsx')); + + $defaultDates = $reader->getRows()->pluck('created_at')->Toarray(); + + expect($defaultDates[0])->toBeInstanceOf(DateTimeImmutable::class); + expect($defaultDates[1])->toBeInstanceOf(DateTimeImmutable::class); + + $formattedDates = $reader + ->preserveDateTimeFormatting() + ->getRows() + ->pluck('created_at') + ->toArray(); + + expect($formattedDates[0])->toEqual('9/20/2024'); + expect($formattedDates[1])->toEqual('9/19/2024'); +}); + +it('can preserve empty rows', function () { + $reader = SimpleExcelReader::create(getStubPath('empty_rows.xlsx')); + + expect($reader->getRows()->count())->toBe(2); + expect($reader->preserveEmptyRows()->getRows()->count())->toBe(3); +}); diff --git a/tests/stubs/empty_rows.xlsx b/tests/stubs/empty_rows.xlsx new file mode 100644 index 0000000..93ac999 Binary files /dev/null and b/tests/stubs/empty_rows.xlsx differ diff --git a/tests/stubs/formatted_dates.xlsx b/tests/stubs/formatted_dates.xlsx new file mode 100644 index 0000000..2498115 Binary files /dev/null and b/tests/stubs/formatted_dates.xlsx differ