mywheels/twig-spreadsheet-bundle
Twig Spreadsheet Bundle brings Twig templating to spreadsheet generation, letting you define workbook layouts in familiar templates and export structured data to spreadsheet files from your PHP or Symfony application.
This is a Symfony bundle, not a Laravel package, and it is effectively abandoned (last release April 2019, one star, zero dependents). Treat it as a reference implementation rather than a dependency you install.
If you want to inspect it, clone the repo and look first at:
TwigSpreadsheetExtension.php — registers the Twig tags/DSL ({% spreadsheet %}, {% sheet %}, {% row %}, {% cell %}, style tags).SpreadsheetFactory.php — the service that collects spreadsheet state and produces a PhpOffice\PhpSpreadsheet\Spreadsheet.DependencyInjection/ and Resources/config/services.yml — Symfony wiring you would have to reproduce in a Laravel service provider.Minimal install in a Symfony app (for context):
composer require mywheels/twig-spreadsheet-bundle phpoffice/phpspreadsheet
Register MyWheels\TwigSpreadsheetBundle\TwigSpreadsheetBundle::class in config/bundles.php.
In Laravel, the first practical use case is not this bundle — it's the concept: define export templates (reports, invoices, data dumps) that non-developers can edit without touching PHP. The direct Laravel equivalents are:
maatwebsite/excel (Laravel Excel) — the idiomatic wrapper around PhpSpreadsheet.phpoffice/phpspreadsheet directly for one-off exports.If you specifically want the "template-defined spreadsheet" idea, plan to port the DSL, not install the bundle.
The bundle's pattern is a Twig DSL that mutates a shared Spreadsheet object as the template renders:
{% spreadsheet spreadsheet %}
{% sheet 'Report' %}
{% row %}
{% cell %}Name{% endcell %}
{% cell %}Amount{% endcell %}
{% endrow %}
{% for line in lines %}
{% row %}
{% cell %}{{ line.name }}{% endcell %}
{% cell %}{{ line.amount }}{% endcell %}
{% endrow %}
{% endfor %}
{% endsheet %}
{% endspreadsheet %}
In Symfony you'd typically inject SpreadsheetFactory, render the template, then call $factory->getSpreadsheet() and stream or save it. The Twig context can pass data in via $this->render('...', $data).
To reproduce the pattern in Laravel, wire Twig manually in a service provider:
$this->app->singleton(\Twig\Environment::class, function ($app) {
$loader = new \Twig\Loader\FilesystemLoader(resource_path('spreadsheets'));
$twig = new \Twig\Environment($loader, ['autoescape' => false]);
// $twig->addExtension(new SpreadsheetExtension($app->make(SpreadsheetFactory::class)));
return $twig;
});
Then wrap rendering in a job/service:
class SpreadsheetExporter
{
public function __construct(private \Twig\Environment $twig) {}
public function render(string $template, array $data): Spreadsheet
{
$spreadsheet = new Spreadsheet();
$this->twig->render($template, $data + ['spreadsheet' => $spreadsheet]);
return $spreadsheet;
}
}
Better integration tips:
resources/spreadsheets/) — don't mix with Blade views.@spreadsheetCell / @row directive can compile to the same builder calls with zero new template engine.framework-bundle and twig-bundle, and its composer.json pins early PhpSpreadsheet version ranges. Composer will refuse to resolve against Laravel 9/10/11 + current PhpSpreadsheet (2.x/3.x). Expect conflicts on psr/container, symfony/*, and phpoffice/phpspreadsheet.Style object and log unknown keys.=SUM(...)) via the DSL requires getCalculatedValue() after render — a slow path on large sheets. Cache results or compute in PHP in the service layer instead.Spreadsheet yourself from a service that reads the template.maatwebsite/excel for exports, and if you want the template-driven experience, implement it as a custom Blade directive or a small Twig\Environment just for spreadsheet templates — either way, you keep the ergonomic DSL and drop the abandoned Symfony bundle entirely.How can I help you explore Laravel packages today?