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.
Architecture fit: This is a Symfony bundle, not a Laravel package — the first thing to flag in any evaluation, because the brief frames the target as a Laravel/PHP stack. The bundle sits at the intersection of three concerns: Symfony's DI/configuration layer, Twig as the templating/render engine, and PhpSpreadsheet as the workbook writer. Its value proposition is essentially "define an .xlsx layout declaratively in a Twig template and render it through a service." That is a narrow, opinionated integration. In a Laravel application the two load-bearing pieces — the Symfony bundle bootstrapping and the Twig environment — are absent or non-idiomatic (Laravel uses Blade and its own service container). What remains useful is the pattern and a small amount of Twig-to-PhpSpreadsheet mapping code, not the package itself.
Integration feasibility: Consuming it directly as a Composer dependency in Laravel is possible but not advisable. You would pull in Symfony bundle machinery and Twig (twig/twig) alongside Blade, register the bundle manually outside Symfony's kernel, and then either (a) render spreadsheets by spinning up a standalone Twig environment just for this template path, or (b) port the Twig functions/extensions to Blade directives. Option (a) is the lower-effort path — Twig can be instantiated standalone — but it means maintaining two templating engines and two template dialects in one codebase, a persistent cognitive and onboarding tax. Option (b) is a fork-by-another-name: you are copying a few hundred lines of extension code into your app and owning it thereafter. Estimate: a few days of engineering to get a working spike, plus ongoing ownership. The fork path is the realistic one.
Technical risk: High, concentrated in abandonment and ecosystem drift. Signals: 1 star, 0 dependents, last release April 2019. The underlying dependency, PhpSpreadsheet, has moved substantially since 2019 (PHP version floors, deprecations, API changes around readers/writers, cell handling, and PHP 8.x type behavior). A bundle pinned to a 2019-era PhpSpreadsheet range is likely to either block your PhpSpreadsheet upgrades or require you to widen constraints and hope the internal calls still work. Compounding this: zero dependents means effectively no field-testing outside the author's own use, so edge cases in number formatting, formulas, merged cells, and date handling are unvalidated. Twig itself has had major-version churn (v2 → v3), so the extension API surface the bundle targets may already be stale. Security exposure is low in absolute terms (it writes files, it doesn't accept untrusted templates — but see the template-authoring question below), but "low-severity, unpatched, unmaintained" is still a category you have to inventory.
Key questions:
Stack fit: Poor as a drop-in, moderate as a pattern donor. The clean framing for stakeholders: this package is not a dependency we adopt, it is a reference implementation we study. Its durable idea — separating spreadsheet layout from spreadsheet data population via a template — is genuinely valuable and worth preserving. Its implementation is Symfony-and-Twig-shaped, which does not match our stack. Recommend a "pattern extraction" decision rather than an "adoption" decision, and be explicit about that in the decision record so no one later assumes we have a supported vendor dependency.
Migration path: There is no migration path in the conventional sense (no prior system to move off, no upgrade treadmill to join). The realistic path is a bounded internal build:
If leadership insists on reuse, the fallback is to vendor the bundle under a packages/ path with a documented fork, pin the PhpSpreadsheet constraint to whatever we can actually test, and accept ownership of the code from day one. Budget for that ownership.
Compatibility: Three independent compatibility axes, all strained: PHP version (2019 code against 8.x — expect deprecation noise at minimum, hard failures plausibly), PhpSpreadsheet version (the API has drifted meaningfully; the bundle's internal calls are untested against current releases), and Twig major version (extension registration changed across v2/v3). In a Laravel app there is a fourth: coexistence of Twig and Blade, which is technically fine but organizationally corrosive. Confirm each axis with the spike before writing any plan that depends on the package.
Sequencing: Discovery and spike first (cheap, kills the question fast). Then a build-vs-fork decision gate with engineering and the export-owning team. Only then implementation. Do not sequence this behind a customer-facing deadline — the risk is that schedule pressure forces the direct-dependency path and you inherit an unmaintained bundle in a revenue-critical export flow. If an export feature is already on the roadmap with a near-term date, decouple: ship the near-term feature on a maintained library, and treat the Twig-template pattern as a later refinement.
Maintenance: This is the dominant cost and the reason to decline adoption. An unmaintained 2019 bundle with one star and zero dependents has no upstream to absorb change. Every PHP upgrade, PhpSpreadsheet upgrade, or Twig upgrade becomes an internal patch. Because the code is small, patches are individually cheap, but the obligation is permanent and unattributed until someone is named. If we fork, assign a named owner and put it on the same dependency-review cadence as our other vendored code, with an explicit "delete or replace" review date. If we do not fork, there is no maintenance burden — because there is no dependency.
Support: Zero. No vendor, no community, no issue triage to rely on. Internal engineers become the only support channel, and their knowledge is undocumented unless we write it. For a low-stakes internal reporting tool this may be tolerable; for anything a customer or auditor depends on, it is not.
Scaling: Two dimensions. Throughput: PhpSpreadsheet is memory-hungry — it builds the workbook in memory, so large exports are the classic failure point. The bundle does nothing to address this; the Twig-render pattern in particular encourages loading the full dataset before rendering. For anything beyond modest row counts, plan on queued generation, chunked or streaming writers, and object storage rather than synchronous downloads. Concurrency: template rendering plus workbook construction is CPU- and memory-bound; size the queue workers and set explicit limits, or one large export will starve the pool. Neither concern is specific to this package, but adopting it does not buy you any of the mitigations you would get from a maintained exporter.
Failure modes: Enumerate them now so they are not surprises: (1) silent output corruption — number formats, dates, and formulas rendering differently than intended with no exception thrown, which is the worst failure class in a reporting pipeline because it erodes trust in the data itself; (2) memory exhaustion on large exports, surfacing as 500s or worker kills; (3) hard breakage on a routine PHP or dependency upgrade, discovered at deploy time; (4) template-injection or resource-exhaustion if templates are ever authored by non-engineers; (5) orphaned code — the original author moves on, nobody understands the Twig mapping, and the export becomes a black box. Mitigations: golden-file tests that diff generated workbooks against known-good fixtures, hard row-count thresholds with a streaming path above them, and pinning with a scheduled review.
Ramp-up: Deceptively steep relative to code size. A new engineer must learn Twig and the bundle's particular conventions and PhpSpreadsheet's styling and writer APIs — three layers for what looks like a simple export. In a Blade shop the Twig layer is pure overhead and will be resisted. If we build our own thin layout layer, ramp-up collapses to PhpSpreadsheet plus our own documented conventions, which is a materially better onboarding story.
Recommendation: Do not adopt as a production dependency. Run the two-day spike to validate the template-driven layout pattern, then build a small internal equivalent on maintained libraries with Blade-native or plain-PHP ergonomics. Credit the package's design in the decision record — the pattern is the asset here, and the repository is a one-star artifact of it, not a component we can lean on.
How can I help you explore Laravel packages today?