Skip to content

Commit 09d0381

Browse files
committed
Allow to add Cell instances as data collection values
Apply StyleCI patch Fix Codacy Static Code Analysis Issues - The method exportOrDownload() has an NPath complexity of 300. The configured NPath comp1lexity threshold is 200. - The method exportOrDownload() has a Cyclomatic Complexity of 13. The configured cyclomatic complexity threshold is 10. - Avoid using static access to class '\OpenSpout\Common\Entity\Row' in method 'writeHeader'. Fix test with 'ubuntu-latest, 8.1, lowest' build Extract Cell and Row creations to single methods Remove static Cell creation from Exportable trait Eat this Codacy Static Code Analyzer Enough joking , Codacy
1 parent 05bc956 commit 09d0381

File tree

3 files changed

+229
-130
lines changed

3 files changed

+229
-130
lines changed

src/Exportable.php

Lines changed: 112 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,9 @@
66
use Illuminate\Support\Collection;
77
use Illuminate\Support\Str;
88
use InvalidArgumentException;
9+
use OpenSpout\Common\Entity\Cell;
910
use OpenSpout\Common\Entity\Row;
1011
use OpenSpout\Common\Entity\Style\Style;
11-
use OpenSpout\Writer\Common\Creator\WriterEntityFactory;
12-
use OpenSpout\Writer\XLSX\Writer;
1312

