zeliard91/twigstring-bundle
Symfony bundle for rendering Twig templates from strings at runtime. It provides a TwigString service and Twig extension, making it easy to evaluate dynamic or database-stored template snippets with Twig syntax inside your Symfony application.
This is a Symfony2 bundle, not a Laravel package. Before anything else: it does not install or run under Laravel. As a Laravel developer your first move is to confirm that and pivot, but it's still worth understanding because the underlying technique — rendering a Twig template that lives in a string rather than a file — maps 1:1 to something you'll do in Laravel every week.
If you're in the Symfony2 context the bundle targets (the only place it actually runs):
composer require zeliard91/twigstring-bundle (pin to the 2016-era constraints; expect conflicts on modern Symfony).AppKernel::registerBundles():
new Zeliard91\TwigstringBundle\TwigstringBundle(),
Resources/config/services.xml — the whole package is a thin wrapper around Twig\Environment::createTemplate(). There is no config tree to speak of; that's the entire surface area.$twig->render('emails/welcome.html.twig', $data) you render from a string pulled out of a DB column.The Laravel equivalent you actually want:
// Laravel 8+
$html = Blade::render('Hello {{ $name }}', ['name' => 'World']);
Or, if you insist on Twig semantics inside Laravel, pull twig/twig in directly and skip this bundle entirely:
$twig = new \Twig\Environment(new \Twig\Loader\ArrayLoader([]));
$twig->createTemplate('Hello {{ name }}')->render(['name' => 'World']);
That is essentially all TwigstringBundle is doing — createTemplate() on a string. Start there.
1. The DB-template pattern (the bundle's whole reason to exist).
In Symfony2 the call shape is a service fetch:
$html = $this->get('twigstring')->render(
$templateEntity->getBody(),
['order' => $order, 'customer' => $order->getCustomer()]
);
The equivalent in Laravel, which is where you'll spend your time:
$html = Blade::render($template->body, ['order' => $order]);
If you need Twig syntax specifically (e.g. importing templates authored by a Symfony team), wrap twig/twig directly as shown above and inject it as a singleton in a service provider.
2. Nested / partial rendering.
Both Twig and Blade let a string template include other templates. In Twig this is {% include %} resolved against the loader — which is why the string-template wrapper usually reuses the environment's existing loader/namespace so partials still resolve. In Blade, @include('partials.foo') works inside Blade::render() the same way. Design your DB templates to reference named partials, not to inline everything, or you'll be copy-pasting markup across rows.
3. Expose it as a filter/function for editors.
A common integration is letting content editors type {{ user.name }} in a CMS field and rendering it at request time:
// Blade
Blade::render($cmsField->value, ['user' => $user]);
Cache the compiled output per (template hash + data hash) if this is on a hot path — string templates are compiled on every call (see gotchas).
4. Migration tip from Symfony2 → Laravel.
| Symfony2 / this bundle | Laravel equivalent |
|---|---|
$this->get('twigstring')->render($str, $data) |
Blade::render($str, $data) |
Twig {% for %} / {{ }} |
@foreach / {{ }} (or keep Twig via twig/twig) |
| Twig filters (` | upper`) |
| Global Twig extensions | Custom Blade directives / Twig extensions |
Pick one syntax family and stay there. Mixing Blade @if with Twig {% if %} in the same DB corpus is a guaranteed debugging session.
Blade::render() (Laravel 8+) or raw twig/twig.createTemplate() in the vendor copy and port the five lines yourself if you want the behavior.createTemplate() bypasses the template cache by default. Every render compiles the string fresh unless you cache the resulting TemplateWrapper or the output yourself. For DB templates rendered on every request, add an application-level cache keyed on a hash of the template body.SandboxExtension; Blade has no equivalent sandbox — so if the string is user-controlled in Laravel, you're exposing @php, @include, {{ }} with arbitrary objects, and more. Restrict to trusted/admin-authored templates, or parse with a whitelisted placeholder syntax instead of a full engine.{% extends %} or {% include %} need the environment's loader to resolve those names. If the wrapper builds a private environment, your normal app/Resources/views paths won't be visible — this is the usual "works standalone, breaks with extends" failure.symfony/symfony: ~2.x constraints conflict with almost anything modern. You'll need --ignore-platform-reqs hacks at best; don't do this in a maintained app.{{ }} escapes and {!! !!}/{% autoescape false %} doesn't — same XSS footgun applies to string templates as to file templates. Sanitize before rendering if the data is untrusted.Blade::directive() to add custom syntax, Blade::stringable() / Blade::if() for conditions, and a service provider to bind a configured Twig environment if you go the Twig route. That's where the equivalent "bundle" logic belongs.render(); exceptions from string templates frequently report a synthetic name (__string_template__...) that gives you no file/line pointer. In Blade, Blade::render() on a malformed string throws with the compiled PHP — inspect that to find the offending directive.How can I help you explore Laravel packages today?