davidannebicque/html-to-spreadsheet-bundle
Install the Bundle
composer require davidannebicque/html-to-spreadsheet-bundle
Add to config/bundles.php (Symfony auto-discovers it, but explicit inclusion is recommended for clarity).
First Use Case: Basic HTML-to-XLSX
Create a Twig template (templates/export/simple_table.html.twig) with annotated HTML:
<table data-xls-file="report.xlsx">
<thead>
<tr>
<th data-xls-style="header">Name</th>
<th data-xls-style="header">Value</th>
</tr>
</thead>
<tbody>
<tr>
<td>Item 1</td>
<td data-xls-style="money">100.50</td>
</tr>
</tbody>
</table>
Render in Controller
use Dannebicque\HtmlToSpreadsheetBundle\Renderer\SpreadsheetRenderer;
class ExportController extends AbstractController
{
public function export(SpreadsheetRenderer $renderer): Response
{
return $renderer->renderToResponse('export/simple_table.html.twig');
}
}
Access /export to download report.xlsx.
data-xls-* attributes for styles, formulas, and metadata:
<td data-xls-style="percent2" data-xls-value="0.75">75%</td>
<td data-xls-formula="=SUM(A1:A10)">Total</td>
data-xls-*:
<th data-xls-style="{{ styleClass }}">Dynamic Header</th>
$renderer->renderToResponse('template.html.twig', 'report.ods'); // ODS
$renderer->renderToResponse('template.html.twig', 'report.csv'); // CSV
.xlsx.{# templates/_styles.html.twig #}
<style data-xls-style="success">
background-color: #d4edda;
font-weight: bold;
</style>
{% include '_styles.html.twig' %}
<table data-xls-file="report.xlsx">
<!-- ... -->
</table>
use Dannebicque\HtmlToSpreadsheetBundle\Controller\SpreadsheetTrait;
class ExportController extends AbstractController
{
use SpreadsheetTrait;
public function export(): Response
{
return $this->renderSpreadsheet('template.html.twig', 'report.xlsx');
}
}
SpreadsheetRenderer for custom logic:
public function customExport(SpreadsheetRenderer $renderer, User $user): Response
{
return $renderer->renderToResponse(
'user_report.html.twig',
'user_' ~ $user->id ~ '.xlsx',
['user' => $user]
);
}
<table data-xls-freeze-panes="A2">
<!-- ... -->
</table>
<th data-xls-width="30">Narrow Column</th>
<td data-xls-image="path/to/logo.png" data-xls-image-width="100"></td>
// config/services.yaml
Dannebicque\HtmlToSpreadsheetBundle\Event\SpreadsheetEvents::POST_RENDER:
tag: kernel.event_listener
class: App\EventListener\SpreadsheetListener
// src/EventListener/SpreadsheetListener.php
public function onPostRender(PostRenderEvent $event): void
{
$spreadsheet = $event->getSpreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$sheet->setSelectedCell('A1'); // Auto-select cell after render
}
Attribute Conflicts:
data-* attributes used by other libraries (e.g., data-xls-* vs. data-toggle).data-app-xls-*) or wrap tables in a container:
<div data-xls-namespace="app">
<table data-xls-file="report.xlsx">
<!-- Attributes become data-app-xls-* -->
</table>
</div>
Style Inheritance:
<style> tags apply globally. Override them with inline data-xls-style:
<style data-xls-style="default">...</style>
<td data-xls-style="override">Overrides default</td>
CSV Quirks:
<td data-xls-csv-delimiter="|">Value, with, commas</td>
Performance with Large Data:
setReadDataOnly(true).$spreadsheet = $renderer->render('template.html.twig');
$sheet = $spreadsheet->getActiveSheet();
// Manually add more rows via PhpSpreadsheet API
French Presets:
float2 for 1 000,50 instead of 1,000.50).$renderer->addStyle('custom_float', ['numberFormat' => '#,##0.00']);
Inspect Rendered HTML:
data-xls-* attributes before rendering. Use Twig’s dump():
{{ dump(table|slice(0, 1)) }} {# Inspect first row #}
PhpSpreadsheet Errors:
// config/packages/dannebicque_html_to_spreadsheet.yaml
dannebicque_html_to_spreadsheet:
php_spreadsheet:
log_level: 200 {# Log DEBUG messages #}
File Download Issues:
StreamedResponse for large files:
use Symfony\Component\HttpFoundation\StreamedResponse;
public function largeExport(): StreamedResponse
{
return new StreamedResponse(
function () use ($renderer) {
$response = $renderer->renderToResponse('large_table.html.twig', 'large.xlsx');
$response->send();
},
200,
['Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']
);
}
Custom Styles:
$renderer->addStyle('custom_bold', ['font' => ['bold' => true]]);
<td data-xls-style="custom_bold">Bold Text</td>
Pre/Post-Processing:
SpreadsheetRenderer class to modify the spreadsheet object:
class CustomRenderer extends SpreadsheetRenderer
{
protected function postProcess(Spreadsheet $spreadsheet): void
{
$sheet = $spreadsheet->getActiveSheet();
$sheet->getStyle('A1')->getFont()->setSize(14);
}
}
Register as a service:
# config/services.yaml
How can I help you explore Laravel packages today?