diff --git a/README.md b/README.md index 6d7ff7d..7a7e832 100644 --- a/README.md +++ b/README.md @@ -1,85 +1,125 @@ -# 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) + +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) +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 +Use composer to download the package: +``` +composer require cyber-duck/laravel-excel +``` + +### Laravel 4.x + +Register the service provider in `config/app.php` by adding this line to providers array. -## Installation -The package must be installed directly from [Composer](https://getcomposer.org/). -Run the following command: +```php +'providers' => [ + Cyberduck\LaravelExcel\ExcelLegacyServiceProvider::class, +], ``` -$ composer require cyberduck/laravel-excel + +### Laravel < 5.5 + +Register the service provider in `config/app.php` by adding this line to providers array. + +```php +'providers' => [ + Cyberduck\LaravelExcel\ExcelServiceProvider::class, +], ``` -To make Facades available, register the service provider in config/app.php adding *Cyberduck\LaravelExcel\ExcelServiceProvider* to the provider array. +### Laravel 5.5 -Note. If you are on Laravel 4, use *Cyberduck\LaravelExcel\ExcelLegacyServiceProvider* +No need to register anything, since it used package auto discovery feature in Laravel 5.5. ## Export Excel ### Generate and download an excel file -Add +Add ``` use Exporter; -``` +``` to your controller. -In your action, add +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 action, add +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 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*, 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); +``` -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. +*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 ``` -namespace App\Serialiser; +namespace App\Serialisers; use Illuminate\Database\Eloquent\Model; use Cyberduck\LaravelExcel\Contract\SerialiserInterface; class ExampleSerialiser implements SerialiserInterface { - public function getData(Model $data) + public function getData($data) { $row = []; $row[] = $data->field1; - $row[] = $data->relation->field2; + $row[] = $data->relationship->field2; return $row; } @@ -88,14 +128,86 @@ class ExampleSerialiser implements SerialiserInterface { return [ 'Field 1', - 'Field 2 (from a relation)' + 'Field 2 (from a relationship)' ]; } } ``` +then set the serialiser before saving the file the collection. +``` +$collection = Exporter::make('Excel')->load($yourCollection)->setSerialiser(new ExampleSerialiser)->stream($yourFileName); +``` ## 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')->load($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 extending *Cyberduck\LaravelExcel\Contract\ParserInterface* and implement the methods *transform($row)*. + +Example +``` +namespace App\Parsers; + +use App\Models\YourModel; +use Cyberduck\LaravelExcel\Contract\ParserInterface; + +class ExampleParser implements ParserInterface +{ + public function transform($row, $header) + { + $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; + } +} +``` +then set the parser before creating the collection. +``` +$collection = Importer::make('Excel')->load($filepath)->setParser(new ExampleParser)->getCollection(); +``` ## Different formats -Coming soon! +The package 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 a009c4c..c881277 100644 --- a/composer.json +++ b/composer.json @@ -1,25 +1,47 @@ { - "name": "cyberduck/laravel-excel", + "name": "cyber-duck/laravel-excel", "type": "library", - "description": "", - "keywords": ["Laravel", "Excel"], - "require": { - "php": ">=5.4.0", - "box/spout": "^2.4", - "illuminate/database": "4.*|5.1", - "illuminate/support": "4.*|5.1" - }, + "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", "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": "^7.2.5", + "box/spout": "^3.1", + "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|^7.0.0" + }, "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" + ] + }, + "extra": { + "laravel": { + "providers": [ + "Cyberduck\\LaravelExcel\\ExcelServiceProvider" + ] + } + }, + "minimum-stability": "stable" } diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..edc9687 --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,22 @@ + + + + + + + + + ./tests/ + ./tests/views + + + \ No newline at end of file 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..d3c1118 100644 --- a/src/Exporter/AbstractSpreadsheet.php +++ b/src/Exporter/AbstractSpreadsheet.php @@ -1,8 +1,9 @@ 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) { @@ -27,6 +36,18 @@ public function load(Collection $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; @@ -35,6 +56,8 @@ public function setSerialiser(SerialiserInterface $serialiser) abstract public function getType(); + abstract public function createWriter(); + public function save($filename) { $writer = $this->create(); @@ -53,18 +76,38 @@ public function stream($filename) protected function create() { - return WriterFactory::create($this->type); + $writer = $this->createWriter(); + $this->callbacks->each(function ($elem) use (&$writer) { + call_user_func_array(array($writer, $elem[0]), $elem[1]); + }); + return $writer; } protected function makeRows($writer) { $headerRow = $this->serialiser->getHeaderRow(); if (!empty($headerRow)) { - $writer->addRow($headerRow); + $row = WriterEntityFactory::createRowFromArray($headerRow); + $writer->addRow($row); } - 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 { + $this->addRowsDataToWriter($this->data->get(), $writer); + } + } else { + $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 12fa276..d94d337 100644 --- a/src/Importer/AbstractSpreadsheet.php +++ b/src/Importer/AbstractSpreadsheet.php @@ -1,8 +1,7 @@ path = ''; - $this->sheet = 0; + $this->sheet = 1; + $this->hasHeaderRow = 0; $this->type = $this->getType(); $this->parser = new BasicParser(); + $this->model = false; + $this->callbacks = collect([]); + } + + public function __call($name, $args) + { + $this->callbacks->push([$name, $args]); + return $this; } public function load($path) { $this->path = $path; + return $this; } public function setSheet($sheet) { $this->sheet = $sheet; + return $this; + } + + public function hasHeader($hasHeaderRow) + { + $this->hasHeaderRow = $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(); + abstract public function createReader(); + public function getCollection() { - $reader = $this->create(); - $reader->open(); - $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->hasHeaderRow) { + $headers = $row->toArray(); + } else { + $data = $this->parser->transform($row->toArray(), $headers); + + if ($data !== false) { + if ($this->model) { + $data = $this->model->getQuery()->newInstance($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->getData($row); + + foreach ($sheet->getRowIterator() as $rowindex => $row) { + if ($rowindex == 1 && $this->hasHeaderRow) { + $headers = $row->toArray(); + } else { + $data = $this->parser->transform($row->toArray(), $headers); + if ($data !== false) { + $relationships = []; + $when = array_intersect_key($data, $updateIfEquals); + $values = array_diff_key($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); + } + } + } + } + } } } - return collect($collection); + } + + protected function open() + { + $reader = $this->createReader(); + $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/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/src/Parser/BasicParser.php b/src/Parser/BasicParser.php index 86824e3..bc179b6 100644 --- a/src/Parser/BasicParser.php +++ b/src/Parser/BasicParser.php @@ -1,12 +1,21 @@ toArray(); + if ($data instanceof Model) { + return $data->toArray(); + } elseif (is_array($data)) { + return $data; + } else { + return get_object_vars($data); + } } public function getHeaderRow() diff --git a/tests/TestCase.php b/tests/TestCase.php new file mode 100644 index 0000000..7514f6e --- /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() : void + { + 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[] = $this->defaultRow; + } + DB::table('items')->insert($rows); + } + } +} diff --git a/tests/Unit/ExporterTest.php b/tests/Unit/ExporterTest.php new file mode 100644 index 0000000..4da2c9c --- /dev/null +++ b/tests/Unit/ExporterTest.php @@ -0,0 +1,176 @@ +file = __DIR__.'/../docs/test.xlsx'; + (new Migration)->up(); + } + + public function tearDown() : void + { + (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 = ReaderEntityFactory::createCSVReader(); + $reader->open($this->file); + foreach ($reader->getSheetIterator() as $index => $sheet) { + foreach ($sheet->getRowIterator() as $row) { + $this->assertEquals(array_values($this->defaultRow), $row->toArray()); + $lines++; + } + } + $reader->close(); + $this->assertEquals($itemsToSeed, $lines); + + unlink(self::FILE); + } + + public function test_can_export_ods() + { + $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 = ReaderEntityFactory::createODSReader(); + $reader->open($this->file); + foreach ($reader->getSheetIterator() as $index => $sheet) { + foreach ($sheet->getRowIterator() as $row) { + $this->assertEquals(array_values($this->defaultRow), $row->toArray()); + $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 = ReaderEntityFactory::createXLSXReader(); + $reader->open($this->file); + foreach ($reader->getSheetIterator() as $index => $sheet) { + foreach ($sheet->getRowIterator() as $row) { + $this->assertEquals(array_values($this->defaultRow), $row->toArray()); + $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 = 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($this->defaultRow)); + $this->assertEquals($expected, $row->toArray()); + $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 = 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($this->defaultRow)); + $this->assertEquals($expected, $row->toArray()); + $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 = ReaderEntityFactory::createCSVReader(); + $reader->open($this->file); + foreach ($reader->getSheetIterator() as $index => $sheet) { + foreach ($sheet->getRowIterator() as $row) { + if ($lines == 0) { + $this->assertEquals(['HEADER'], $row->toArray()); + } else { + $this->assertEquals(['A'], $row->toArray()); + } + $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/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 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'); + } +}