omines / datatables-bundle

DataTables bundle for Symfony
https://omines.github.io/datatables-bundle/
MIT License
258 stars 115 forks source link

Add server side export #83

Closed MaximePinot closed 4 years ago

MaximePinot commented 5 years ago

This Bundle only allows server side processing. This raises an issue when it comes to use the HTML5 export buttons. These buttons only export the current page (as the DOM is only aware of the current page).

This pull request aims to fix this limitation.

Usage

I suggest you look at the ExporterController and the exporter.html.twig file for a complete usage example.

How it works

Front-end

https://github.com/MaximePinot/datatables-bundle/blob/10e586c98cb3c4f2f167828a932ef9180551e33d/tests/Fixtures/AppBundle/Resources/views/exporter.html.twig#L11-L26

Adding an export button must be handled by the front-end developer as it is not the Bundle's concern to manage/render anything. As the Bundle still needs some specific parameters to be sent, I created a function that generates the function needed by the action option.

Back-end

Everything is handled automatically by the Bundle and its current structure (isCallback / getResponse) is not changed (see this piece of code).

To trigger an "export state", the request must be sent with a _exporter parameter (along with the usual _dt parameter) whose value is the name of the DataTable exporter (defined by the getName() method).

At the moment, I only created an Excel exporter. I think the Bundle should be shipped with a few common exporters such as PDF, CSV and HTML. I plan to add these three, but I want to be sure that my implementation is correct before.

Anyone can add a DataTable exporter to its project by creating a service class that implements the Omines\DataTablesBundle\Exporter\DataTableExporterInterface. The service must be tagged with datatables.exporter.

Documentation

I did not write any documentation yet. I first want to be sure that my implementation is correct. When this pull request is ready to be merged. I will add a commit that adds a Server side export section to the documentation.

curry684 commented 5 years ago

@shades684 changes make sense afaics, your opinion?

MaximePinot commented 5 years ago

Hi @curry684, thank you for reviewing my pull request.

I think some things should be improved. For example, it would be better to automatically tag classes that implement Omines\DataTablesBundle\Exporter\DataTableExporterInterface.

I need to add more tests. I'm using my fork in production and a "Cannot traverse an already closed generator" error is raised when one tries to export an empty DataTable. Apart from that, it's working fine.

However, exported data can be confusing depending of the render callback. Is there a way I can get the raw value from the database before the render callback is called?

curry684 commented 5 years ago

AbstractColumn::transform converts the raw value pre-rendering.

https://github.com/omines/datatables-bundle/blob/94777da/src/Column/AbstractColumn.php#L68-L77

MaximePinot commented 4 years ago

Hi @curry684 ,

I've been using my server-side-export branch for more than 6 months now on a big project. Everything is working as expected.

Could you also test it on one of your project?

As soon as you tell me everything is fine and my implementation is correct, I will add :

Then, I believe this PR will be ready to be merged!

MaximePinot commented 4 years ago

Wow, maybe I should have git merge instead of git rebase :sweat_smile: Sorry for all the duplicates... But at least, tests are passing!

curry684 commented 4 years ago

I have no good way to test at the moment and the PR is unreviewable due to the rebase, so I'll just merge it and we'll see how the community likes it :P

MaximePinot commented 4 years ago

Thanks @curry684! I'm watching this repository so I'll be responsive if someone opens an issue about this feature. :wink:

curry684 commented 4 years ago

It would seem something in Symfony 5 broke it:

https://travis-ci.org/github/omines/datatables-bundle/jobs/703172222

There were 5 errors:
1) Tests\Functional\Exporter\Csv\CsvExporterTest::testExport
Error: Call to undefined method Symfony\Component\HttpFoundation\Response::getFile()
/home/travis/build/omines/datatables-bundle/tests/Functional/Exporter/Csv/CsvExporterTest.php:34
2) Tests\Functional\Exporter\Event\DataTableExporterResponseEventTest::testPreResponseEvent with data set #0 ('excel', 'xlsx')
TypeError: Argument 1 passed to PHPUnit\Framework\Assert::assertStringContainsString() must be of the type string, null given, called in /home/travis/build/omines/datatables-bundle/tests/Functional/Exporter/Event/DataTableExporterResponseEventTest.php on line 43
/home/travis/build/omines/datatables-bundle/tests/Functional/Exporter/Event/DataTableExporterResponseEventTest.php:43
3) Tests\Functional\Exporter\Event\DataTableExporterResponseEventTest::testPreResponseEvent with data set #1 ('txt', 'txt')
TypeError: Argument 1 passed to PHPUnit\Framework\Assert::assertStringContainsString() must be of the type string, null given, called in /home/travis/build/omines/datatables-bundle/tests/Functional/Exporter/Event/DataTableExporterResponseEventTest.php on line 43
/home/travis/build/omines/datatables-bundle/tests/Functional/Exporter/Event/DataTableExporterResponseEventTest.php:43
4) Tests\Functional\Exporter\Excel\ExcelExporterTest::testExport
Error: Call to undefined method Symfony\Component\HttpFoundation\Response::getFile()
/home/travis/build/omines/datatables-bundle/tests/Functional/Exporter/Excel/ExcelExporterTest.php:45
5) Tests\Functional\Exporter\Excel\ExcelExporterTest::testWithSearch
Error: Call to undefined method Symfony\Component\HttpFoundation\Response::getFile()
/home/travis/build/omines/datatables-bundle/tests/Functional/Exporter/Excel/ExcelExporterTest.php:103

Also a fatal:

1) Tests\Functional\Exporter\Excel\ExcelExporterTest::testEmptyDataTable
Failed asserting that false is true.
/home/travis/build/omines/datatables-bundle/tests/Functional/Exporter/Excel/ExcelExporterTest.php:77

Not really sure what's behind this. Could you have a look?

I'm holding off 0.5.0 until this is fixed (currently at rc1).