Twig Extensions: Symfony Integration & Best Practices
Symfony Auto-Registration & Dependency Injection
// Symfony auto-registers any class implementing
// Twig\Extension\ExtensionInterface as a service, autowiring
// constructor dependencies -- no manual registration boilerplate
class CurrencyExtension extends AbstractExtension
{
public function __construct(
private CurrencyFormatter $formatter,
) {}
public function getFilters(): array
{
return [new TwigFilter('price', [$this->formatter, 'format'])];
}
}is_safe: Trusted HTML Output
new TwigFilter('markdown', [$this, 'renderMarkdown'], [
'is_safe' => ['html'], // output already trusted HTML -- Twig
// won't auto-escape it, sparing template
// authors from needing |markdown|raw
]);needs_context & needs_environment
// needs_context passes the full current template variable context
// as the first argument -- for logic needing more than just its
// explicit arguments
new TwigFunction('current_locale', [$this, 'getCurrentLocale'], [
'needs_context' => true,
]);Keep Extensions Presentation-Focused
A discount filter should delegate to a proper DiscountCalculator service rather than reimplementing business rules directly in the extension -- keeping that calculation logic testable and reusable outside the templating context too. The same reasoning that keeps business logic out of templates applies to extension implementations.
Organizing & Testing
Split unrelated functionality into focused extension classes (CurrencyExtension, DateExtension) rather than one sprawling monolith.
Give filters/functions descriptive names (format_currency, not format) to avoid naming collisions across multiple extensions.
Test the underlying PHP implementation directly with normal unit tests -- no need to render an actual template just to verify formatting logic.
Custom tags (via TokenParser) introduce entirely new {% %} syntax and are meaningfully more complex than filters/functions -- most needs are met without reaching for them.
Keep your own version of these notes — editable, searchable, and organised by your stack.
Start free