symfonytwig

How do I add a twig global from a bundle config?


I'd like my bundle to inject a twig global from its config.

class MyBundle extends AbstractBundle
{
    public function build(ContainerBuilder $container): void
    {
        parent::build($container);
        $container->addCompilerPass(new TwigPass());
    }
    public function loadExtension(array $config, ContainerConfigurator $container, ContainerBuilder $builder): void
    { 
        $theme = $config['theme']; // how to make this a twig global?
        // $twig = $builder->getDefinition('twig'); // NOPE! Twig isn't loaded yet.
    }

The compiler pass gets twig, which isn't available when my bundle extension is loading.

class TwigPass implements CompilerPassInterface
{
    public function process(ContainerBuilder $container)
    {
        if (false === $container->hasDefinition('twig')) {
            return;
        }
        
        $theme = 'theme_from_config';
        $def = $container->getDefinition('twig');
        $def->addMethodCall('addGlobal', ['theme', $theme]);

I'm missing something, or something is out of order. How can the compiler pass get the config data from the extension? Or if that's not the right approach, how can I inject a twig global from my bundle config?


Solution

  • The way to make config data available to a pass is to add the data to the container as a parameter:

    class TwigPass implements CompilerPassInterface
    {
        public function process(ContainerBuilder $container)
        {
            if (false === $container->hasDefinition('twig')) {
                return;
            }
            $theme = $container->getParameter('my.theme');
    
            $def = $container->getDefinition('twig');
            $def->addMethodCall('addGlobal', ['theme', $theme]);
        }
    }
    class CeradMyBundle extends AbstractBundle
    
        public function loadExtension(array $config, ContainerConfigurator $container, ContainerBuilder $builder): void
        {
            $container->parameters()->set('my.theme', $config['theme']);
        }
    

    To actually get your theme config value into the $config array requires making a Configure class. Fortunately AbstractBundle can simplify this with a configure method:

    # config/packages/cerad_my.yaml
    cerad_my:
      theme: theme_from_config_file
    
    class CeradMyBundle extends AbstractBundle
    
      public function configure(DefinitionConfigurator $definition): void
      {
          $definition->rootNode()
              ->children()
                  ->scalarNode('theme')->defaultValue('theme_default')->end()
              ->end()
          ;
      }
    

    After getting this to work, it was a tiny bit annoying to have that one extra DI class i.e. TwigPass so I stole a trick from the Kernel and just had the AbstractBundle implement the pass interface:

    class CeradMyBundle extends AbstractBundle implements CompilerPassInterface
    {
      public function build(ContainerBuilder $container): void
      {
          // Register as a pass
          $container->addCompilerPass($this);
      }
      public function loadExtension(array $config, ContainerConfigurator $container, ContainerBuilder $builder): void
      {
        $container->parameters()
          ->set('my.theme', $config['theme']);
      }
      public function configure(DefinitionConfigurator $definition): void
      {
          $definition->rootNode()
              ->children()
                  ->scalarNode('theme')->defaultValue('theme_default')->end()
              ->end()
          ;
      }
      // The compiler pass
      public function process(ContainerBuilder $container)
      {
          if (false === $container->hasDefinition('twig')) {
              return;
          }
          $theme = $container->getParameter('my.theme');
          $def = $container->getDefinition('twig');
          $def->addMethodCall('addGlobal', ['theme', $theme]);
      }
    }
    

    If you follow this approach then you can actually save your theme as a property in your bundle class and avoid the need to add a public parameter. Your choice.