1413
/**
1514
* Trait Exportable.
@@ -20,31 +19,21 @@
2019
*/
2120
trait Exportable
2221
{
23-
/**
24-
* @var Style
25-
*/
26-
private $header_style;
27-
private $rows_style;
28-
29-
/**
30-
* @param \OpenSpout\Reader\ReaderInterface|\OpenSpout\Writer\WriterInterface $reader_or_writer
31-
*
32-
* @return mixed
33-
*/
34-
abstract protected function setOptions(&$reader_or_writer);
22+
private ?Style $header_style = null;
23+
private ?Style $rows_style = null;
3524

3625
/**
3726
* @param string $path
3827
* @param callable|null $callback
3928
*
40-
* @throws \OpenSpout\Common\Exception\InvalidArgumentException
4129
* @throws \OpenSpout\Common\Exception\UnsupportedTypeException
4230
* @throws \OpenSpout\Writer\Exception\WriterNotOpenedException
4331
* @throws \OpenSpout\Common\Exception\IOException
32+
* @throws \OpenSpout\Common\Exception\InvalidArgumentException
4433
*
4534
* @return string
4635
*/
47-
public function export($path, callable $callback = null)
36+
public function export(string $path, callable $callback = null)
4837
{
4938
self::exportOrDownload($path, 'openToFile', $callback);
5039

@@ -55,10 +44,10 @@ public function export($path, callable $callback = null)
5544
* @param $path
5645
* @param callable|null $callback
5746
*
58-
* @throws \OpenSpout\Common\Exception\InvalidArgumentException
5947
* @throws \OpenSpout\Common\Exception\UnsupportedTypeException
6048
* @throws \OpenSpout\Writer\Exception\WriterNotOpenedException
6149
* @throws \OpenSpout\Common\Exception\IOException
50+
* @throws \OpenSpout\Common\Exception\InvalidArgumentException
6251
*
6352
* @return \Symfony\Component\HttpFoundation\StreamedResponse|string
6453
*/
@@ -74,6 +63,37 @@ public function download($path, callable $callback = null)
7463
return '';
7564
}
7665

66+
/**
67+
* @param Style $style
68+
*
69+
* @return Exportable
70+
*/
71+
public function headerStyle(Style $style)
72+
{
73+
$this->header_style = $style;
74+
75+
return $this;
76+
}
77+
78+
/**
79+
* @param Style $style
80+
*
81+
* @return Exportable
82+
*/
83+
public function rowsStyle(Style $style)
84+
{
85+
$this->rows_style = $style;
86+
87+
return $this;
88+
}
89+
90+
/**
91+
* @param \OpenSpout\Reader\ReaderInterface|\OpenSpout\Writer\WriterInterface $reader_or_writer
92+
*
93+
* @return mixed
94+
*/
95+
abstract protected function setOptions(&$reader_or_writer);
96+
7797
/**
7898
* @param $path
7999
* @param string $function
@@ -85,27 +105,15 @@ public function download($path, callable $callback = null)
85105
* @throws \OpenSpout\Writer\Exception\WriterNotOpenedException
86106
* @throws \OpenSpout\Common\Exception\SpoutException
87107
*/
88-
private function exportOrDownload($path, $function, callable $callback = null)
108+
private function exportOrDownload($path, string $function, callable $callback = null)
89109
{
90-
if (Str::endsWith($path, 'csv')) {
91-
$options = new \OpenSpout\Writer\CSV\Options();
92-
$writer = new \OpenSpout\Writer\CSV\Writer($options);
93-
} elseif (Str::endsWith($path, 'ods')) {
94-
$options = new \OpenSpout\Writer\ODS\Options();
95-
$writer = new \OpenSpout\Writer\ODS\Writer($options);
96-
} else {
97-
$options = new \OpenSpout\Writer\XLSX\Options();
98-
$writer = new \OpenSpout\Writer\XLSX\Writer($options);
99-
}
100-
101-
$this->setOptions($options);
102-
/* @var \OpenSpout\Writer\WriterInterface $writer */
110+
/* @var \OpenSpout\Writer\WriterInterface $writer */
111+
$writer = $this->prepareWriter($path);
112+
$this->setOptions($writer);
103113
$writer->$function($path);
104114

105-
$has_sheets = ($writer instanceof \OpenSpout\Writer\XLSX\Writer || $writer instanceof \OpenSpout\Writer\ODS\Writer);
106-
107115
// It can export one sheet (Collection) or N sheets (SheetCollection)
108-
$data = $this->transpose ? $this->transposeData() : ($this->data instanceof SheetCollection ? $this->data : collect([$this->data]));
116+
$data = $this->prepareDataForExport();
109117

110118
foreach ($data as $key => $collection) {
111119
if ($collection instanceof Collection) {
@@ -120,19 +128,48 @@ private function exportOrDownload($path, $function, callable $callback = null)
120128
if (is_string($key)) {
121129
$writer->getCurrentSheet()->setName($key);
122130
}
123-
if ($has_sheets && $data->keys()->last() !== $key) {
131+
if ($this->hasSheets($writer) && $data->keys()->last() !== $key) {
124132
$writer->addNewSheetAndMakeItCurrent();
125133
}
126134
}
127135
$writer->close();
128136
}
129137

138+
private function prepareWriter($path): \OpenSpout\Writer\WriterInterface
139+
{
140+
if (Str::endsWith($path, 'csv')) {
141+
$writer = new \OpenSpout\Writer\CSV\Writer(new \OpenSpout\Writer\CSV\Options());
142+
} elseif (Str::endsWith($path, 'ods')) {
143+
$writer = new \OpenSpout\Writer\ODS\Writer(new \OpenSpout\Writer\ODS\Options());
144+
} else {
145+
$writer = new \OpenSpout\Writer\XLSX\Writer(new \OpenSpout\Writer\XLSX\Options());
146+
}
147+
148+
return $writer;
149+
}
150+
151+
private function hasSheets(\OpenSpout\Writer\WriterInterface $writer): bool
152+
{
153+
return $writer instanceof \OpenSpout\Writer\XLSX\Writer || $writer instanceof \OpenSpout\Writer\ODS\Writer;
154+
}
155+
156+
private function prepareDataForExport(): SheetCollection|array|Generator|Collection|null
157+
{
158+
return $this->transpose
159+
? $this->transposeData()
160+
: (
161+
$this->data instanceof SheetCollection
162+
? $this->data
163+
: collect([$this->data])
164+
);
165+
}
166+
130167
/**
131168
* Transpose data from rows to columns.
132169
*
133170
* @return SheetCollection
134171
*/
135-
private function transposeData()
172+
private function transposeData(): SheetCollection
136173
{
137174
$data = $this->data instanceof SheetCollection ? $this->data : collect([$this->data]);
138175
$transposedData = [];
@@ -164,39 +201,22 @@ private function writeRowsFromCollection($writer, Collection $collection, ?calla
164201
return $callback($value);
165202
});
166203
}
204+
167205
// Prepare collection (i.e remove non-string)
168-
$this->prepareCollection($collection);
206+
// and transform into collection of row cells collections
207+
//$this->transformCollection($collection);
208+
169209
// Add header row.
170210
if ($this->with_header) {
171-
$this->writeHeader($writer, $collection->first());
172-
}
173-
174-
// createRowFromArray works only with arrays
175-
if (!is_array($collection->first())) {
176-
$collection = $collection->map(function ($value) {
177-
return $value->toArray();
178-
});
211+
$this->writeHeader($writer, $this->transformRow($collection->first()));
179212
}
180213

181-
// is_array($first_row) ? $first_row : $first_row->toArray())
182-
$all_rows = $collection->map(function ($value) {
183-
return Row::fromValues($value);
184-
})->toArray();
185-
if ($this->rows_style) {
186-
$this->addRowsWithStyle($writer, $all_rows, $this->rows_style);
187-
} else {
188-
$writer->addRows($all_rows);
189-
}
190-
}
191-
192-
private function addRowsWithStyle($writer, $all_rows, $rows_style)
193-
{
194-
$styled_rows = [];
195-
// Style rows one by one
196-
foreach ($all_rows as $row) {
197-
$styled_rows[] = Row::fromValues($row->toArray(), $rows_style);
198-
}
199-
$writer->addRows($styled_rows);
214+
// Add rows
215+
$writer->addRows(
216+
$collection->map(function ($row) {
217+
return $this->createRow($this->transformRow($row), $this->rows_style);
218+
})->toArray()
219+
);
200220
}
201221

202222
private function writeRowsFromGenerator($writer, Generator $generator, ?callable $callback = null)
@@ -208,14 +228,17 @@ private function writeRowsFromGenerator($writer, Generator $generator, ?callable
208228
}
209229

210230
// Prepare row (i.e remove non-string)
211-
$item = $this->transformRow($item);
231+
// and transform to collection of Cells
232+
$row_cells = $this->transformRow($item);
212233

213234
// Add header row.
214235
if ($this->with_header && $key === 0) {
215-
$this->writeHeader($writer, $item);
236+
$this->writeHeader($writer, $row_cells);
216237
}
217238
// Write rows (one by one).
218-
$writer->addRow(Row::fromValues($item->toArray(), $this->rows_style));
239+
$writer->addRow(
240+
$this->createRow($row_cells, $this->rows_style)
241+
);
219242
}
220243
}
221244

