Skip to content

Commit

Permalink
Add Excel OpenSpout exporter (#332)
Browse files Browse the repository at this point in the history
* Basic OpenSpout Excel exporter

* ExcelOpenSpoutExporter: test case for exporter collection

---------

Co-authored-by: Maarten Visscher <[email protected]>
  • Loading branch information
mhvis and mhvis committed Mar 6, 2024
1 parent 668e7bd commit 879898d
Show file tree
Hide file tree
Showing 5 changed files with 206 additions and 1 deletion.
4 changes: 3 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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/"}
Expand Down
58 changes: 58 additions & 0 deletions src/Exporter/Excel/ExcelOpenSpoutExporter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php

/*
* Symfony DataTables Bundle
* (c) Omines Internetbureau B.V. - https://omines.nl/
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Omines\DataTablesBundle\Exporter\Excel;

use Omines\DataTablesBundle\Exporter\DataTableExporterInterface;
use OpenSpout\Common\Entity\Row;
use OpenSpout\Common\Entity\Style\Style;
use OpenSpout\Writer\XLSX\Writer;

/**
* Excel exporter using OpenSpout.
*/
class ExcelOpenSpoutExporter implements DataTableExporterInterface
{
public function export(array $columnNames, \Iterator $data): \SplFileInfo
{
$filePath = sys_get_temp_dir() . '/' . uniqid('dt') . '.xlsx';

$writer = new Writer();
$writer->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';
}
}
4 changes: 4 additions & 0 deletions src/Resources/config/services.xml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@
<tag name="datatables.exporter"/>
</service>

<service id="Omines\DataTablesBundle\Exporter\Excel\ExcelOpenSpoutExporter">
<tag name="datatables.exporter"/>
</service>

<service id="Omines\DataTablesBundle\Exporter\Csv\CsvExporter">
<tag name="datatables.exporter"/>
</service>
Expand Down
101 changes: 101 additions & 0 deletions tests/Functional/Exporter/Excel/ExcelOpenSpoutExporterTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
<?php

/*
* Symfony DataTables Bundle
* (c) Omines Internetbureau B.V. - https://omines.nl/
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Tests\Functional\Exporter\Excel;

use PhpOffice\PhpSpreadsheet\IOFactory;
use Symfony\Bundle\FrameworkBundle\KernelBrowser;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Component\HttpFoundation\BinaryFileResponse;

class ExcelOpenSpoutExporterTest extends WebTestCase
{
/** @var KernelBrowser */
private $client;

protected function setUp(): void
{
self::ensureKernelShutdown();
$this->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());

// 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::assertEmpty($sheet->getCell('A2')->getFormattedValue());
static::assertEmpty($sheet->getCell('B2')->getFormattedValue());
}

public function testWithSearch(): void
{
$this->client->request('POST', '/exporter', [
'_dt' => 'dt',
'_exporter' => 'excel-openspout',
'search' => ['value' => 'FirstName124'],
]);

/** @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());
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());
}
}
40 changes: 40 additions & 0 deletions tests/Unit/Exporter/ExcelOpenSpoutExporterTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

/*
* Symfony DataTables Bundle
* (c) Omines Internetbureau B.V. - https://omines.nl/
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Tests\Unit\Exporter;

use Omines\DataTablesBundle\Exporter\DataTableExporterCollection;
use Omines\DataTablesBundle\Exporter\Excel\ExcelOpenSpoutExporter;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;

class ExcelOpenSpoutExporterTest extends KernelTestCase
{
/** @var DataTableExporterCollection */
private $exporterCollection;

protected function setUp(): void
{
$this->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());
}
}

0 comments on commit 879898d

Please sign in to comment.