Skip to content

Commit d546d7c

Browse files
committed
feature: excel adapter loader
1 parent 16b069e commit d546d7c

File tree

13 files changed

+1589
-5
lines changed

13 files changed

+1589
-5
lines changed

documentation/components/adapters/excel.md

Lines changed: 139 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Excel Adapter
1+
# Excel Adapter
22

33
- [⬅️️ Back](/documentation/introduction.md)
44
- [📦Packagist](https://packagist.org/packages/flow-php/etl-adapter-excel)
@@ -20,6 +20,9 @@ developers dealing with Excel in large-scale and data-intensive projects. With F
2020
managing Excel data within your ETL workflows becomes a more simplified and efficient task, perfectly aligning
2121
with the robust and adaptable nature of the Flow PHP ecosystem.
2222

23+
> **Note:** This adapter only supports local filesystem paths due to limitations of the underlying OpenSpout library.
24+
> Remote filesystems (S3, Azure Blob Storage, etc.) are not supported.
25+
2326
## Installation
2427

2528
```
@@ -66,3 +69,138 @@ $rows = data_frame()
6669
)
6770
->fetch();
6871
```
72+
73+
## Loader
74+
75+
### Basic Usage
76+
77+
```php
78+
<?php
79+
80+
data_frame()
81+
->read($extractor)
82+
->write(to_excel('path/to/output.xlsx'))
83+
->run();
84+
```
85+
86+
### ODS Format
87+
88+
```php
89+
<?php
90+
91+
use Flow\ETL\Adapter\Excel\ExcelWriter;
92+
93+
data_frame()
94+
->read($extractor)
95+
->write(to_excel('path/to/output.ods')->withWriter(ExcelWriter::ODS))
96+
->run();
97+
```
98+
99+
### Custom Sheet Name
100+
101+
```php
102+
<?php
103+
104+
data_frame()
105+
->read($extractor)
106+
->write(to_excel('path/to/output.xlsx')->withSheetName('MyData'))
107+
->run();
108+
```
109+
110+
### Dynamic Sheet Names from Entry
111+
112+
Route rows to different sheets based on entry values:
113+
114+
```php
115+
<?php
116+
117+
$loader = to_excel('path/to/output.xlsx')
118+
->withSheetNameFromEntry('category');
119+
120+
data_frame()
121+
->read($extractor)
122+
->write($loader)
123+
->run();
124+
```
125+
126+
### Without Header Row
127+
128+
```php
129+
<?php
130+
131+
data_frame()
132+
->read($extractor)
133+
->write(to_excel('path/to/output.xlsx')->withHeader(false))
134+
->run();
135+
```
136+
137+
### Header Styling
138+
139+
```php
140+
<?php
141+
142+
use OpenSpout\Common\Entity\Style\Style;
143+
144+
$headerStyle = new Style(fontBold: true);
145+
146+
$loader = to_excel('path/to/output.xlsx')
147+
->withHeaderStyle($headerStyle);
148+
149+
data_frame()
150+
->read($extractor)
151+
->write($loader)
152+
->run();
153+
```
154+
155+
### Cell Styling
156+
157+
Apply custom styles to individual cells based on entry values:
158+
159+
```php
160+
<?php
161+
162+
use Flow\ETL\Adapter\Excel\CellStyler;
163+
use Flow\ETL\Row\Entry;
164+
use OpenSpout\Common\Entity\Style\Style;
165+
166+
$cellStyler = new class implements CellStyler {
167+
public function style(Entry $entry, int $rowNumber, int $columnIndex, string $sheetName): ?Style
168+
{
169+
// Make first column bold
170+
if ($columnIndex === 0) {
171+
return new Style(fontBold: true);
172+
}
173+
174+
return null;
175+
}
176+
};
177+
178+
$loader = to_excel('path/to/output.xlsx')
179+
->withCellStyler($cellStyler);
180+
181+
data_frame()
182+
->read($extractor)
183+
->write($loader)
184+
->run();
185+
```
186+
187+
### Custom Writer Options
188+
189+
For advanced configuration, pass OpenSpout options directly:
190+
191+
```php
192+
<?php
193+
194+
use OpenSpout\Writer\XLSX\Options as XlsxOptions;
195+
196+
$options = new XlsxOptions(
197+
SHOULD_USE_INLINE_STRINGS: false,
198+
DEFAULT_COLUMN_WIDTH: 15.0,
199+
DEFAULT_ROW_HEIGHT: 20.0,
200+
);
201+
202+
data_frame()
203+
->read($extractor)
204+
->write(to_excel('path/to/output.xlsx')->withWriterOptions($options))
205+
->run();
206+
```
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Flow\ETL\Adapter\Excel;
6+
7+
use Flow\ETL\Row\Entry;
8+
use OpenSpout\Common\Entity\Style\Style;
9+
10+
interface CellStyler
11+
{
12+
/**
13+
* Return a Style for the given cell, or null for default styling.
14+
*
15+
* @param Entry<mixed> $entry the entry being written
16+
* @param int $rowNumber the 1-based row number in the sheet (1 = first data row, not header)
17+
* @param int $columnIndex the 0-based column index
18+
* @param string $sheetName the name of the sheet being written to
19+
*/
20+
public function style(Entry $entry, int $rowNumber, int $columnIndex, string $sheetName) : ?Style;
21+
}

src/adapter/etl-adapter-excel/src/Flow/ETL/Adapter/Excel/DSL/functions.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use function Flow\Filesystem\DSL\path_real;
88
use Flow\ETL\{Adapter\Excel\ExcelExtractor,
9+
Adapter\Excel\ExcelLoader,
910
Adapter\Excel\Function\IsValidExcelSheetName,
1011
Attribute\DocumentationDSL,
1112
Attribute\DocumentationExample,
@@ -22,6 +23,13 @@ function from_excel(
2223
return new ExcelExtractor(\is_string($path) ? path_real($path) : $path);
2324
}
2425

26+
#[DocumentationDSL(module: Module::EXCEL, type: DSLType::LOADER)]
27+
#[DocumentationExample(topic: 'data_frame', example: 'data_writing', option: 'excel')]
28+
function to_excel(string|Path $path) : ExcelLoader
29+
{
30+
return new ExcelLoader(\is_string($path) ? path_real($path) : $path);
31+
}
32+
2533
#[DocumentationDSL(module: Module::EXCEL, type: DSLType::HELPER)]
2634
function is_valid_excel_sheet_name(string|ScalarFunction $sheet_name) : IsValidExcelSheetName
2735
{

0 commit comments

Comments
 (0)