-
-
Notifications
You must be signed in to change notification settings - Fork 268
(feature) adds support for lazy importing of rows #374
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
f6f2908
4c2191d
e21873e
0cb07e5
a62636f
53d4624
212e544
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -3,6 +3,7 @@ | |||||||||||||||
| namespace Rap2hpoutre\FastExcel; | ||||||||||||||||
|
|
||||||||||||||||
| use Illuminate\Support\Collection; | ||||||||||||||||
| use Illuminate\Support\LazyCollection; | ||||||||||||||||
| use Illuminate\Support\Str; | ||||||||||||||||
| use OpenSpout\Common\Entity\Cell; | ||||||||||||||||
| use OpenSpout\Reader\SheetInterface; | ||||||||||||||||
|
|
@@ -39,7 +40,7 @@ abstract protected function setOptions(&$options); | |||||||||||||||
| * | ||||||||||||||||
| * @return Collection | ||||||||||||||||
| */ | ||||||||||||||||
| public function import($path, callable $callback = null) | ||||||||||||||||
| public function import($path, ?callable $callback = null) | ||||||||||||||||
| { | ||||||||||||||||
| $reader = $this->reader($path); | ||||||||||||||||
|
|
||||||||||||||||
|
|
@@ -54,6 +55,42 @@ public function import($path, callable $callback = null) | |||||||||||||||
| return collect($collection ?? []); | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| /** | ||||||||||||||||
| * Import file lazily using LazyCollection for memory efficiency. | ||||||||||||||||
| * | ||||||||||||||||
| * @param string $path | ||||||||||||||||
| * @param callable|null $callback | ||||||||||||||||
| * | ||||||||||||||||
| * @throws \OpenSpout\Common\Exception\UnsupportedTypeException | ||||||||||||||||
| * @throws \OpenSpout\Reader\Exception\ReaderNotOpenedException | ||||||||||||||||
| * @throws \OpenSpout\Common\Exception\IOException | ||||||||||||||||
| * | ||||||||||||||||
| * @return LazyCollection | ||||||||||||||||
| */ | ||||||||||||||||
| public function importLazy($path, ?callable $callback = null) | ||||||||||||||||
| { | ||||||||||||||||
| return new LazyCollection(function () use ($path, $callback) { | ||||||||||||||||
| $reader = $this->reader($path); | ||||||||||||||||
|
|
||||||||||||||||
| try { | ||||||||||||||||
| foreach ($reader->getSheetIterator() as $key => $sheet) { | ||||||||||||||||
| if ($this->sheet_number != $key) { | ||||||||||||||||
| continue; | ||||||||||||||||
| } | ||||||||||||||||
| if ($this->transpose) { | ||||||||||||||||
| // Fallback to non-lazy processing when transposing | ||||||||||||||||
| throw new \Exception('Transposing is not supported with lazy import.'); | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| yield from $this->importSheetGenerator($sheet, $callback); | ||||||||||||||||
| break; | ||||||||||||||||
| } | ||||||||||||||||
| } finally { | ||||||||||||||||
| $reader->close(); | ||||||||||||||||
| } | ||||||||||||||||
| }); | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| /** | ||||||||||||||||
| * @param string $path | ||||||||||||||||
| * @param callable|null $callback | ||||||||||||||||
|
|
@@ -64,7 +101,7 @@ public function import($path, callable $callback = null) | |||||||||||||||
| * | ||||||||||||||||
| * @return Collection | ||||||||||||||||
| */ | ||||||||||||||||
| public function importSheets($path, callable $callback = null) | ||||||||||||||||
| public function importSheets($path, ?callable $callback = null) | ||||||||||||||||
| { | ||||||||||||||||
| $reader = $this->reader($path); | ||||||||||||||||
|
|
||||||||||||||||
|
|
@@ -136,46 +173,75 @@ private function transposeCollection(array $array) | |||||||||||||||
| return $collection; | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| /** | ||||||||||||||||
| * Normalize a row according to start_row and headers. | ||||||||||||||||
| * - Updates $headers and $count_header when encountering header row. | ||||||||||||||||
| * - Pads/truncates rows to header size when headers exist. | ||||||||||||||||
| * - Returns combined associative row when headers exist, or the raw row when not. | ||||||||||||||||
| * - Returns null to skip processing (before start_row or header row itself). | ||||||||||||||||
| * | ||||||||||||||||
| * @param int $key | ||||||||||||||||
| * @param array $row | ||||||||||||||||
| * @param array $headers | ||||||||||||||||
| * @param int $count_header | ||||||||||||||||
| * | ||||||||||||||||
| * @return array|null | ||||||||||||||||
|
||||||||||||||||
| * @return array|null | |
| * @param int $k The current row index. | |
| * @param array $row The row data to normalize. | |
| * @param array &$headers Reference to the headers array, updated when header row is encountered. | |
| * @param int &$count_header Reference to the header count, updated when header row is encountered. | |
| * | |
| * @return array|null Returns an associative array if headers exist, the raw row if not, or null to skip processing. |
Copilot
AI
Aug 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The cell processing logic is duplicated between importSheet() and importSheetGenerator(). Consider extracting this into a private method like processCellValue(Cell $cell) to reduce code duplication.
| }, $rowAsObject->getCells()); | |
| $row = array_map([$this, 'processCellValue'], $rowAsObject->getCells()); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| <?php | ||
|
|
||
| namespace Rap2hpoutre\FastExcel\Tests; | ||
|
|
||
| use Illuminate\Support\LazyCollection; | ||
| use Rap2hpoutre\FastExcel\FastExcel; | ||
|
|
||
| class LazyImportTest extends TestCase | ||
| { | ||
| /** | ||
| * Ensure importLazy returns a LazyCollection and yields same data as import. | ||
| */ | ||
| public function testImportLazyXlsx() | ||
| { | ||
| $fe = new FastExcel(); | ||
| $lazy = $fe->importLazy(__DIR__.'/test1.xlsx'); | ||
| $this->assertInstanceOf(LazyCollection::class, $lazy); | ||
| // Materialize to compare with existing helper collection() | ||
| $this->assertEquals($this->collection(), $lazy->collect()); | ||
| } | ||
|
|
||
| /** | ||
| * Ensure importLazy supports callback mapping similar to import. | ||
| */ | ||
| public function testImportLazyWithCallback() | ||
| { | ||
| $fe = new FastExcel(); | ||
| $lazy = $fe->importLazy(__DIR__.'/test1.xlsx', function ($row) { | ||
| return [ | ||
| 'col1' => $row['col1'], | ||
| 'col2' => $row['col2'], | ||
| ]; | ||
| }); | ||
|
|
||
| $expected = (new FastExcel())->import(__DIR__.'/test1.xlsx', function ($row) { | ||
| return [ | ||
| 'col1' => $row['col1'], | ||
| 'col2' => $row['col2'], | ||
| ]; | ||
| }); | ||
|
|
||
| $this->assertEquals($expected, $lazy->collect()); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The error message should be more descriptive and use a specific exception type. Consider using InvalidArgumentException with a message like 'Transpose functionality is not compatible with lazy importing. Use import() method instead.'