symfony/twig-bridge
Symfony’s Twig Bridge integrates the Twig templating engine with Symfony components, providing extensions, loaders, form and translation support, and other glue code needed to use Twig seamlessly in Symfony-based applications.
Installation:
composer require symfony/twig-bridge
This package is typically auto-installed when using Symfony Flex or the Symfony Framework Bundle.
First Use Case: Render a Twig template in a Symfony controller:
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
class HomeController extends AbstractController
{
public function index(): Response
{
return $this->render('home/index.html.twig', [
'name' => 'John Doe',
]);
}
}
templates/home/index.html.twig.{{ path('app_home') }}).Where to Look First:
twig (auto-configured in Symfony).templates/forms/ directory for custom form templates.Templating in Controllers:
render() or renderView() to return Twig responses.return $this->render('template.html.twig', ['user' => $user]);
Form Handling:
{{ form_start(form) }}
{{ form_widget(form) }}
{{ form_end(form) }}
templates/forms/ (e.g., text_type.html.twig).Asset Management:
asset() function for static files:
<img src="{{ asset('images/logo.png') }}">
config/packages/twig.yaml:
twig:
assets_version: 'unique123'
Security Context:
{% if is_granted('ROLE_ADMIN') %}
Admin Panel
{% endif %}
access_decision() (Symfony 7.4+) for granular checks:
{% set decision = access_decision('edit', user) %}
Email Templates:
TemplatedEmail:
$email = (new TemplatedEmail())
->from(new Address('sender@example.com', 'Sender'))
->to($user->getEmail())
->subject('Welcome!')
->htmlTemplate('emails/welcome.html.twig')
->context(['name' => $user->getName()]);
Custom Twig Extensions:
Create a service tagged as twig.extension:
# config/services.yaml
services:
App\Twig\AppExtension:
tags: ['twig.extension']
// src/Twig/AppExtension.php
class AppExtension extends AbstractExtension
{
public function getFunctions(): array
{
return [
new Function('app_greet', [AppRuntime::class, 'greet']),
];
}
}
Debugging:
Enable Twig’s debug mode in config/packages/dev/twig.yaml:
twig:
debug: true
strict_variables: true
Caching: Configure runtime caching for production:
twig:
cache: '%kernel.cache_dir%/twig'
Caching Quirks:
{% block %} can leak prefixes. Use unique names:
{% block user_row_%index% %}
php bin/console cache:clear
Form Theming:
<label> tags for Bootstrap 4/5 compatibility:
{# templates/forms/bootstrap_4_layout.html.twig #}
{% block form_errors %}
<div class="invalid-feedback">{{ form_errors|join(', ') }}</div>
{% endblock %}
label: false in form options:
$builder->add('submit', SubmitType::class, ['label' => false]);
Security:
fileExcerpt(): Sanitize file paths passed to {{ fileExcerpt(path) }} (fixed in v8.1.0+).is_granted() sparingly in loops; prefer server-side checks for performance.Dependency Conflicts:
^6.0 (fixed in v8.0.5+).^3.25 (check composer.json constraints).templates/ directory is in the kernel.project_dir (default: var/cache/dev/).twig service is autowired or manually configured in services.yaml.strict_variables in dev to catch undefined variables early.Custom Globals: Add globals via a compiler pass or event subscriber:
services:
App\EventSubscriber\TwigGlobalSubscriber:
tags: ['kernel.event_subscriber']
class TwigGlobalSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents(): array
{
return [KernelEvents::REQUEST => 'onKernelRequest'];
}
public function onKernelRequest(RequestEvent $event): void
{
$twig = $event->getKernel()->getContainer()->get('twig');
$twig->addGlobal('app_config', $this->getAppConfig());
}
}
Override Twig Environment: Replace the default environment in a bundle:
// src/DependencyInjection/AppExtension.php
public function load(array $configs, ContainerBuilder $container): void
{
$container->set('twig', $this->createTwigEnvironment($container));
}
CLI Templates:
Use Twig for CLI output by injecting the twig service into commands:
class MyCommand extends Command
{
public function __construct(private TwigEngine $twig)
{
parent::__construct();
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$output->writeln($this->twig->render('cli/output.html.twig', []));
return Command::SUCCESS;
}
}
{% include %} and {% embed %} for modular templates.<link rel="stylesheet" href="{{ asset('css/style.css', 'unique123') }}">
trans filter for dynamic content:
{{ 'Welcome, %name%'|trans({'%name%': user.name }) }}
How can I help you explore Laravel packages today?