hostnet/financial-twig-extension-bundle
Hostnet Financial Twig Extension Bundle adds Twig filters and functions for financial calculations and formatting, helping Symfony templates handle values like VAT, interest, and currency display without extra PHP logic. Simple to install and integrate.
Architecture fit: framework-seam mismatch, portable core. The package is a Symfony Bundle — it ships a Bundle subclass, a DI Extension, services.yaml resource loading, and Twig extensions registered via the twig.extension tag. Laravel has no bundle lifecycle, no DI compiler passes, and no service tagging; the container will autowire plain classes but will silently ignore the bundle's wiring. The genuinely reusable asset is the Twig extension layer itself: Twig\Extension\AbstractExtension implementations with filters/functions are framework-agnostic and will run anywhere Twig runs. That is the part worth evaluating; the Symfony scaffolding is disposable. There is a second seam beyond Symfony→Laravel: Laravel ships Blade, not Twig, so the filters have no natural consumer unless we introduce Twig.
Integration feasibility: possible, but effort-to-payoff is poor on the default stack. Three viable routes, in descending order of pragmatism: (a) port the filter bodies into a Laravel FinancialFormatter service plus Blade directives (@money, @percent) — likely 150–300 LOC, no new runtime dependency; (b) introduce rcrowe/twigbridge in a bounded rendering context (PDF statements, financial email templates) and register each extension manually in a service provider's boot(); (c) fork, strip the Bundle namespace, republish internally as a Laravel package. Pulling symfony/dependency-injection + framework-bundle into a Laravel app to obtain a handful of formatting filters is a weight and upgrade-coupling cost I would not sign off on.
Technical risk: maturity and supply chain, not code complexity.
-1,234.00 vs. (1,234.00)), and grouping separators are audit-visible. We cannot inherit correctness here; we must characterize it.Key questions to resolve in a one-day spike:
moneyphp/money, brick/money, or just number_format/NumberFormatter? A dependency on a money value object changes the port significantly.ext-intl / ICU a hard requirement?Number::currency() and whatever money library we already run?Stack fit: conditional. If the application is Blade-first, only the formatting logic transfers and the Symfony packaging is pure overhead. If we already render Twig somewhere — most commonly PDF invoices (dompdf/snappy) or transactional financial email — the extensions drop in with a manual registration loop and the bundle is genuinely useful. Determine this first; it bifurcates the whole plan.
Migration path.
App\Support\Formatting\FinancialFormatter, expose via Blade directives and a facade. Cost: ~200 LOC plus tests. Removes the dependency entirely; no TwigBridge, no Symfony DI, no upstream risk. Downside: we own divergence from upstream forever, which for a frozen formatting ruleset is acceptable.rcrowe/twigbridge scoped to one rendering context, then in a service provider boot(): resolve the Twig environment and call addExtension() for each extension class. This replicates Symfony's tag semantics by hand. Cost: 5–8 engineering days including TwigBridge bake-in and CI, plus ongoing TwigBridge/Laravel major-version skew risk.DependencyInjection/, keep the extension classes, publish under our vendor namespace. Reasonable if we expect to add filters (e.g., FX conversion, compact notation) and want upstream's structure as a starting point.Compatibility. Verify Twig 3.x compatibility (Twig 1/2 APIs are removed in modern Laravel-adjacent stacks), PHP constraint overlap with our runtime, and — for Lane B — that TwigBridge supports our current Laravel major before committing. TwigBridge historically lags Laravel releases by a quarter or more; that lag becomes our upgrade blocker.
Sequencing.
Maintenance. We own this regardless of lane. Lane B leaves us coupled to two upstream cadences (Hostnet's Symfony releases and TwigBridge's Laravel support) for a small amount of logic — a poor maintenance ratio. Lane A/C reduces upstream surface to zero at the cost of owning ~200 lines we can fully test. Given 0 dependents and 1 star, assume no one else will file the bug we hit.
Support. No commercial support; GitHub issues only, with a low-activity repo suggesting slow response. Name an internal DRI. Keep the fork-ready diff current — it is small enough that re-vendoring on an upstream CVE or ICU behavior change is a hours-scale task, not a project.
Scaling. Runtime cost is negligible: formatting is CPU-bound, no I/O, sub-microsecond per call. Two real considerations: (i) do not instantiate NumberFormatter per cell — memoize a formatter service per locale, or a 10k-row financial table becomes a 10k-allocation render; (ii) if rendering is server-side in request path, keep formatter construction out of the loop and out of the container resolve path.
Failure modes.
ext-intl / incomplete ICU data in a container image → exception or wrong separators at render time, not boot time. Pin the extension in composer.json and assert it in a health check.Unknown "money" filter on first render of a production page. This is the highest-probability failure and it is a runtime, not startup, failure; add a boot-time smoke assertion that each filter name resolves.($1,234.00); a formatter emitting -$1,234.00 is a visible, audit-relevant defect. Lock with golden tests.Ramp-up. Low. An engineer can read the entire filter implementation in under an hour. Budget 1 day for the source-inventory spike, 2–4 days for Lane A implementation plus characterization tests, 5–8 days for Lane B including TwigBridge adoption and CI. Team learning cost is near zero for Lane A (Blade directives are familiar); moderate for Lane B, where engineers must understand Twig extension registration and Symfony service-tag semantics transposed into a Laravel provider.
Verdict. Adopt the logic, not the bundle. The package is small, MIT-licensed, and recently released, but its 1-star / 0-dependent profile means the adoption signal we would normally rely on does not exist, and its Symfony packaging is dead weight in a Laravel application. Port the filters behind a tested internal formatter service unless Twig already exists in the stack, in which case bridge it in one bounded rendering context only.
How can I help you explore Laravel packages today?