From efe123cd177de243a155e14e1a61f28892330966 Mon Sep 17 00:00:00 2001 From: Maarten Visscher Date: Tue, 5 Mar 2024 10:43:37 +0100 Subject: [PATCH 1/2] Basic OpenSpout Excel exporter --- composer.json | 4 +- src/Exporter/Excel/ExcelOpenSpoutExporter.php | 49 ++++++++++ src/Resources/config/services.xml | 4 + .../Excel/ExcelOpenSpoutExporterTest.php | 94 +++++++++++++++++++ 4 files changed, 150 insertions(+), 1 deletion(-) create mode 100755 src/Exporter/Excel/ExcelOpenSpoutExporter.php create mode 100755 tests/Functional/Exporter/Excel/ExcelOpenSpoutExporterTest.php diff --git a/composer.json b/composer.json index e5c2a3bf..260194f6 100644 --- a/composer.json +++ b/composer.json @@ -40,6 +40,7 @@ "friendsofphp/php-cs-fixer": "^v3.40.0", "mongodb/mongodb": "^1.17", "ocramius/package-versions": "^2.8", + "openspout/openspout": "^4.23", "phpoffice/phpspreadsheet": "^1.29.0 || ^2.0", "phpstan/extension-installer": "^1.3.1", "phpstan/phpstan": "^1.10.55", @@ -65,7 +66,8 @@ "mongodb/mongodb": "For integration with MongoDB collections", "ruflin/elastica": "For integration with Elasticsearch indexes", "symfony/twig-bundle": "To use default Twig based rendering and TwigColumn", - "phpoffice/phpspreadsheet": "To export the data from DataTables to Excel" + "phpoffice/phpspreadsheet": "To export the data from DataTables to Excel", + "openspout/openspout": "To use the OpenSpout Excel exporter" }, "autoload": { "psr-4": { "Omines\\DataTablesBundle\\": "src/"} diff --git a/src/Exporter/Excel/ExcelOpenSpoutExporter.php b/src/Exporter/Excel/ExcelOpenSpoutExporter.php new file mode 100755 index 00000000..32661145 --- /dev/null +++ b/src/Exporter/Excel/ExcelOpenSpoutExporter.php @@ -0,0 +1,49 @@ +openToFile($filePath); + + // Write header + $boldStyle = (new Style())->setFontBold(); + $writer->addRow(Row::fromValues($columnNames, $boldStyle)); + + // Write data + foreach ($data as $row) { + // Remove HTML tags + $values = array_map('strip_tags', $row); + + $writer->addRow(Row::fromValues($values)); + } + + $writer->close(); + + return new \SplFileInfo($filePath); + } + + public function getMimeType(): string + { + return 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'; + } + + public function getName(): string + { + return 'excel-openspout'; + } +} diff --git a/src/Resources/config/services.xml b/src/Resources/config/services.xml index 450d4dbf..2b69fe8c 100644 --- a/src/Resources/config/services.xml +++ b/src/Resources/config/services.xml @@ -38,6 +38,10 @@ + + + + diff --git a/tests/Functional/Exporter/Excel/ExcelOpenSpoutExporterTest.php b/tests/Functional/Exporter/Excel/ExcelOpenSpoutExporterTest.php new file mode 100755 index 00000000..b499c81b --- /dev/null +++ b/tests/Functional/Exporter/Excel/ExcelOpenSpoutExporterTest.php @@ -0,0 +1,94 @@ +client = self::createClient(); + } + + public function testExport(): void + { + $this->client->request('POST', '/exporter', ['_dt' => 'dt', '_exporter' => 'excel-openspout']); + + $response = $this->client->getResponse(); + + // Using PhpSpreadsheet for tests + $sheet = IOFactory::load($response->getFile()->getPathname())->getActiveSheet(); + + static::assertSame('dt.columns.firstName', $sheet->getCell('A1')->getFormattedValue()); + static::assertSame('dt.columns.lastName', $sheet->getCell('B1')->getFormattedValue()); + + static::assertSame('FirstName0', $sheet->getCell('A2')->getFormattedValue()); + static::assertSame('LastName0', $sheet->getCell('B2')->getFormattedValue()); + + static::assertSame('FirstName1', $sheet->getCell('A3')->getFormattedValue()); + static::assertSame('LastName1', $sheet->getCell('B3')->getFormattedValue()); + + static::assertSame('FirstName2', $sheet->getCell('A4')->getFormattedValue()); + static::assertSame('LastName2', $sheet->getCell('B4')->getFormattedValue()); + + static::assertSame('FirstName3', $sheet->getCell('A5')->getFormattedValue()); + static::assertSame('LastName3', $sheet->getCell('B5')->getFormattedValue()); + + static::assertSame('FirstName4', $sheet->getCell('A6')->getFormattedValue()); + static::assertSame('LastName4', $sheet->getCell('B6')->getFormattedValue()); + } + + public function testEmptyDataTable(): void + { + $this->client->request('POST', '/exporter-empty-datatable', ['_dt' => 'dt', '_exporter' => 'excel-openspout']); + + /** @var BinaryFileResponse $response */ + $response = $this->client->getResponse(); + + static::assertTrue($response->isSuccessful()); + + $sheet = IOFactory::load($response->getFile()->getPathname())->getActiveSheet(); + + static::assertSame('dt.columns.firstName', $sheet->getCell('A1')->getFormattedValue()); + static::assertSame('dt.columns.lastName', $sheet->getCell('B1')->getFormattedValue()); + + static::assertEmpty($sheet->getCell('A2')->getFormattedValue()); + static::assertEmpty($sheet->getCell('B2')->getFormattedValue()); + } + + /** + * @throws \PhpOffice\PhpSpreadsheet\Exception + * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception + */ + public function testWithSearch(): void + { + $this->client->request('POST', '/exporter', [ + '_dt' => 'dt', + '_exporter' => 'excel-openspout', + 'search' => ['value' => 'FirstName124'], + ]); + + /** @var BinaryFileResponse $response */ + $response = $this->client->getResponse(); + + $sheet = IOFactory::load($response->getFile()->getPathname())->getActiveSheet(); + + static::assertSame('dt.columns.firstName', $sheet->getCell('A1')->getFormattedValue()); + static::assertSame('dt.columns.lastName', $sheet->getCell('B1')->getFormattedValue()); + + static::assertSame('FirstName124', $sheet->getCell('A2')->getFormattedValue()); + static::assertSame('LastName124', $sheet->getCell('B2')->getFormattedValue()); + + static::assertEmpty($sheet->getCell('A3')->getFormattedValue()); + static::assertEmpty($sheet->getCell('B3')->getFormattedValue()); + } +} From 47540541235a4e1b3f2e0ec00817a229fbec12db Mon Sep 17 00:00:00 2001 From: Maarten Visscher Date: Tue, 5 Mar 2024 12:42:24 +0100 Subject: [PATCH 2/2] ExcelOpenSpoutExporter: test case for exporter collection --- src/Exporter/Excel/ExcelOpenSpoutExporter.php | 11 ++++- .../Excel/ExcelOpenSpoutExporterTest.php | 15 +++++-- .../Exporter/ExcelOpenSpoutExporterTest.php | 40 +++++++++++++++++++ 3 files changed, 61 insertions(+), 5 deletions(-) create mode 100755 tests/Unit/Exporter/ExcelOpenSpoutExporterTest.php diff --git a/src/Exporter/Excel/ExcelOpenSpoutExporter.php b/src/Exporter/Excel/ExcelOpenSpoutExporter.php index 32661145..a7226763 100755 --- a/src/Exporter/Excel/ExcelOpenSpoutExporter.php +++ b/src/Exporter/Excel/ExcelOpenSpoutExporter.php @@ -1,4 +1,13 @@ isSuccessful()); + // Using PhpSpreadsheet for tests $sheet = IOFactory::load($response->getFile()->getPathname())->getActiveSheet(); static::assertSame('dt.columns.firstName', $sheet->getCell('A1')->getFormattedValue()); @@ -65,10 +75,6 @@ public function testEmptyDataTable(): void static::assertEmpty($sheet->getCell('B2')->getFormattedValue()); } - /** - * @throws \PhpOffice\PhpSpreadsheet\Exception - * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception - */ public function testWithSearch(): void { $this->client->request('POST', '/exporter', [ @@ -80,6 +86,7 @@ public function testWithSearch(): void /** @var BinaryFileResponse $response */ $response = $this->client->getResponse(); + // Using PhpSpreadsheet for tests $sheet = IOFactory::load($response->getFile()->getPathname())->getActiveSheet(); static::assertSame('dt.columns.firstName', $sheet->getCell('A1')->getFormattedValue()); diff --git a/tests/Unit/Exporter/ExcelOpenSpoutExporterTest.php b/tests/Unit/Exporter/ExcelOpenSpoutExporterTest.php new file mode 100755 index 00000000..c8dc12c5 --- /dev/null +++ b/tests/Unit/Exporter/ExcelOpenSpoutExporterTest.php @@ -0,0 +1,40 @@ +bootKernel(); + + $this->exporterCollection = $this->getContainer()->get(DataTableExporterCollection::class); + } + + public function testTag(): void + { + $this->assertInstanceOf(ExcelOpenSpoutExporter::class, $this->exporterCollection->getByName('excel-openspout')); + } + + public function testName(): void + { + $this->assertSame('excel-openspout', $this->exporterCollection->getByName('excel-openspout')->getName()); + } +}