Twig Extensions
01 / 02

Twig Extensions: Symfony Integration & Best Practices

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