From 917080fce419f62ac4bcb703775f1a3b549768a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nenad=20=C5=BDivanovi=C4=87?= Date: Sat, 20 Mar 2021 13:25:18 +0100 Subject: [PATCH] Upgrade to Box Spout 3 and prepare for v2 (#6) * Dropped support for PHP 7.1 * Added support for PHP 8 * Upgraded Box Spout to v3 --- .github/workflows/run-tests.yml | 16 +++++----- README.md | 1 + composer.json | 4 +-- src/Factories/ReaderFactory.php | 6 ++-- src/Factories/WriterFactory.php | 12 ++++++-- src/Imports/HeadingRowExtractor.php | 2 +- src/Imports/ProcessesRows.php | 2 +- src/Simplesheet.php | 2 +- src/Writers/CsvWriter.php | 42 +++++++++++++++++---------- src/Writers/Sheet.php | 14 ++++++--- tests/Concerns/FromCollectionTest.php | 4 ++- tests/TestCase.php | 8 +++-- 12 files changed, 71 insertions(+), 42 deletions(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 483ab05..6dde4f5 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -14,7 +14,7 @@ jobs: strategy: matrix: - php: [7.1, 7.2, 7.3, 7.4] + php: [7.2, 7.3, 7.4, 8.0] laravel: [8, 7, 6, 5.8, 5.7, 5.6, 5.5] dependency-version: [prefer-stable] os: [ubuntu-latest] @@ -36,12 +36,14 @@ jobs: exclude: - laravel: 8 php: 7.2 - - laravel: 8 - php: 7.1 - - laravel: 7 - php: 7.1 - - laravel: 6 - php: 7.1 + - laravel: 5.8 + php: 8.0 + - laravel: 5.7 + php: 8.0 + - laravel: 5.6 + php: 8.0 + - laravel: 5.5 + php: 8.0 name: PHP${{ matrix.php }} - L${{ matrix.laravel }} diff --git a/README.md b/README.md index 732660f..d4ed902 100644 --- a/README.md +++ b/README.md @@ -52,3 +52,4 @@ Versions will be supported for a limited amount of time. | Version | Laravel Version | Php Version | Box Spout | Support | | ------- | --------------- | ----------- | --------- | ---------------------- | | 1.* | 5.5 - 8.* | ^7.1 | ^2.7 | Bug and security fixes | +| 2.* | 5.5 - 8.* | >=7.2 | ^3.2 | New features | diff --git a/composer.json b/composer.json index c30ad76..dd0bd22 100644 --- a/composer.json +++ b/composer.json @@ -11,8 +11,8 @@ ], "require": { "ext-json": "*", - "php": "^7.1", - "box/spout": "^2.7", + "php": "^7.2|^8.0", + "box/spout": "^3.2", "illuminate/support": "^5.5|^6.0|^7.0|^8.0" }, "require-dev": { diff --git a/src/Factories/ReaderFactory.php b/src/Factories/ReaderFactory.php index 8b9b6fc..e5ff8b1 100644 --- a/src/Factories/ReaderFactory.php +++ b/src/Factories/ReaderFactory.php @@ -3,8 +3,8 @@ namespace Nikazooz\Simplesheet\Factories; use Box\Spout\Common\Type; +use Box\Spout\Reader\Common\Creator\ReaderFactory as SpoutReaderFactory; use Box\Spout\Reader\CSV\Reader as CsvReader; -use Box\Spout\Reader\ReaderFactory as SpoutReaderFactory; use Box\Spout\Reader\ReaderInterface; use Nikazooz\Simplesheet\Concerns\MapsCsvSettings; use Nikazooz\Simplesheet\Concerns\WithCustomCsvSettings; @@ -31,12 +31,12 @@ public static function make($type, $import): ReaderInterface protected static function makeUnconfiguredReader($type) { if (Simplesheet::TSV === $type) { - return SpoutReaderFactory::create(Type::CSV) + return SpoutReaderFactory::createFromType(Type::CSV) ->setFieldDelimiter("\t") ->setShouldPreserveEmptyRows(true); } - return SpoutReaderFactory::create($type)->setShouldPreserveEmptyRows(true); + return SpoutReaderFactory::createFromType($type)->setShouldPreserveEmptyRows(true); } /** diff --git a/src/Factories/WriterFactory.php b/src/Factories/WriterFactory.php index 0c19769..0496003 100644 --- a/src/Factories/WriterFactory.php +++ b/src/Factories/WriterFactory.php @@ -2,8 +2,10 @@ namespace Nikazooz\Simplesheet\Factories; +use Box\Spout\Common\Creator\HelperFactory; use Box\Spout\Common\Helper\GlobalFunctionsHelper; -use Box\Spout\Writer\WriterFactory as SpoutWriterFactory; +use Box\Spout\Reader\CSV\Manager\OptionsManager; +use Box\Spout\Writer\Common\Creator\WriterFactory as SpoutWriterFactory; use Box\Spout\Writer\WriterInterface; use Nikazooz\Simplesheet\Concerns\MapsCsvSettings; use Nikazooz\Simplesheet\Concerns\WithCustomCsvSettings; @@ -30,7 +32,7 @@ public static function make($type, $export): WriterInterface return static::makeCsvWriter($type, $export); } - return SpoutWriterFactory::create($type); + return SpoutWriterFactory::createFromType($type); } /** @@ -38,7 +40,11 @@ public static function make($type, $export): WriterInterface */ protected static function makeCsvWriter($type, $export): WriterInterface { - $writer = (new CsvWriter())->setGlobalFunctionsHelper(new GlobalFunctionsHelper()); + $writer = (new CsvWriter( + new OptionsManager(), + new GlobalFunctionsHelper(), + new HelperFactory() + )); static::applyCsvSettings(static::getCsvConfig()); diff --git a/src/Imports/HeadingRowExtractor.php b/src/Imports/HeadingRowExtractor.php index 41d1980..0aab638 100644 --- a/src/Imports/HeadingRowExtractor.php +++ b/src/Imports/HeadingRowExtractor.php @@ -64,7 +64,7 @@ public static function extract(SheetInterface $sheet, $importable): array break; } - $rows[] = $row; + $rows[] = $row->toArray(); } $headingRow = head($rows); diff --git a/src/Imports/ProcessesRows.php b/src/Imports/ProcessesRows.php index ea8969e..ac0b47f 100644 --- a/src/Imports/ProcessesRows.php +++ b/src/Imports/ProcessesRows.php @@ -47,7 +47,7 @@ protected function iterateRowsBetween($sheet, int $startRow, int $endRow = null) break; } - yield $rowNumber => $row; + yield $rowNumber => $row->toArray(); } } diff --git a/src/Simplesheet.php b/src/Simplesheet.php index f0cbf7b..86b94bc 100644 --- a/src/Simplesheet.php +++ b/src/Simplesheet.php @@ -124,7 +124,7 @@ public function raw($export, string $writerType) * @param object $export * @param string $fileName * @param string|null $writerType - * @return string + * @return \Nikazooz\Simplesheet\Files\TemporaryFile * * @throws \Nikazooz\Simplesheet\NoTypeDetectedException */ diff --git a/src/Writers/CsvWriter.php b/src/Writers/CsvWriter.php index e930a5c..8f9837a 100644 --- a/src/Writers/CsvWriter.php +++ b/src/Writers/CsvWriter.php @@ -2,7 +2,9 @@ namespace Nikazooz\Simplesheet\Writers; +use Box\Spout\Common\Entity\Row; use Box\Spout\Common\Exception\IOException; +use Box\Spout\Writer\Common\Entity\Options; use Box\Spout\Writer\CSV\Writer; class CsvWriter extends Writer @@ -75,7 +77,7 @@ protected function openWriter() if ($this->includeSeparatorLine) { $this->globalFunctionsHelper->fputs( $this->filePointer, - 'sep='.$this->fieldDelimiter.$this->lineEnding + 'sep='.$this->getFieldDelimiter().$this->lineEnding ); } } @@ -83,34 +85,32 @@ protected function openWriter() /** * Adds data to the currently opened writer. * - * @param array $dataRow Array containing data to be written. - * Example $dataRow = ['data1', 1234, null, '', 'data5']; + * @param \Box\Spout\Common\Entity\Row $row * @param \Box\Spout\Writer\Style\Style $style Ignored here since CSV does not support styling. * @return void * @throws \Box\Spout\Common\Exception\IOException If unable to write data */ - protected function addRowToWriter(array $dataRow, $style) + protected function addRowToWriter(Row $row) { if (PHP_EOL !== $this->lineEnding) { - return $this->customAddRowToWriter($dataRow); + return $this->customAddRowToWriter($row); } - parent::addRowToWriter($dataRow, $style); + parent::addRowToWriter($row); } /** * Adds data to the currently opened writer. * - * @param array $dataRow Array containing data to be written. - * Example $dataRow = ['data1', 1234, null, '', 'data5']; + * @param \Box\Spout\Common\Entity\Row $row * @return void * @throws \Box\Spout\Common\Exception\IOException If unable to write data */ - protected function customAddRowToWriter($dataRow) + protected function customAddRowToWriter(Row $row) { $wasWriteSuccessful = $this->globalFunctionsHelper->fputs( $this->filePointer, - $this->prepareRowForWriting($dataRow) + $this->prepareRowForWriting($row) ); if ($wasWriteSuccessful === false) { @@ -124,14 +124,14 @@ protected function customAddRowToWriter($dataRow) } /** - * @param array $row + * @param \Box\Spout\Common\Entity\Row $row * @return string */ - protected function prepareRowForWriting($row) + protected function prepareRowForWriting(Row $row) { - return implode($this->fieldDelimiter, array_map(function ($cell) { + return implode($this->getFieldDelimiter(), array_map(function ($cell) { return $this->encloseString($cell); - }, $row)).$this->lineEnding; + }, $row->toArray())).$this->lineEnding; } /** @@ -145,9 +145,19 @@ protected function encloseString($str) } return vsprintf('%s%s%s', [ - $this->fieldEnclosure, + $this->getFieldEnclosure(), addslashes($str), - $this->fieldEnclosure, + $this->getFieldEnclosure(), ]); } + + protected function getFieldDelimiter() + { + return $this->optionsManager->getOption(Options::FIELD_DELIMITER); + } + + protected function getFieldEnclosure() + { + return $this->optionsManager->getOption(Options::FIELD_ENCLOSURE); + } } diff --git a/src/Writers/Sheet.php b/src/Writers/Sheet.php index 44333d6..5a92beb 100644 --- a/src/Writers/Sheet.php +++ b/src/Writers/Sheet.php @@ -2,8 +2,10 @@ namespace Nikazooz\Simplesheet\Writers; -use Box\Spout\Writer\AbstractMultiSheetsWriter; +use Box\Spout\Common\Entity\Cell; +use Box\Spout\Common\Entity\Row; use Box\Spout\Writer\WriterInterface; +use Box\Spout\Writer\WriterMultiSheetsAbstract; use Illuminate\Contracts\Support\Arrayable; use Illuminate\Support\Collection; use Nikazooz\Simplesheet\Concerns\FromArray; @@ -170,7 +172,7 @@ public static function mapArraybleRow($row) { // When dealing with eloquent models, we'll skip the relations // as we won't be able to display them anyway. - if (method_exists($row, 'attributesToArray')) { + if (is_object($row) && method_exists($row, 'attributesToArray')) { return $row->attributesToArray(); } @@ -194,7 +196,11 @@ public static function mapArraybleRow($row) */ public function appendRow($row) { - $this->spoutWriter->addRow($row); + $cells = array_map(function ($value) { + return new Cell($value); + }, $row); + + $this->spoutWriter->addRow(new Row($cells, null)); } /** @@ -234,7 +240,7 @@ protected function multipleSheetsAreNotSupported() */ protected function multipleSheetsAreSupported() { - return $this->spoutWriter instanceof AbstractMultiSheetsWriter; + return $this->spoutWriter instanceof WriterMultiSheetsAbstract; } /** diff --git a/tests/Concerns/FromCollectionTest.php b/tests/Concerns/FromCollectionTest.php index fbc5046..c20e470 100644 --- a/tests/Concerns/FromCollectionTest.php +++ b/tests/Concerns/FromCollectionTest.php @@ -46,7 +46,9 @@ public function can_export_with_multiple_sheets_from_collection() foreach ($export->sheets() as $sheetIndex => $sheet) { $worksheet = $this->getSheetByIndex($reader, $sheetIndex); - $this->assertEquals($sheet->collection()->toArray(), array_values(iterator_to_array($worksheet->getRowIterator()))); + $this->assertEquals($sheet->collection()->toArray(), array_values(array_map(function ($row) { + return $row->toArray(); + }, iterator_to_array($worksheet->getRowIterator())))); $this->assertEquals($sheet->title(), $worksheet->getName()); } diff --git a/tests/TestCase.php b/tests/TestCase.php index f433813..9accfa9 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -2,7 +2,7 @@ namespace Nikazooz\Simplesheet\Tests; -use Box\Spout\Reader\ReaderFactory; +use Box\Spout\Reader\Common\Creator\ReaderFactory; use Box\Spout\Reader\ReaderInterface; use Closure; use Illuminate\Contracts\Queue\Job; @@ -24,7 +24,7 @@ class TestCase extends OrchestraTestCase */ public function read(string $filePath, string $writerType): ReaderInterface { - $reader = ReaderFactory::create($writerType); + $reader = ReaderFactory::createFromType($writerType); $reader->open($filePath); @@ -43,7 +43,9 @@ protected function readAsArray(string $filePath, string $writerType, int $sheetI $sheet = $this->getSheetByIndex($reader, $sheetIndex); - return array_values(iterator_to_array($sheet->getRowIterator())); + return array_values(array_map(function ($row) { + return $row->toArray(); + }, iterator_to_array($sheet->getRowIterator()))); } /**