@@ -229,82 +252,42 @@ private function writeRowsFromArray($writer, array $array, ?callable $callback =
229252
}
230253
}
231254

232-
private function writeHeader($writer, $first_row)
255+
private function writeHeader($writer, array $first_row)
233256
{
234-
if ($first_row === null) {
235-
return;
236-
}
237-
238-
$keys = array_keys(is_array($first_row) ? $first_row : $first_row->toArray());
239-
$writer->addRow(Row::fromValues($keys));
240-
// $writer->addRow(WriterEntityFactory::createRowFromArray($keys, $this->header_style));
257+
$writer->addRow(
258+
$this->createRow($this->transformRow(array_keys($first_row)), $this->header_style)
259+
);
241260
}
242261

243262
/**
244-
* Prepare collection by removing non string if required.
245-
*/
246-
protected function prepareCollection(Collection $collection)
247-
{
248-
$need_conversion = false;
249-
$first_row = $collection->first();
250-
251-
if (!$first_row) {
252-
return;
253-
}
254-
255-
foreach ($first_row as $item) {
256-
if (!is_string($item)) {
257-
$need_conversion = true;
258-
}
259-
}
260-
if ($need_conversion) {
261-
$this->transform($collection);
262-
}
263-
}
264-
265-
/**
266-
* Transform the collection.
263+
* Transform one row (i.e remove non-string).
264+
* into array of Cells.
267265
*/
268-
private function transform(Collection $collection)
266+
private function transformRow($data): array
269267
{
270-
$collection->transform(function ($data) {
271-
return $this->transformRow($data);
272-
});
268+
return collect($data)
269+
->filter(function ($value) {
270+
return $this->isValidValue($value);
271+
})->map(function ($value) {
272+
return $this->createCell($value, null);
273+
})->toArray();
273274
}
274275

275-
/**
276-
* Transform one row (i.e remove non-string).
277-
*/
278-
private function transformRow($data)
276+
private function isValidValue($value): bool
279277
{
280-
return collect($data)->map(function ($value) {
281-
return is_null($value) ? (string) $value : $value;
282-
})->filter(function ($value) {
283-
return is_string($value) || is_int($value) || is_float($value);
284-
});
278+
return is_string($value) || is_int($value) || is_float($value)
279+
|| is_null($value) || $value instanceof Cell;
285280
}
286281

287-
/**
288-
* @param Style $style
289-
*
290-
* @return Exportable
291-
*/
292-
public function headerStyle(Style $style)
282+
private function createCell($value, ?Style $style): Cell
293283
{
294-
$this->header_style = $style;
295-
296-
return $this;
284+
return ($value instanceof Cell)
285+
? $value
286+
: Cell::fromValue($value, $style);
297287
}
298288

299-
/**
300-
* @param Style $style
301-
*
302-
* @return Exportable
303-
*/
304-
public function rowsStyle(Style $style)
289+
private function createRow(array $row_cells, ?Style $row_style): Row
305290
{
306-
$this->rows_style = $style;
307-
308-
return $this;
291+
return new Row($row_cells, $row_style);
309292
}
310293
}

src/FastExcel.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ public function configureReaderUsing(?callable $callback = null)
170170
}
171171

172172
/**
173-
* Configure the underlying Spout Reader using a callback.
173+
* Configure the underlying Spout Writer using a callback.
174174
*
175175
* @param callable|null $callback
176176
*

0 commit comments

Comments
 (0)