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?
CodePudding user response:
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.