From 94b92bbc3988fcc4613427be9c476399b474141e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Blanco?= Date: Mon, 18 Apr 2016 13:30:54 +0100 Subject: [PATCH 01/28] Update ImporterInterface.php Typo --- src/Contract/ImporterInterface.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Contract/ImporterInterface.php b/src/Contract/ImporterInterface.php index f1f0a0b..581852d 100644 --- a/src/Contract/ImporterInterface.php +++ b/src/Contract/ImporterInterface.php @@ -3,7 +3,7 @@ use Illuminate\Database\Eloquent\Collection; -interface ExporterInterface +interface ImporterInterface { public function load($path); public function setParser(ParserInterface $parser); From c028422fa8798d0dc34e81cb6bf587b9514ebf13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Blanco?= Date: Tue, 6 Sep 2016 09:27:53 +0100 Subject: [PATCH 02/28] Update composer.json --- composer.json | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/composer.json b/composer.json index a009c4c..2d2f0fb 100644 --- a/composer.json +++ b/composer.json @@ -1,8 +1,8 @@ { - "name": "cyberduck/laravel-excel", + "name": "cyber-duck/laravel-excel", "type": "library", - "description": "", - "keywords": ["Laravel", "Excel"], + "description": "A package to export things efficiently.", + "keywords": ["laravel", "excel", "exporter", "export"], "require": { "php": ">=5.4.0", "box/spout": "^2.4", @@ -21,5 +21,13 @@ "psr-4": { "Cyberduck\\LaravelExcel\\": "src" } - } + }, + "extra": { + "component": "package", + "frameworks": ["Laravel 4", "Laravel 5"], + "versions": { + "1": "1.0/master" + } + }, + "minimum-stability": "dev" } From 1801e173da591f51064d18e80cd9813d87386dd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Blanco?= Date: Tue, 6 Sep 2016 09:28:27 +0100 Subject: [PATCH 03/28] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6d7ff7d..80ef0e5 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ This package provides a way to export an Eloquent collection as an excel file an The package must be installed directly from [Composer](https://getcomposer.org/). Run the following command: ``` -$ composer require cyberduck/laravel-excel +$ composer require cyber-duck/laravel-excel ``` To make Facades available, register the service provider in config/app.php adding *Cyberduck\LaravelExcel\ExcelServiceProvider* to the provider array. From f7421f09dc339791867b53dd11c5987fc599dadd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Blanco?= Date: Tue, 6 Sep 2016 09:28:39 +0100 Subject: [PATCH 04/28] Update composer.json --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 2d2f0fb..3e3f45f 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "name": "cyber-duck/laravel-excel", "type": "library", - "description": "A package to export things efficiently.", + "description": "This package provides a way to export an Eloquent collection as an excel file and to import a Excel file as an Eloquent collection.", "keywords": ["laravel", "excel", "exporter", "export"], "require": { "php": ">=5.4.0", From b8f5d15b784552acd1717c1d048e7a22e60c064b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Blanco?= Date: Tue, 6 Sep 2016 10:02:58 +0100 Subject: [PATCH 05/28] Update composer.json --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 3e3f45f..b52d0f8 100644 --- a/composer.json +++ b/composer.json @@ -6,8 +6,8 @@ "require": { "php": ">=5.4.0", "box/spout": "^2.4", - "illuminate/database": "4.*|5.1", - "illuminate/support": "4.*|5.1" + "illuminate/database": "4.*|5.1.*", + "illuminate/support": "4.*|5.1.*" }, "license": "MIT", "authors": [ From 7d9f218955ff310b35119d3e79dd8a42b1b2a5e0 Mon Sep 17 00:00:00 2001 From: Simone Todaro Date: Sun, 25 Sep 2016 15:52:48 +0100 Subject: [PATCH 06/28] Update composer.json --- composer.json | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/composer.json b/composer.json index b52d0f8..2d68079 100644 --- a/composer.json +++ b/composer.json @@ -6,8 +6,8 @@ "require": { "php": ">=5.4.0", "box/spout": "^2.4", - "illuminate/database": "4.*|5.1.*", - "illuminate/support": "4.*|5.1.*" + "illuminate/database": "4.*|5.*", + "illuminate/support": "4.*|5.*" }, "license": "MIT", "authors": [ @@ -21,13 +21,5 @@ "psr-4": { "Cyberduck\\LaravelExcel\\": "src" } - }, - "extra": { - "component": "package", - "frameworks": ["Laravel 4", "Laravel 5"], - "versions": { - "1": "1.0/master" - } - }, - "minimum-stability": "dev" + } } From 2fde479d97e38e5c572b2306a4386589ee017e40 Mon Sep 17 00:00:00 2001 From: Simone Todaro Date: Sun, 25 Sep 2016 23:39:26 +0100 Subject: [PATCH 07/28] Update README.md --- README.md | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 80ef0e5..c62fde2 100644 --- a/README.md +++ b/README.md @@ -7,14 +7,12 @@ This package provides a way to export an Eloquent collection as an excel file and to import a Excel file as an Eloquent collection. It's based on [box/spout](https://github.com/box/spout). -## Installation -The package must be installed directly from [Composer](https://getcomposer.org/). -Run the following command: +## Installation ``` $ composer require cyber-duck/laravel-excel ``` -To make Facades available, register the service provider in config/app.php adding *Cyberduck\LaravelExcel\ExcelServiceProvider* to the provider array. +Register the service provider in config/app.php adding *Cyberduck\LaravelExcel\ExcelServiceProvider* to the provider array. Note. If you are on Laravel 4, use *Cyberduck\LaravelExcel\ExcelLegacyServiceProvider* @@ -59,11 +57,12 @@ return Exporter::make('Excel')->load($yourCollection)->save($yourFileNameWithPat ``` ### Advanced usage -By default, every element of the Collection become a row and every unprotected field of the Model become a cell. No headers row is printed. +By default, every element of the Collection becomes a row and every unprotected field of the Model becomes a cell. +No headers row is printed. -To change this behaviour, create a class extending *Cyberduck\LaravelExcel\Contract\SerialiserInterface* and implement the methods *getHeaderRow()* and *getData(Model $data)*. -*getHeaderRow()* must return an array of string, and every elements is a cell of the first row. To not print the header row, simply return a void array *[]*. -*getData(Model $data)* must return an array of string, and every elements is a cell of rows after the header. +To change this behaviour, create a class which extends *Cyberduck\LaravelExcel\Contract\SerialiserInterface* and implements the methods *getHeaderRow()* and *getData(Model $data)*. +*getHeaderRow()* must return an array of string where every element is a cell of the first row. To not print the header row, simply return a void array *[]*. +*getData(Model $data)* must return an array of string, and every elements is a cell. Example ``` @@ -79,7 +78,7 @@ class ExampleSerialiser implements SerialiserInterface $row = []; $row[] = $data->field1; - $row[] = $data->relation->field2; + $row[] = $data->relationship->field2; return $row; } @@ -88,7 +87,7 @@ class ExampleSerialiser implements SerialiserInterface { return [ 'Field 1', - 'Field 2 (from a relation)' + 'Field 2 (from a relationship)' ]; } } From 73fcd166ec7aee63f9207de13a281fb6ca5a88e4 Mon Sep 17 00:00:00 2001 From: SimoTod Date: Sun, 2 Oct 2016 23:36:04 +0100 Subject: [PATCH 08/28] Update documentation --- README.md | 88 +++++++++++++++++++++++++--- composer.json | 19 +++--- src/Contract/ParserInterface.php | 7 +++ src/Importer/AbstractSpreadsheet.php | 2 +- src/Parser/BasicParser.php | 4 +- 5 files changed, 101 insertions(+), 19 deletions(-) create mode 100644 src/Contract/ParserInterface.php diff --git a/README.md b/README.md index c62fde2..f18574a 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,21 @@ # Laravel Excel +[![Latest Stable Version](https://poser.pugx.org/cyber-duck/laravel-excel/v/stable)](https://packagist.org/packages/cyber-duck/laravel-excel) +[![Total Downloads](https://poser.pugx.org/cyber-duck/laravel-excel/downloads)](https://packagist.org/packages/cyber-duck/laravel-excel) +[![License](https://poser.pugx.org/cyber-duck/laravel-excel/license)](https://raw.githubusercontent.com/Cyber-Duck/laravel-excel/master/LICENSE) + +Laravel Excel is a pachage to export and import excel files using Eloquent Collections in Laravel (5.* and 4.*). +It's based on [box/spout](https://github.com/box/spout). + +Author: [Simone Todaro](https://github.com/SimoTod) + +Made with :heart: by [Cyber-Duck Ltd](http://www.cyber-duck.co.uk) + [Installation](#installation) [Export Excel](#export-excel) [Import Excel](#import-excel) [Different formats](#different-formats) -This package provides a way to export an Eloquent collection as an excel file and to import a Excel file as an Eloquent collection. It's based on [box/spout](https://github.com/box/spout). - ## Installation ``` $ composer require cyber-duck/laravel-excel @@ -25,7 +34,7 @@ use Exporter; ``` to your controller. -In your action, add +In your controler function, create a new excel file. ``` $excel = Exporter::make('Excel'); $excel->load($yourCollection); @@ -44,7 +53,7 @@ use Exporter; ``` to your controller. -In your action, add +In your controler function, create a new excel file. ``` $excel = Exporter::make('Excel'); $excel->load($yourCollection); @@ -66,7 +75,7 @@ To change this behaviour, create a class which extends *Cyberduck\LaravelExcel\C Example ``` -namespace App\Serialiser; +namespace App\Serialisers; use Illuminate\Database\Eloquent\Model; use Cyberduck\LaravelExcel\Contract\SerialiserInterface; @@ -94,7 +103,72 @@ class ExampleSerialiser implements SerialiserInterface ``` ## Import Excel -Coming soon! (In development) +Add +``` +use Importer; +``` +to your controller. + +In your controler function, import an excel file. +``` +$excel = Importer::make('Excel'); +$excel->load($filepath); +$collection = $excel->getCollection(); +//dd($collection) +``` + +The importer class is fluent, then you can also write +``` +return Importer::make('Excel')->getCollection($filepath)->getCollection(); +``` + +### Advanced usage +By default, every row of the first sheet of the excel file becomes an array and the final result is wraped in a Collection (Illuminate\Support\Collection). + +To import a different sheet, use *setSheet($sheet)* +``` +$excel = Importer::make('Excel'); +$excel->load($filepath); +$excel->setSheet($sheetNumber); +$collection = $excel->getCollection(); +//dd($collection) +``` + +To import each row in an Eloquent model, create a class which extends *Cyberduck\LaravelExcel\Contract\ParserInterface* and implements the methods *transform($row)*. + +Example +``` +namespace App\Parsers; + +use App\Models\YourModel; +use Cyberduck\LaravelExcel\Contract\ParserInterface; + +class ExampleSerialiser implements ParserInterface +{ + public function transform($row) + { + $model = new YourModel(); + $model->field1 = $row[0]; + $model->field2 = $row[1]; + // We can manunipulate the data before returning the object + $model->field3 = new \Carbon($row[2]); + return $model; + } +} +``` ## Different formats -Coming soon! +The pachage supports ODS and CSV files. + +### ODS +``` +$exporter = Exporter::make('OpenOffice'); +$importer = Importer::make('OpenOffice'); +``` + +### CSV +``` +$exporter = Exporter::make('Csv'); +$importer = Importer::make('Csv'); +``` + diff --git a/composer.json b/composer.json index 2d68079..594e940 100644 --- a/composer.json +++ b/composer.json @@ -2,24 +2,25 @@ "name": "cyber-duck/laravel-excel", "type": "library", "description": "This package provides a way to export an Eloquent collection as an excel file and to import a Excel file as an Eloquent collection.", - "keywords": ["laravel", "excel", "exporter", "export"], - "require": { - "php": ">=5.4.0", - "box/spout": "^2.4", - "illuminate/database": "4.*|5.*", - "illuminate/support": "4.*|5.*" - }, + "keywords": ["laravel", "excel", "exporter", "export", "importer", "import", "eloquent", "spout"], "license": "MIT", "authors": [ { "name": "Simone Todaro", - "email": "simone@cyber-duck.co.uk", + "email": "simo.todaro@gmail.com", "role": "Developer" } ], + "require": { + "php": ">=5.4.0", + "box/spout": "^2.4", + "illuminate/database": "4.*|5.*", + "illuminate/support": "4.*|5.*" + }, "autoload": { "psr-4": { "Cyberduck\\LaravelExcel\\": "src" } - } + }, + "minimum-stability": "stable" } diff --git a/src/Contract/ParserInterface.php b/src/Contract/ParserInterface.php new file mode 100644 index 0000000..c25efdd --- /dev/null +++ b/src/Contract/ParserInterface.php @@ -0,0 +1,7 @@ +getRowIterator() as $row) { - $collection[] = $this->parser->getData($row); + $collection[] = $this->parser->transform($row); } } return collect($collection); diff --git a/src/Parser/BasicParser.php b/src/Parser/BasicParser.php index 86824e3..caf2e4a 100644 --- a/src/Parser/BasicParser.php +++ b/src/Parser/BasicParser.php @@ -1,11 +1,11 @@ Date: Fri, 3 Feb 2017 17:19:39 +0000 Subject: [PATCH 09/28] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index f18574a..fe4e753 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,8 @@ It's based on [box/spout](https://github.com/box/spout). Author: [Simone Todaro](https://github.com/SimoTod) +Contributors: [Clément Blanco](https://github.com/Claymm) + Made with :heart: by [Cyber-Duck Ltd](http://www.cyber-duck.co.uk) [Installation](#installation) From 812df643e0f67a714e5985f239a447a4963d9314 Mon Sep 17 00:00:00 2001 From: SimoTod Date: Wed, 28 Jun 2017 20:47:40 +0100 Subject: [PATCH 10/28] Add support for query builder objects and generic collections --- src/Contract/ExporterInterface.php | 5 ++++- src/Contract/ImporterInterface.php | 2 -- src/Contract/SerialiserInterface.php | 4 +--- src/ExcelServiceProvider.php | 4 ++-- src/Exporter/AbstractSpreadsheet.php | 32 ++++++++++++++++++++++++---- src/Importer/AbstractSpreadsheet.php | 1 - src/Serialiser/BasicSerialiser.php | 10 +++++++-- 7 files changed, 43 insertions(+), 15 deletions(-) diff --git a/src/Contract/ExporterInterface.php b/src/Contract/ExporterInterface.php index 75e3a22..61f25bc 100644 --- a/src/Contract/ExporterInterface.php +++ b/src/Contract/ExporterInterface.php @@ -1,11 +1,14 @@ alias('Exporter', '\Cyberduck\LaravelExcel\ExporterFacade'); - $loader->alias('Importer', '\Cyberduck\LaravelExcel\ImporterFacade'); + $loader->alias('Exporter', \Cyberduck\LaravelExcel\ExporterFacade::class); + $loader->alias('Importer', \Cyberduck\LaravelExcel\ImporterFacade::class); } public function register() diff --git a/src/Exporter/AbstractSpreadsheet.php b/src/Exporter/AbstractSpreadsheet.php index 41cbdec..7f332e2 100644 --- a/src/Exporter/AbstractSpreadsheet.php +++ b/src/Exporter/AbstractSpreadsheet.php @@ -1,8 +1,9 @@ serialiser = new BasicSerialiser(); } - public function load(Collection $data) { $this->data = $data; return $this; } + public function loadQuery(Builder $query) + { + $this->data = $query; + return $this; + } + + public function setChunk($size) + { + $this->chunksize = $size; + return $this; + } + public function setSerialiser(SerialiserInterface $serialiser) { $this->serialiser = $serialiser; @@ -62,8 +75,19 @@ protected function makeRows($writer) if (!empty($headerRow)) { $writer->addRow($headerRow); } - foreach ($this->data as $record) { - $writer->addRow($this->serialiser->getData($record)); + if ($this->data instanceof Builder) { + if (isset($this->chuncksize)) { + $this->data->chunk($this->chuncksize); + } else { + $data = $this->data->get(); + foreach ($data as $record) { + $writer->addRow($this->serialiser->getData($record)); + } + } + } else { + foreach ($this->data as $record) { + $writer->addRow($this->serialiser->getData($record)); + } } return $writer; } diff --git a/src/Importer/AbstractSpreadsheet.php b/src/Importer/AbstractSpreadsheet.php index 648ff9b..f457fb9 100644 --- a/src/Importer/AbstractSpreadsheet.php +++ b/src/Importer/AbstractSpreadsheet.php @@ -1,7 +1,6 @@ toArray(); + if ($data instanceof Model) { + return $data->toArray(); + } elseif (is_array($data)) { + return $data; + } else { + return get_object_vars($data); + } } public function getHeaderRow() From 46f9a917d70e54a0659f21d9fb86112c7b330ae1 Mon Sep 17 00:00:00 2001 From: SimoTod Date: Wed, 28 Jun 2017 20:48:13 +0100 Subject: [PATCH 11/28] Add tests --- README.md | 3 +- composer.json | 14 ++ phpunit.xml | 19 +++ tests/TestCase.php | 61 ++++++++ tests/Unit/ExporterTest.php | 176 ++++++++++++++++++++++ tests/Unit/FacadesTest.php | 16 ++ tests/Unit/FactoryTest.php | 90 +++++++++++ tests/Unit/ImporterTest.php | 7 + tests/Unit/ServiceProviderTest.php | 28 ++++ tests/utils/DatabaseSeeder.php | 34 +++++ tests/utils/FirstColumnOnlySerialiser.php | 17 +++ tests/utils/Item.php | 8 + tests/utils/Migration.php | 44 ++++++ 13 files changed, 515 insertions(+), 2 deletions(-) create mode 100644 phpunit.xml create mode 100644 tests/TestCase.php create mode 100644 tests/Unit/ExporterTest.php create mode 100644 tests/Unit/FacadesTest.php create mode 100644 tests/Unit/FactoryTest.php create mode 100644 tests/Unit/ImporterTest.php create mode 100644 tests/Unit/ServiceProviderTest.php create mode 100644 tests/utils/DatabaseSeeder.php create mode 100644 tests/utils/FirstColumnOnlySerialiser.php create mode 100644 tests/utils/Item.php create mode 100644 tests/utils/Migration.php diff --git a/README.md b/README.md index fe4e753..036ab6b 100644 --- a/README.md +++ b/README.md @@ -160,7 +160,7 @@ class ExampleSerialiser implements ParserInterface ``` ## Different formats -The pachage supports ODS and CSV files. +The package supports ODS and CSV files. ### ODS ``` @@ -173,4 +173,3 @@ $importer = Importer::make('OpenOffice'); $exporter = Exporter::make('Csv'); $importer = Importer::make('Csv'); ``` - diff --git a/composer.json b/composer.json index 594e940..e258ae0 100644 --- a/composer.json +++ b/composer.json @@ -17,10 +17,24 @@ "illuminate/database": "4.*|5.*", "illuminate/support": "4.*|5.*" }, + "require-dev": { + "phpunit/phpunit": "~4.0", + "phpspec/phpspec": "~2.1", + "laravel/laravel": "~5.3" + }, "autoload": { "psr-4": { "Cyberduck\\LaravelExcel\\": "src" } }, + "autoload-dev": { + "files": [ + "tests/TestCase.php", + "tests/utils/Item.php", + "tests/utils/Migration.php", + "tests/utils/DatabaseSeeder.php", + "tests/utils/FirstColumnOnlySerialiser.php" + ] + }, "minimum-stability": "stable" } diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..6d55c5c --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,19 @@ + + + + + ./tests/ + ./tests/views + + + \ No newline at end of file diff --git a/tests/TestCase.php b/tests/TestCase.php new file mode 100644 index 0000000..0f5ef32 --- /dev/null +++ b/tests/TestCase.php @@ -0,0 +1,61 @@ + 'A', + 'field2' => 'B', + 'field3' => 'C', + 'field4' => 'D', + 'field5' => 'E', + 'field6' => 'F', + 'field7' => 'G', + 'field8' => 'H', + 'field9' => 'I', + 'field10' => 'J', + 'field11' => 'K', + 'field12' => 'L', + 'field13' => 'M', + 'field14' => 'N', + 'field15' => 'O', + ]; + + public function createApplication() + { + $app = require __DIR__.'/../vendor/laravel/laravel/bootstrap/app.php'; + $app->register('Cyberduck\LaravelExcel\ExcelServiceProvider'); + + $app->make('Illuminate\Contracts\Console\Kernel')->bootstrap(); + + return $app; + } + + /** + * Setup DB before each test. + * + * @return void + */ + public function setUp() + { + parent::setUp(); + + $this->app['config']->set('database.default', 'sqlite'); + $this->app['config']->set('database.connections.sqlite.database', ':memory:'); + } + + public function seed($item = 10) + { + for ($j = 0; $jfloor($item/50)) ? 50 : ($item-($j*50)); + for ($i = 0; $i<$limit; $i++) { + $rows[] = self::DEFAULT_ROW; + } + DB::table('items')->insert($rows); + } + } +} diff --git a/tests/Unit/ExporterTest.php b/tests/Unit/ExporterTest.php new file mode 100644 index 0000000..aaf16cd --- /dev/null +++ b/tests/Unit/ExporterTest.php @@ -0,0 +1,176 @@ +up(); + } + + public function tearDown() + { + (new Migration)->down(); + parent::tearDown(); + } + + public function test_can_export_csv() + { + $itemsToSeed = 2; + $this->seed($itemsToSeed); + + //Export the file + $exporter = $this->app->make('cyber-duck/exporter')->make('csv'); + $exporter->load(Item::all())->save(self::FILE); + + //Read the content + $lines = 0; + $reader = ReaderFactory::create(Type::CSV); + $reader->open(self::FILE); + foreach ($reader->getSheetIterator() as $index => $sheet) { + foreach ($sheet->getRowIterator() as $row) { + $this->assertEquals(array_values(self::DEFAULT_ROW), $row); + $lines++; + } + } + $reader->close(); + $this->assertEquals($itemsToSeed, $lines); + + unlink(self::FILE); + } + + public function test_can_export_odt() + { + $itemsToSeed = 2; + $this->seed($itemsToSeed); + + //Export the file + $exporter = $this->app->make('cyber-duck/exporter')->make('openoffice'); + $exporter->load(Item::all())->save(self::FILE); + + //Read the content + $lines = 0; + $reader = ReaderFactory::create(Type::ODS); + $reader->open(self::FILE); + foreach ($reader->getSheetIterator() as $index => $sheet) { + foreach ($sheet->getRowIterator() as $row) { + $this->assertEquals(array_values(self::DEFAULT_ROW), $row); + $lines++; + } + } + $reader->close(); + $this->assertEquals($itemsToSeed, $lines); + + unlink(self::FILE); + } + + public function test_can_export_xlsx() + { + $itemsToSeed = 2; + $this->seed($itemsToSeed); + + //Export the file + $exporter = $this->app->make('cyber-duck/exporter')->make('excel'); + $exporter->load(Item::all())->save(self::FILE); + + //Read the content + $lines = 0; + $reader = ReaderFactory::create(Type::XLSX); + $reader->open(self::FILE); + foreach ($reader->getSheetIterator() as $index => $sheet) { + foreach ($sheet->getRowIterator() as $row) { + $this->assertEquals(array_values(self::DEFAULT_ROW), $row); + $lines++; + } + } + $reader->close(); + $this->assertEquals($itemsToSeed, $lines); + + unlink(self::FILE); + } + + public function test_can_use_a_query_builder() + { + $itemsToSeed = 2; + $this->seed($itemsToSeed); + + //Export the file + $exporter = $this->app->make('cyber-duck/exporter')->make('csv'); + $exporter->loadQuery(Item::getQuery())->save(self::FILE); + + //Read the content + $lines = 0; + $reader = ReaderFactory::create(Type::CSV); + $reader->open(self::FILE); + foreach ($reader->getSheetIterator() as $index => $sheet) { + foreach ($sheet->getRowIterator() as $idx => $row) { + $expected = array_merge([strval($idx)], array_values(self::DEFAULT_ROW)); + $this->assertEquals($expected, $row); + $lines++; + } + } + $reader->close(); + $this->assertEquals($itemsToSeed, $lines); + + unlink(self::FILE); + } + + public function test_can_use_a_query_builder_with_chunk() + { + $itemsToSeed = 2; + $this->seed($itemsToSeed); + + //Export the file + $exporter = $this->app->make('cyber-duck/exporter')->make('csv'); + $exporter->loadQuery(Item::getQuery())->setChunk(2)->save(self::FILE); + + //Read the content + $lines = 0; + $reader = ReaderFactory::create(Type::CSV); + $reader->open(self::FILE); + foreach ($reader->getSheetIterator() as $index => $sheet) { + foreach ($sheet->getRowIterator() as $idx => $row) { + $expected = array_merge([strval($idx)], array_values(self::DEFAULT_ROW)); + $this->assertEquals($expected, $row); + $lines++; + } + } + $reader->close(); + $this->assertEquals($itemsToSeed, $lines); + + unlink(self::FILE); + } + + public function test_can_use_a_custom_serialiser() + { + $itemsToSeed = 2; + $this->seed($itemsToSeed); + + //Export the file + $exporter = $this->app->make('cyber-duck/exporter')->make('csv'); + $exporter->setSerialiser(new FirstColumnOnlySerialiser())->load(Item::all())->save(self::FILE); + + //Read the content + $lines = 0; + $reader = ReaderFactory::create(Type::CSV); + $reader->open(self::FILE); + foreach ($reader->getSheetIterator() as $index => $sheet) { + foreach ($sheet->getRowIterator() as $row) { + if ($lines == 0) { + $this->assertEquals(['HEADER'], $row); + } else { + $this->assertEquals(['A'], $row); + } + $lines++; + } + } + $reader->close(); + + unlink(self::FILE); + } +} diff --git a/tests/Unit/FacadesTest.php b/tests/Unit/FacadesTest.php new file mode 100644 index 0000000..2ad9024 --- /dev/null +++ b/tests/Unit/FacadesTest.php @@ -0,0 +1,16 @@ +assertInstanceOf( + \Cyberduck\LaravelExcel\Factory\ExporterFactory::class, + Exporter::getFacadeRoot() + ); + $this->assertInstanceOf( + \Cyberduck\LaravelExcel\Factory\ImporterFactory::class, + Importer::getFacadeRoot() + ); + } +} diff --git a/tests/Unit/FactoryTest.php b/tests/Unit/FactoryTest.php new file mode 100644 index 0000000..55b7ebd --- /dev/null +++ b/tests/Unit/FactoryTest.php @@ -0,0 +1,90 @@ +make('csv'); + $this->assertInstanceOf( + \Cyberduck\LaravelExcel\Importer\Csv::class, + $spreadsheet + ); + $this->assertEquals( + \Box\Spout\Common\Type::CSV, + $spreadsheet->getType() + ); + } + + public function test_factory_can_create_odt() + { + $factory = new ImporterFactory(); + $spreadsheet = $factory->make('openoffice'); + $this->assertInstanceOf( + \Cyberduck\LaravelExcel\Importer\OpenOffice::class, + $factory->make('openoffice') + ); + $this->assertEquals( + \Box\Spout\Common\Type::ODS, + $spreadsheet->getType() + ); + } + + public function test_factory_can_create_xls() + { + $factory = new ImporterFactory(); + $spreadsheet = $factory->make('excel'); + $this->assertInstanceOf( + \Cyberduck\LaravelExcel\Importer\Excel::class, + $factory->make('excel') + ); + $this->assertEquals( + \Box\Spout\Common\Type::XLSX, + $spreadsheet->getType() + ); + } + public function test_exporter_factory_can_create_csv() + { + $factory = new ExporterFactory(); + $spreadsheet = $factory->make('csv'); + $this->assertInstanceOf( + \Cyberduck\LaravelExcel\Exporter\Csv::class, + $spreadsheet + ); + $this->assertEquals( + \Box\Spout\Common\Type::CSV, + $spreadsheet->getType() + ); + } + + public function test_exporter_factory_can_create_odt() + { + $factory = new ExporterFactory(); + $spreadsheet = $factory->make('openoffice'); + $this->assertInstanceOf( + \Cyberduck\LaravelExcel\Exporter\OpenOffice::class, + $spreadsheet + ); + $this->assertEquals( + \Box\Spout\Common\Type::ODS, + $spreadsheet->getType() + ); + } + + public function test_exporter_factory_can_create_xls() + { + $factory = new ExporterFactory(); + $spreadsheet = $factory->make('excel'); + $this->assertInstanceOf( + \Cyberduck\LaravelExcel\Exporter\Excel::class, + $spreadsheet + ); + $this->assertEquals( + \Box\Spout\Common\Type::XLSX, + $spreadsheet->getType() + ); + } +} diff --git a/tests/Unit/ImporterTest.php b/tests/Unit/ImporterTest.php new file mode 100644 index 0000000..72b2e39 --- /dev/null +++ b/tests/Unit/ImporterTest.php @@ -0,0 +1,7 @@ +assertTrue($this->app->bound('cyber-duck/exporter')); + $this->assertTrue($this->app->bound('cyber-duck/importer')); + $this->assertInstanceOf( + \Cyberduck\LaravelExcel\Factory\ExporterFactory::class, + $this->app->make('cyber-duck/exporter') + ); + $this->assertInstanceOf( + \Cyberduck\LaravelExcel\Factory\ImporterFactory::class, + $this->app->make('cyber-duck/importer') + ); + //Test aliases + $this->assertInstanceOf( + \Cyberduck\LaravelExcel\Exporter\AbstractSpreadsheet::class, + Exporter::make("Excel") + ); + $this->assertInstanceOf( + \Cyberduck\LaravelExcel\Importer\AbstractSpreadsheet::class, + Importer::make("Excel") + ); + } +} diff --git a/tests/utils/DatabaseSeeder.php b/tests/utils/DatabaseSeeder.php new file mode 100644 index 0000000..c5eb6f8 --- /dev/null +++ b/tests/utils/DatabaseSeeder.php @@ -0,0 +1,34 @@ + 'A', + 'field2' => 'B', + 'field3' => 'C', + 'field4' => 'D', + 'field5' => 'E', + 'field6' => 'F', + 'field7' => 'G', + 'field8' => 'H', + 'field9' => 'I', + 'field10' => 'J', + 'field11' => 'K', + 'field12' => 'L', + 'field13' => 'M', + 'field14' => 'N', + 'field15' => 'O', + ]; + } + DB::table('items')->insert($rows); + } + } +} \ No newline at end of file diff --git a/tests/utils/FirstColumnOnlySerialiser.php b/tests/utils/FirstColumnOnlySerialiser.php new file mode 100644 index 0000000..108a6c1 --- /dev/null +++ b/tests/utils/FirstColumnOnlySerialiser.php @@ -0,0 +1,17 @@ +toArray(); + return [$arrayValues['field1']]; + } + + public function getHeaderRow() + { + return ['HEADER']; + } +} diff --git a/tests/utils/Item.php b/tests/utils/Item.php new file mode 100644 index 0000000..d52b569 --- /dev/null +++ b/tests/utils/Item.php @@ -0,0 +1,8 @@ +increments('id'); + $table->text('field1'); + $table->text('field2'); + $table->text('field3'); + $table->text('field4'); + $table->text('field5'); + $table->text('field6'); + $table->text('field7'); + $table->text('field8'); + $table->text('field9'); + $table->text('field10'); + $table->text('field11'); + $table->text('field12'); + $table->text('field13'); + $table->text('field14'); + $table->text('field15'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('items'); + } +} From e63b71dd9f1f215315502017256268cc96a06f86 Mon Sep 17 00:00:00 2001 From: SimoTod Date: Fri, 30 Jun 2017 23:53:02 +0100 Subject: [PATCH 12/28] Update readme --- README.md | 90 +++++++++++++++++------------- src/Contract/ImporterInterface.php | 1 + 2 files changed, 51 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index 036ab6b..1c46670 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,13 @@ -# Laravel Excel - +# Laravel Excel [![Latest Stable Version](https://poser.pugx.org/cyber-duck/laravel-excel/v/stable)](https://packagist.org/packages/cyber-duck/laravel-excel) [![Total Downloads](https://poser.pugx.org/cyber-duck/laravel-excel/downloads)](https://packagist.org/packages/cyber-duck/laravel-excel) [![License](https://poser.pugx.org/cyber-duck/laravel-excel/license)](https://raw.githubusercontent.com/Cyber-Duck/laravel-excel/master/LICENSE) -Laravel Excel is a pachage to export and import excel files using Eloquent Collections in Laravel (5.* and 4.*). +Exporting and importing Excel, CSV and OpenOffice stylesheets using Eloquent Collections and Query Builders in Laravel (5.* and 4.*). It's based on [box/spout](https://github.com/box/spout). -Author: [Simone Todaro](https://github.com/SimoTod) - -Contributors: [Clément Blanco](https://github.com/Claymm) - +Author: [Simone Todaro](https://github.com/SimoTod) +Contributors: [Clément Blanco](https://github.com/Claymm) Made with :heart: by [Cyber-Duck Ltd](http://www.cyber-duck.co.uk) [Installation](#installation) @@ -18,60 +15,73 @@ Made with :heart: by [Cyber-Duck Ltd](http://www.cyber-duck.co.uk) [Import Excel](#import-excel) [Different formats](#different-formats) -## Installation +## Installation +Use composer to download the package: ``` -$ composer require cyber-duck/laravel-excel +composer require cyber-duck/laravel-excel ``` -Register the service provider in config/app.php adding *Cyberduck\LaravelExcel\ExcelServiceProvider* to the provider array. +Register the service provider in `config/app.php` adding *Cyberduck\LaravelExcel\ExcelServiceProvider* to the provider array. Note. If you are on Laravel 4, use *Cyberduck\LaravelExcel\ExcelLegacyServiceProvider* ## Export Excel ### Generate and download an excel file -Add +Add ``` use Exporter; -``` +``` to your controller. -In your controler function, create a new excel file. +In your controler function, create a new excel file from an Eloquent collection. ``` $excel = Exporter::make('Excel'); -$excel->load($yourCollection); -return $excel->stream($yourFileName); -``` +$excel->load($yourCollection); +return $excel->stream($yourFileName); +``` -The exporter class is fluent, then you can also write +The exporter class is fluent, so you can also write ``` return Exporter::make('Excel')->load($yourCollection)->stream($yourFileName); ``` -### Generate and save an excel file -Add +The exporter class supports Query builder objects as well +``` +$query = DB:table('table')->select('col1','col2'); +$excel = Exporter::make('Excel'); +$excel->loadQuery($query); +return $excel->stream($yourFileName); ``` -use Exporter; -``` -to your controller. -In your controler function, create a new excel file. +If you deal with big tables, you can set the chunk size to minimise the memory usage ``` +$query = DB:table('table')->select('col1','col2'); $excel = Exporter::make('Excel'); -$excel->load($yourCollection); -return $excel->save($yourFileNameWithPath); -``` +$excel->loadQuery($query); +$excel->setChunk(1000); +return $excel->stream($yourFileName); +``` -The exporter class is fluent, then you can also write +### Generate and save an excel file +To save the excel file on the server, use the save method. ``` -return Exporter::make('Excel')->load($yourCollection)->save($yourFileNameWithPath); +return $excel->save($yourFileNameWithPath); ``` ### Advanced usage By default, every element of the Collection becomes a row and every unprotected field of the Model becomes a cell. No headers row is printed. -To change this behaviour, create a class which extends *Cyberduck\LaravelExcel\Contract\SerialiserInterface* and implements the methods *getHeaderRow()* and *getData(Model $data)*. +To change this behaviour, create a class extending *Cyberduck\LaravelExcel\Contract\SerialiserInterface*, implement the methods *getHeaderRow()* and *getData(Model $data)* and set this class on the excel object usint *setSerialiser()*. +``` +$serialiser = new CustomSerialiser(); +$excel = Exporter::make('Excel'); +$excel->load($collection); +$excel->setSerialiser($serialiser); +return $excel->stream($yourFileName); +``` + *getHeaderRow()* must return an array of string where every element is a cell of the first row. To not print the header row, simply return a void array *[]*. *getData(Model $data)* must return an array of string, and every elements is a cell. @@ -105,21 +115,21 @@ class ExampleSerialiser implements SerialiserInterface ``` ## Import Excel -Add +Add ``` use Importer; -``` +``` to your controller. In your controler function, import an excel file. ``` $excel = Importer::make('Excel'); -$excel->load($filepath); -$collection = $excel->getCollection(); +$excel->load($filepath); +$collection = $excel->getCollection(); //dd($collection) -``` +``` -The importer class is fluent, then you can also write +The importer class is fluent, then you can also write ``` return Importer::make('Excel')->getCollection($filepath)->getCollection(); ``` @@ -130,13 +140,13 @@ By default, every row of the first sheet of the excel file becomes an array and To import a different sheet, use *setSheet($sheet)* ``` $excel = Importer::make('Excel'); -$excel->load($filepath); -$excel->setSheet($sheetNumber); -$collection = $excel->getCollection(); +$excel->load($filepath); +$excel->setSheet($sheetNumber); +$collection = $excel->getCollection(); //dd($collection) -``` +``` -To import each row in an Eloquent model, create a class which extends *Cyberduck\LaravelExcel\Contract\ParserInterface* and implements the methods *transform($row)*. +To import each row in an Eloquent model, create a class extending *Cyberduck\LaravelExcel\Contract\ParserInterface* and implement the methods *transform($row)*. Example ``` diff --git a/src/Contract/ImporterInterface.php b/src/Contract/ImporterInterface.php index cca022d..5ed19bc 100644 --- a/src/Contract/ImporterInterface.php +++ b/src/Contract/ImporterInterface.php @@ -6,4 +6,5 @@ interface ImporterInterface public function load($path); public function setParser(ParserInterface $parser); public function getCollection(); + public function setSheet($sheet); } From efc14d04227e8041c6f0b66eccc67a3343e59b87 Mon Sep 17 00:00:00 2001 From: Simone Todaro Date: Tue, 1 Aug 2017 14:25:03 +0100 Subject: [PATCH 13/28] Fix importer issue --- src/Importer/AbstractSpreadsheet.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Importer/AbstractSpreadsheet.php b/src/Importer/AbstractSpreadsheet.php index f457fb9..7a6b5cf 100644 --- a/src/Importer/AbstractSpreadsheet.php +++ b/src/Importer/AbstractSpreadsheet.php @@ -16,7 +16,7 @@ abstract class AbstractSpreadsheet implements ImporterInterface public function __construct() { $this->path = ''; - $this->sheet = 0; + $this->sheet = 1; $this->type = $this->getType(); $this->parser = new BasicParser(); } @@ -41,7 +41,7 @@ abstract public function getType(); public function getCollection() { $reader = $this->create(); - $reader->open(); + $reader->open($this->path); $collection = $this->parseRows($reader); $reader->close(); return $collection; From 5e7de012004d208df0d56375c7220a0705835317 Mon Sep 17 00:00:00 2001 From: Simone Todaro Date: Wed, 2 Aug 2017 13:21:00 +0100 Subject: [PATCH 14/28] Refactor importer --- src/Contract/ImporterInterface.php | 6 +- src/Contract/ParserInterface.php | 2 +- src/Importer/AbstractSpreadsheet.php | 85 ++++++++++++++++++++++++---- src/Parser/BasicParser.php | 11 +++- 4 files changed, 89 insertions(+), 15 deletions(-) diff --git a/src/Contract/ImporterInterface.php b/src/Contract/ImporterInterface.php index 5ed19bc..1377534 100644 --- a/src/Contract/ImporterInterface.php +++ b/src/Contract/ImporterInterface.php @@ -1,10 +1,14 @@ path = ''; $this->sheet = 1; + $this->hasHeaderRow = 0; $this->type = $this->getType(); $this->parser = new BasicParser(); + $this->model = false; } public function load($path) @@ -31,38 +36,94 @@ public function setSheet($sheet) $this->sheet = $sheet; } + public function hasHeader($hasHeaderRow) + { + $this->hasHeaderRow = $hasHeaderRow; + } + public function setParser(ParserInterface $parser) { $this->parser = $parser; } + public function setModel(Model $model) + { + $this->model = $model; + } + abstract public function getType(); public function getCollection() { - $reader = $this->create(); - $reader->open($this->path); - $collection = $this->parseRows($reader); + $headers = false; + + $reader = $this->open(); + + foreach ($reader->getSheetIterator() as $index => $sheet) { + if ($index !== $this->sheet) { + continue; + } + + $collection = $this->model ? $this->model->newCollection() : collect([]); + + foreach ($sheet->getRowIterator() as $rowindex => $row) { + if ($rowindex == 1 && $this->header) { + $headers = $row; + } else { + $data = $this->parser->transform($row, $headers); + + if ($this->model) { + $data = $this->model->getQuery()->insert($data); + } + + $collection->push($data); + } + } + } + $reader->close(); + return $collection; } - protected function create() + public function save($updateIfEquals = []) { - return ReaderFactory::create($this->type); - } + if (!$this->model) { + return; + } + + $headers = false; + + $reader = $this->open(); + + $updateIfEquals = array_flip($updateIfEquals); - protected function parseRows($reader) - { - $collection = []; foreach ($reader->getSheetIterator() as $index => $sheet) { if ($index !== $this->sheet) { continue; } - foreach ($sheet->getRowIterator() as $row) { - $collection[] = $this->parser->transform($row); + + foreach ($sheet->getRowIterator() as $rowindex => $row) { + if ($rowindex == 1 && $this->header) { + $headers = $row; + } else { + $data = $this->parser->transform($row, $headers); + $when = array_intersect_key($data, $updateIfEquals); + $values = array_diff($data, $when); + if (!empty($when)) { + $this->model->getQuery()->updateOrInsert($when, $values); + } else { + $this->model->getQuery()->insert($values); + } + } } } - return collect($collection); + } + + protected function open() + { + $reader= ReaderFactory::create($this->type); + $reader->open($this->path); + return $reader; } } diff --git a/src/Parser/BasicParser.php b/src/Parser/BasicParser.php index caf2e4a..bc179b6 100644 --- a/src/Parser/BasicParser.php +++ b/src/Parser/BasicParser.php @@ -1,12 +1,21 @@ Date: Wed, 2 Aug 2017 13:31:15 +0100 Subject: [PATCH 15/28] Fix undefined property --- src/Importer/AbstractSpreadsheet.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Importer/AbstractSpreadsheet.php b/src/Importer/AbstractSpreadsheet.php index 4e2970c..d2da518 100644 --- a/src/Importer/AbstractSpreadsheet.php +++ b/src/Importer/AbstractSpreadsheet.php @@ -67,7 +67,7 @@ public function getCollection() $collection = $this->model ? $this->model->newCollection() : collect([]); foreach ($sheet->getRowIterator() as $rowindex => $row) { - if ($rowindex == 1 && $this->header) { + if ($rowindex == 1 && $this->hasHeaderRow) { $headers = $row; } else { $data = $this->parser->transform($row, $headers); @@ -104,7 +104,7 @@ public function save($updateIfEquals = []) } foreach ($sheet->getRowIterator() as $rowindex => $row) { - if ($rowindex == 1 && $this->header) { + if ($rowindex == 1 && $this->hasHeaderRow) { $headers = $row; } else { $data = $this->parser->transform($row, $headers); From 8cfbf3b4b32b24ad2c92a7ae22a9b6e3181a584d Mon Sep 17 00:00:00 2001 From: Simone Todaro Date: Sun, 27 Aug 2017 19:37:34 +0100 Subject: [PATCH 16/28] Skip row when parser returns false --- src/Importer/AbstractSpreadsheet.php | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/Importer/AbstractSpreadsheet.php b/src/Importer/AbstractSpreadsheet.php index d2da518..f1d2fb9 100644 --- a/src/Importer/AbstractSpreadsheet.php +++ b/src/Importer/AbstractSpreadsheet.php @@ -72,11 +72,13 @@ public function getCollection() } else { $data = $this->parser->transform($row, $headers); - if ($this->model) { - $data = $this->model->getQuery()->insert($data); - } + if ($data !== false) { + if ($this->model) { + $data = $this->model->getQuery()->newInstance($data); + } - $collection->push($data); + $collection->push($data); + } } } } @@ -108,12 +110,14 @@ public function save($updateIfEquals = []) $headers = $row; } else { $data = $this->parser->transform($row, $headers); - $when = array_intersect_key($data, $updateIfEquals); - $values = array_diff($data, $when); - if (!empty($when)) { - $this->model->getQuery()->updateOrInsert($when, $values); - } else { - $this->model->getQuery()->insert($values); + if ($data !== false) { + $when = array_intersect_key($data, $updateIfEquals); + $values = array_diff($data, $when); + if (!empty($when)) { + $this->model->getQuery()->updateOrInsert($when, $values); + } else { + $this->model->getQuery()->insert($values); + } } } } From 33eccf778167069ecc730e140508f8ed963b93d0 Mon Sep 17 00:00:00 2001 From: Simone Todaro Date: Mon, 4 Sep 2017 23:17:13 +0100 Subject: [PATCH 17/28] Add proxy __call methods to access the underlying Spout functions --- src/Exporter/AbstractSpreadsheet.php | 14 +++++++++++++- src/Importer/AbstractSpreadsheet.php | 10 ++++++++++ tests/docs/.gitignore | 2 ++ 3 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 tests/docs/.gitignore diff --git a/src/Exporter/AbstractSpreadsheet.php b/src/Exporter/AbstractSpreadsheet.php index 7f332e2..0eb1a90 100644 --- a/src/Exporter/AbstractSpreadsheet.php +++ b/src/Exporter/AbstractSpreadsheet.php @@ -14,12 +14,20 @@ abstract class AbstractSpreadsheet implements ExporterInterface protected $type; protected $serialiser; protected $chuncksize; + protected $callbacks; public function __construct() { $this->data = []; $this->type = $this->getType(); $this->serialiser = new BasicSerialiser(); + $this->callbacks = collect([]); + } + + public function __call($name, $args) + { + $this->callbacks->push([$name, $args]); + return $this; } public function load(Collection $data) @@ -66,7 +74,11 @@ public function stream($filename) protected function create() { - return WriterFactory::create($this->type); + $writer = WriterFactory::create($this->type); + $this->callbacks->each(function ($elem) use (&$writer) { + call_user_func_array(array($writer, $elem[0]), $elem[1]); + }); + return $writer; } protected function makeRows($writer) diff --git a/src/Importer/AbstractSpreadsheet.php b/src/Importer/AbstractSpreadsheet.php index d2da518..ba3b054 100644 --- a/src/Importer/AbstractSpreadsheet.php +++ b/src/Importer/AbstractSpreadsheet.php @@ -15,6 +15,7 @@ abstract class AbstractSpreadsheet implements ImporterInterface protected $sheet; protected $model; protected $hasHeaderRow; + protected $callbacks; public function __construct() { @@ -26,6 +27,12 @@ public function __construct() $this->model = false; } + public function __call($name, $args) + { + $this->callbacks->push([$name, $args]); + return $this; + } + public function load($path) { $this->path = $path; @@ -124,6 +131,9 @@ protected function open() { $reader= ReaderFactory::create($this->type); $reader->open($this->path); + $this->callbacks->each(function ($elem) use (&$writer) { + call_user_func_array(array($writer, $elem[0]), $elem[1]); + }); return $reader; } } diff --git a/tests/docs/.gitignore b/tests/docs/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/tests/docs/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file From 7afd0167b447b8dbc2c5067460a70557cbb06ab8 Mon Sep 17 00:00:00 2001 From: Simone Todaro Date: Mon, 11 Sep 2017 08:23:33 +0100 Subject: [PATCH 18/28] Add support for relationships --- src/Importer/AbstractSpreadsheet.php | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/Importer/AbstractSpreadsheet.php b/src/Importer/AbstractSpreadsheet.php index 788fc69..52e88e0 100644 --- a/src/Importer/AbstractSpreadsheet.php +++ b/src/Importer/AbstractSpreadsheet.php @@ -118,13 +118,35 @@ public function save($updateIfEquals = []) } else { $data = $this->parser->transform($row, $headers); if ($data !== false) { + $relationships = []; $when = array_intersect_key($data, $updateIfEquals); $values = array_diff($data, $when); + + foreach ($values as $key => $val) { + if (method_exists($this->model, $key)) { + unset($values[$key]); + $relationships[$key] = $val; + } + } + if (!empty($when)) { $this->model->getQuery()->updateOrInsert($when, $values); } else { $this->model->getQuery()->insert($values); } + + if (count($relationships)) { + $model = $this->model->where($values) + ->orderBy($this->model->getKeyName(), 'desc') + ->first(); + foreach ($relationships as $key => $val) { + if (is_array($val)) { + $model->{$key}()->createMany($val); + } else { + $model->{$key}()->associate($val); + } + } + } } } } From 1cbf687f4cdee596b31fd745a1ebf741837c27e9 Mon Sep 17 00:00:00 2001 From: Simone Todaro Date: Mon, 11 Sep 2017 08:34:25 +0100 Subject: [PATCH 19/28] Update AbstractSpreadsheet.php --- src/Importer/AbstractSpreadsheet.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Importer/AbstractSpreadsheet.php b/src/Importer/AbstractSpreadsheet.php index 52e88e0..5c70e17 100644 --- a/src/Importer/AbstractSpreadsheet.php +++ b/src/Importer/AbstractSpreadsheet.php @@ -25,6 +25,7 @@ public function __construct() $this->type = $this->getType(); $this->parser = new BasicParser(); $this->model = false; + $this->callbacks = collect([]); } public function __call($name, $args) From 2d423063c66e0d593904e8e812e0f63ce1eb7507 Mon Sep 17 00:00:00 2001 From: Simone Todaro Date: Mon, 11 Sep 2017 08:41:13 +0100 Subject: [PATCH 20/28] Update AbstractSpreadsheet.php --- src/Importer/AbstractSpreadsheet.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Importer/AbstractSpreadsheet.php b/src/Importer/AbstractSpreadsheet.php index 5c70e17..8a85f88 100644 --- a/src/Importer/AbstractSpreadsheet.php +++ b/src/Importer/AbstractSpreadsheet.php @@ -121,7 +121,7 @@ public function save($updateIfEquals = []) if ($data !== false) { $relationships = []; $when = array_intersect_key($data, $updateIfEquals); - $values = array_diff($data, $when); + $values = array_diff_key($data, $when); foreach ($values as $key => $val) { if (method_exists($this->model, $key)) { From 04a34629dd2e46a0f6c7e1c0f5331f00839b67a5 Mon Sep 17 00:00:00 2001 From: Muhammad Zamroni Date: Fri, 6 Oct 2017 12:55:36 +0700 Subject: [PATCH 21/28] Add package auto discovery feature support for Laravel 5.5 --- README.md | 24 ++++++++++++++++++++++-- composer.json | 7 +++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1c46670..d5c0db2 100644 --- a/README.md +++ b/README.md @@ -21,9 +21,29 @@ Use composer to download the package: composer require cyber-duck/laravel-excel ``` -Register the service provider in `config/app.php` adding *Cyberduck\LaravelExcel\ExcelServiceProvider* to the provider array. +### Laravel 4.x -Note. If you are on Laravel 4, use *Cyberduck\LaravelExcel\ExcelLegacyServiceProvider* +Register the service provider in `app/config/app.php` by adding this line to providers array. + +```php +'providers' => [ + 'Cyberduck\LaravelExcel\ExcelLegacyServiceProvider', +], +``` + +### Laravel < 5.5 + +Register the service provider in `config/app.php` by adding this line to providers array. + +```php +'providers' => [ + 'Cyberduck\LaravelExcel\ExcelServiceProvider', +], +``` + +### Laravel 5.5 + +No need to register anything, since it used package auto discovery feature in Laravel 5.5. ## Export Excel diff --git a/composer.json b/composer.json index e258ae0..7f416b8 100644 --- a/composer.json +++ b/composer.json @@ -36,5 +36,12 @@ "tests/utils/FirstColumnOnlySerialiser.php" ] }, + "extra": { + "laravel": { + "providers": [ + "Cyberduck\\LaravelExcel\\ExcelServiceProvider" + ] + } + }, "minimum-stability": "stable" } From 0459b7cf4ead5ce56925d50337db47493bc18b02 Mon Sep 17 00:00:00 2001 From: wisdom sambian Date: Thu, 26 Oct 2017 09:58:34 +0000 Subject: [PATCH 22/28] Update README.md *getData(Model $data)* must return an array of string, and every elements is a cell. - Casting against the MODEL in the getData() produce error. It expects an array $data. It should be getData($data) instead. Thanks --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1c46670..20380c4 100644 --- a/README.md +++ b/README.md @@ -94,7 +94,7 @@ use Cyberduck\LaravelExcel\Contract\SerialiserInterface; class ExampleSerialiser implements SerialiserInterface { - public function getData(Model $data) + public function getData($data) { $row = []; From 0189f494d107e80007f0b85beb4c007ba679a430 Mon Sep 17 00:00:00 2001 From: Stefano Kowalke Date: Mon, 4 Dec 2017 12:13:26 +0100 Subject: [PATCH 23/28] Make the Importer fluent --- README.md | 2 +- src/Importer/AbstractSpreadsheet.php | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1c46670..e7e95e5 100644 --- a/README.md +++ b/README.md @@ -131,7 +131,7 @@ $collection = $excel->getCollection(); The importer class is fluent, then you can also write ``` -return Importer::make('Excel')->getCollection($filepath)->getCollection(); +return Importer::make('Excel')->load($filepath)->getCollection(); ``` ### Advanced usage diff --git a/src/Importer/AbstractSpreadsheet.php b/src/Importer/AbstractSpreadsheet.php index 8a85f88..1a8aa8a 100644 --- a/src/Importer/AbstractSpreadsheet.php +++ b/src/Importer/AbstractSpreadsheet.php @@ -37,11 +37,13 @@ public function __call($name, $args) public function load($path) { $this->path = $path; + return $this; } public function setSheet($sheet) { $this->sheet = $sheet; + return $this; } public function hasHeader($hasHeaderRow) @@ -52,11 +54,13 @@ public function hasHeader($hasHeaderRow) public function setParser(ParserInterface $parser) { $this->parser = $parser; + return $this; } public function setModel(Model $model) { $this->model = $model; + return $this; } abstract public function getType(); From c059429c4577f61f6f5019516241d757311d0f17 Mon Sep 17 00:00:00 2001 From: Simone Todaro Date: Fri, 31 Aug 2018 20:50:15 +0100 Subject: [PATCH 24/28] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d5c0db2..a8fea18 100644 --- a/README.md +++ b/README.md @@ -23,11 +23,11 @@ composer require cyber-duck/laravel-excel ### Laravel 4.x -Register the service provider in `app/config/app.php` by adding this line to providers array. +Register the service provider in `config/app.php` by adding this line to providers array. ```php 'providers' => [ - 'Cyberduck\LaravelExcel\ExcelLegacyServiceProvider', + Cyberduck\LaravelExcel\ExcelLegacyServiceProvider::class, ], ``` @@ -37,7 +37,7 @@ Register the service provider in `config/app.php` by adding this line to provide ```php 'providers' => [ - 'Cyberduck\LaravelExcel\ExcelServiceProvider', + Cyberduck\LaravelExcel\ExcelServiceProvider::class, ], ``` From d9f8d708a678f717ae082b45a9b6e7653deafb4e Mon Sep 17 00:00:00 2001 From: Simone Todaro Date: Fri, 31 Aug 2018 22:21:07 +0100 Subject: [PATCH 25/28] Update README.md --- README.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1d9c560..7a7e832 100644 --- a/README.md +++ b/README.md @@ -133,6 +133,10 @@ class ExampleSerialiser implements SerialiserInterface } } ``` +then set the serialiser before saving the file the collection. +``` +$collection = Exporter::make('Excel')->load($yourCollection)->setSerialiser(new ExampleSerialiser)->stream($yourFileName); +``` ## Import Excel Add @@ -175,9 +179,9 @@ namespace App\Parsers; use App\Models\YourModel; use Cyberduck\LaravelExcel\Contract\ParserInterface; -class ExampleSerialiser implements ParserInterface +class ExampleParser implements ParserInterface { - public function transform($row) + public function transform($row, $header) { $model = new YourModel(); $model->field1 = $row[0]; @@ -188,6 +192,10 @@ class ExampleSerialiser implements ParserInterface } } ``` +then set the parser before creating the collection. +``` +$collection = Importer::make('Excel')->load($filepath)->setParser(new ExampleParser)->getCollection(); +``` ## Different formats The package supports ODS and CSV files. From 7b747817befed5ee2d50d7865b5d4087205ba67b Mon Sep 17 00:00:00 2001 From: Mohammed Jammeh <> Date: Thu, 26 Mar 2020 11:09:49 +0000 Subject: [PATCH 26/28] This package and its dependencies has been upgraded to use laravel 6. --- composer.json | 14 ++++---- phpunit.xml | 5 ++- src/Exporter/AbstractSpreadsheet.php | 27 ++++++++------ src/Exporter/Csv.php | 6 ++++ src/Exporter/Excel.php | 6 ++++ src/Exporter/OpenOffice.php | 6 ++++ src/Importer/AbstractSpreadsheet.php | 13 +++---- src/Importer/Csv.php | 6 ++++ src/Importer/Excel.php | 6 ++++ src/Importer/OpenOffice.php | 6 ++++ tests/TestCase.php | 6 ++-- tests/Unit/ExporterTest.php | 54 ++++++++++++++-------------- 12 files changed, 101 insertions(+), 54 deletions(-) diff --git a/composer.json b/composer.json index 7f416b8..3218a10 100644 --- a/composer.json +++ b/composer.json @@ -12,15 +12,15 @@ } ], "require": { - "php": ">=5.4.0", - "box/spout": "^2.4", - "illuminate/database": "4.*|5.*", - "illuminate/support": "4.*|5.*" + "php": "^7.2.5", + "box/spout": "^3.1", + "illuminate/database": "^6.0.0", + "illuminate/support": "^6.0.0" }, "require-dev": { - "phpunit/phpunit": "~4.0", - "phpspec/phpspec": "~2.1", - "laravel/laravel": "~5.3" + "phpunit/phpunit": "^7.0", + "phpspec/phpspec": "^6.1.1", + "laravel/laravel": "^6.0.0" }, "autoload": { "psr-4": { diff --git a/phpunit.xml b/phpunit.xml index 6d55c5c..edc9687 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -8,8 +8,11 @@ convertWarningsToExceptions="true" processIsolation="false" stopOnFailure="false" - syntaxCheck="false" > + + + + ./tests/ diff --git a/src/Exporter/AbstractSpreadsheet.php b/src/Exporter/AbstractSpreadsheet.php index 0eb1a90..d3c1118 100644 --- a/src/Exporter/AbstractSpreadsheet.php +++ b/src/Exporter/AbstractSpreadsheet.php @@ -2,7 +2,7 @@ namespace Cyberduck\LaravelExcel\Exporter; use Illuminate\Support\Collection; -use Box\Spout\Writer\WriterFactory; +use Box\Spout\Writer\Common\Creator\WriterEntityFactory; use Illuminate\Database\Query\Builder; use Cyberduck\LaravelExcel\Serialiser\BasicSerialiser; use Cyberduck\LaravelExcel\Contract\SerialiserInterface; @@ -56,6 +56,8 @@ public function setSerialiser(SerialiserInterface $serialiser) abstract public function getType(); + abstract public function createWriter(); + public function save($filename) { $writer = $this->create(); @@ -74,7 +76,7 @@ public function stream($filename) protected function create() { - $writer = WriterFactory::create($this->type); + $writer = $this->createWriter(); $this->callbacks->each(function ($elem) use (&$writer) { call_user_func_array(array($writer, $elem[0]), $elem[1]); }); @@ -85,22 +87,27 @@ protected function makeRows($writer) { $headerRow = $this->serialiser->getHeaderRow(); if (!empty($headerRow)) { - $writer->addRow($headerRow); + $row = WriterEntityFactory::createRowFromArray($headerRow); + $writer->addRow($row); } if ($this->data instanceof Builder) { if (isset($this->chuncksize)) { $this->data->chunk($this->chuncksize); } else { - $data = $this->data->get(); - foreach ($data as $record) { - $writer->addRow($this->serialiser->getData($record)); - } + $this->addRowsDataToWriter($this->data->get(), $writer); } } else { - foreach ($this->data as $record) { - $writer->addRow($this->serialiser->getData($record)); - } + $this->addRowsDataToWriter($this->data, $writer); } return $writer; } + + public function addRowsDataToWriter($data, $writer) + { + foreach ($data as $record) { + $recordData = $this->serialiser->getData($record); + $row = WriterEntityFactory::createRowFromArray($recordData); + $writer->addRow($row); + } + } } diff --git a/src/Exporter/Csv.php b/src/Exporter/Csv.php index 6fda1a6..8fe2c18 100644 --- a/src/Exporter/Csv.php +++ b/src/Exporter/Csv.php @@ -2,6 +2,7 @@ namespace Cyberduck\LaravelExcel\Exporter; use Box\Spout\Common\Type; +use Box\Spout\Writer\Common\Creator\WriterEntityFactory; class Csv extends AbstractSpreadsheet { @@ -9,4 +10,9 @@ public function getType() { return Type::CSV; } + + public function createWriter() + { + return WriterEntityFactory::createCSVWriter(); + } } diff --git a/src/Exporter/Excel.php b/src/Exporter/Excel.php index 0a858a0..8983e6e 100644 --- a/src/Exporter/Excel.php +++ b/src/Exporter/Excel.php @@ -2,6 +2,7 @@ namespace Cyberduck\LaravelExcel\Exporter; use Box\Spout\Common\Type; +use Box\Spout\Writer\Common\Creator\WriterEntityFactory; class Excel extends AbstractSpreadsheet { @@ -9,4 +10,9 @@ public function getType() { return Type::XLSX; } + + public function createWriter() + { + return WriterEntityFactory::createXLSXWriter(); + } } diff --git a/src/Exporter/OpenOffice.php b/src/Exporter/OpenOffice.php index 9e28199..15b0970 100644 --- a/src/Exporter/OpenOffice.php +++ b/src/Exporter/OpenOffice.php @@ -2,6 +2,7 @@ namespace Cyberduck\LaravelExcel\Exporter; use Box\Spout\Common\Type; +use Box\Spout\Writer\Common\Creator\WriterEntityFactory; class OpenOffice extends AbstractSpreadsheet { @@ -9,4 +10,9 @@ public function getType() { return Type::ODS; } + + public function createWriter() + { + return WriterEntityFactory::createODSWriter(); + } } diff --git a/src/Importer/AbstractSpreadsheet.php b/src/Importer/AbstractSpreadsheet.php index 1a8aa8a..d94d337 100644 --- a/src/Importer/AbstractSpreadsheet.php +++ b/src/Importer/AbstractSpreadsheet.php @@ -1,7 +1,6 @@ getRowIterator() as $rowindex => $row) { if ($rowindex == 1 && $this->hasHeaderRow) { - $headers = $row; + $headers = $row->toArray(); } else { - $data = $this->parser->transform($row, $headers); + $data = $this->parser->transform($row->toArray(), $headers); if ($data !== false) { if ($this->model) { @@ -119,9 +120,9 @@ public function save($updateIfEquals = []) foreach ($sheet->getRowIterator() as $rowindex => $row) { if ($rowindex == 1 && $this->hasHeaderRow) { - $headers = $row; + $headers = $row->toArray(); } else { - $data = $this->parser->transform($row, $headers); + $data = $this->parser->transform($row->toArray(), $headers); if ($data !== false) { $relationships = []; $when = array_intersect_key($data, $updateIfEquals); @@ -160,7 +161,7 @@ public function save($updateIfEquals = []) protected function open() { - $reader= ReaderFactory::create($this->type); + $reader = $this->createReader(); $reader->open($this->path); $this->callbacks->each(function ($elem) use (&$writer) { call_user_func_array(array($writer, $elem[0]), $elem[1]); diff --git a/src/Importer/Csv.php b/src/Importer/Csv.php index f91e380..dc23e4d 100644 --- a/src/Importer/Csv.php +++ b/src/Importer/Csv.php @@ -2,6 +2,7 @@ namespace Cyberduck\LaravelExcel\Importer; use Box\Spout\Common\Type; +use Box\Spout\Reader\Common\Creator\ReaderEntityFactory; class Csv extends AbstractSpreadsheet { @@ -9,4 +10,9 @@ public function getType() { return Type::CSV; } + + public function createReader() + { + return ReaderEntityFactory::createCSVReader(); + } } diff --git a/src/Importer/Excel.php b/src/Importer/Excel.php index b5e51b9..6389825 100644 --- a/src/Importer/Excel.php +++ b/src/Importer/Excel.php @@ -2,6 +2,7 @@ namespace Cyberduck\LaravelExcel\Importer; use Box\Spout\Common\Type; +use Box\Spout\Reader\Common\Creator\ReaderEntityFactory; class Excel extends AbstractSpreadsheet { @@ -9,4 +10,9 @@ public function getType() { return Type::XLSX; } + + public function createReader() + { + return ReaderEntityFactory::createXLSXReader(); + } } diff --git a/src/Importer/OpenOffice.php b/src/Importer/OpenOffice.php index abd2b3e..b936d39 100644 --- a/src/Importer/OpenOffice.php +++ b/src/Importer/OpenOffice.php @@ -2,6 +2,7 @@ namespace Cyberduck\LaravelExcel\Importer; use Box\Spout\Common\Type; +use Box\Spout\Reader\Common\Creator\ReaderEntityFactory; class OpenOffice extends AbstractSpreadsheet { @@ -9,4 +10,9 @@ public function getType() { return Type::ODS; } + + public function createReader() + { + return ReaderEntityFactory::createODSReader(); + } } diff --git a/tests/TestCase.php b/tests/TestCase.php index 0f5ef32..7514f6e 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -6,7 +6,7 @@ class TestCase extends BaseTestCase { protected $baseUrl = 'http://localhost'; - const DEFAULT_ROW = [ + protected $defaultRow = [ 'field1' => 'A', 'field2' => 'B', 'field3' => 'C', @@ -39,7 +39,7 @@ public function createApplication() * * @return void */ - public function setUp() + public function setUp() : void { parent::setUp(); @@ -53,7 +53,7 @@ public function seed($item = 10) $rows = []; $limit = ($j>floor($item/50)) ? 50 : ($item-($j*50)); for ($i = 0; $i<$limit; $i++) { - $rows[] = self::DEFAULT_ROW; + $rows[] = $this->defaultRow; } DB::table('items')->insert($rows); } diff --git a/tests/Unit/ExporterTest.php b/tests/Unit/ExporterTest.php index aaf16cd..4da2c9c 100644 --- a/tests/Unit/ExporterTest.php +++ b/tests/Unit/ExporterTest.php @@ -1,19 +1,19 @@ file = __DIR__.'/../docs/test.xlsx'; (new Migration)->up(); } - public function tearDown() + public function tearDown() : void { (new Migration)->down(); parent::tearDown(); @@ -30,11 +30,11 @@ public function test_can_export_csv() //Read the content $lines = 0; - $reader = ReaderFactory::create(Type::CSV); - $reader->open(self::FILE); + $reader = ReaderEntityFactory::createCSVReader(); + $reader->open($this->file); foreach ($reader->getSheetIterator() as $index => $sheet) { foreach ($sheet->getRowIterator() as $row) { - $this->assertEquals(array_values(self::DEFAULT_ROW), $row); + $this->assertEquals(array_values($this->defaultRow), $row->toArray()); $lines++; } } @@ -44,7 +44,7 @@ public function test_can_export_csv() unlink(self::FILE); } - public function test_can_export_odt() + public function test_can_export_ods() { $itemsToSeed = 2; $this->seed($itemsToSeed); @@ -55,11 +55,11 @@ public function test_can_export_odt() //Read the content $lines = 0; - $reader = ReaderFactory::create(Type::ODS); - $reader->open(self::FILE); + $reader = ReaderEntityFactory::createODSReader(); + $reader->open($this->file); foreach ($reader->getSheetIterator() as $index => $sheet) { foreach ($sheet->getRowIterator() as $row) { - $this->assertEquals(array_values(self::DEFAULT_ROW), $row); + $this->assertEquals(array_values($this->defaultRow), $row->toArray()); $lines++; } } @@ -80,11 +80,11 @@ public function test_can_export_xlsx() //Read the content $lines = 0; - $reader = ReaderFactory::create(Type::XLSX); - $reader->open(self::FILE); + $reader = ReaderEntityFactory::createXLSXReader(); + $reader->open($this->file); foreach ($reader->getSheetIterator() as $index => $sheet) { foreach ($sheet->getRowIterator() as $row) { - $this->assertEquals(array_values(self::DEFAULT_ROW), $row); + $this->assertEquals(array_values($this->defaultRow), $row->toArray()); $lines++; } } @@ -105,12 +105,12 @@ public function test_can_use_a_query_builder() //Read the content $lines = 0; - $reader = ReaderFactory::create(Type::CSV); - $reader->open(self::FILE); + $reader = ReaderEntityFactory::createCSVReader(); + $reader->open($this->file); foreach ($reader->getSheetIterator() as $index => $sheet) { foreach ($sheet->getRowIterator() as $idx => $row) { - $expected = array_merge([strval($idx)], array_values(self::DEFAULT_ROW)); - $this->assertEquals($expected, $row); + $expected = array_merge([strval($idx)], array_values($this->defaultRow)); + $this->assertEquals($expected, $row->toArray()); $lines++; } } @@ -131,12 +131,12 @@ public function test_can_use_a_query_builder_with_chunk() //Read the content $lines = 0; - $reader = ReaderFactory::create(Type::CSV); - $reader->open(self::FILE); + $reader = ReaderEntityFactory::createCSVReader(); + $reader->open($this->file); foreach ($reader->getSheetIterator() as $index => $sheet) { foreach ($sheet->getRowIterator() as $idx => $row) { - $expected = array_merge([strval($idx)], array_values(self::DEFAULT_ROW)); - $this->assertEquals($expected, $row); + $expected = array_merge([strval($idx)], array_values($this->defaultRow)); + $this->assertEquals($expected, $row->toArray()); $lines++; } } @@ -157,14 +157,14 @@ public function test_can_use_a_custom_serialiser() //Read the content $lines = 0; - $reader = ReaderFactory::create(Type::CSV); - $reader->open(self::FILE); + $reader = ReaderEntityFactory::createCSVReader(); + $reader->open($this->file); foreach ($reader->getSheetIterator() as $index => $sheet) { foreach ($sheet->getRowIterator() as $row) { if ($lines == 0) { - $this->assertEquals(['HEADER'], $row); + $this->assertEquals(['HEADER'], $row->toArray()); } else { - $this->assertEquals(['A'], $row); + $this->assertEquals(['A'], $row->toArray()); } $lines++; } From e323223c1286acacb0f4f88e323ad803fe0bb6a5 Mon Sep 17 00:00:00 2001 From: Neil Date: Mon, 30 Mar 2020 15:27:44 +0100 Subject: [PATCH 27/28] Added laravel 7 to supported versions --- composer.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/composer.json b/composer.json index 3218a10..01b4972 100644 --- a/composer.json +++ b/composer.json @@ -14,13 +14,13 @@ "require": { "php": "^7.2.5", "box/spout": "^3.1", - "illuminate/database": "^6.0.0", - "illuminate/support": "^6.0.0" + "illuminate/database": "^6.0.0|^7.0.0", + "illuminate/support": "^6.0.0|^7.0.0" }, "require-dev": { "phpunit/phpunit": "^7.0", - "phpspec/phpspec": "^6.1.1", - "laravel/laravel": "^6.0.0" + "phpspec/phpspec": "^6.1.1|^7.0.0", + "laravel/laravel": "^6.0.0|^7.0.0" }, "autoload": { "psr-4": { From 8dc4cbe266c63feeb362fce0eb0f3c5a6823847f Mon Sep 17 00:00:00 2001 From: Neil Date: Mon, 30 Mar 2020 15:32:31 +0100 Subject: [PATCH 28/28] Remove mistake from composer file --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 01b4972..c881277 100644 --- a/composer.json +++ b/composer.json @@ -19,7 +19,7 @@ }, "require-dev": { "phpunit/phpunit": "^7.0", - "phpspec/phpspec": "^6.1.1|^7.0.0", + "phpspec/phpspec": "^6.1.1", "laravel/laravel": "^6.0.0|^7.0.0" }, "autoload": {