我有一个包的语义配置,需要在同一包的编译器传递期间进行解释。
是否可以在不将其存储在中间容器变量中的情况下访问它?
我有一个包的语义配置,需要在同一包的编译器传递期间进行解释。
是否可以在不将其存储在中间容器变量中的情况下访问它?
是的,有点:
<?php
namespace Acme\DemoBundle\DependencyInjection;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
class CompilerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
$configs = $container->getExtensionConfig('acme_demo');
}
}
从我可以看到$configs
的是一组未合并的配置,并且不包括默认值(由配置 TreeBuilder 定义的值)。
只是为了@Peter 的回答的完整性:getExtensionConfig
返回一个数组数组,应该使用对应的数组进行处理,Configuration
以便能够访问默认值。
<?php
namespace Acme\DemoBundle\DependencyInjection;
use Symfony\Component\Config\Definition\ConfigurationInterface;
use Symfony\Component\Config\Definition\Processor;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
class CompilerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
$configs = $container->getExtensionConfig('acme_demo');
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);
/// You can safely work with $config now
}
private function processConfiguration(ConfigurationInterface $configuration, array $configs)
{
$processor = new Processor();
return $processor->processConfiguration($configuration, $configs);
}
}
我意识到这是一篇旧帖子,但我一直在寻找相同的信息,最终发现这适用于单个参数:
$cfgVal = $container
->getParameterBag()
->resolveValue( $container->getParameter( 'param_name' ));
当然,这个功能可能是在原始帖子之后添加的。
我一直在寻找如何读取已处理的配置,而无需设置自定义参数以稍后在 CompilerPass 中检索,并遇到了以下解决方案。
查看内核中的操作顺序Kernel::prepareContainer
,我们可以看到它调用Bundle::getContainerExtension()
后跟Bundle::build()
这意味着Extension::load
在运行编译器之前调用了方法并处理了配置。
由于 Symfony 还在容器中注册了扩展,因此您只需从CompilerPass
.
然而,由于 Symfony 也会清空processedConfigs
数组,因此在加载扩展后,您需要使CompilerPass
.
namespace AppBundle;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;
use AppBundle\DependencyInjection\Compiler\AppCompilerPass;
class AppBundle extends Bundle
{
public function build()
{
$container->addCompilerPass(new AppCompilerPass());
}
/** demonstration of the default functionality in Bundle
public function getContainerExtension()
{
if (null === $this->extension) {
$this->extension = new AppBundle\DependencyInjection\AppExtension();
}
return $this->extension;
} */
}
namespace AppBundle\DependencyInjection;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\Extension;
class AppExtension extends Extension
{
const ALIAS = 'app'; //just for demonstration and reference in CompilerPass
private $config = array();
public function load(array $configs, ContainerBuilder $container): void
{
//make the processed configuration available
$this->config = $this->processConfiguration(new Configuration(), $configs);
//...
}
public function getConfig()
{
try {
return $this->config;
} finally {
//erases the config after it is retrieved, for security and performance reasons
$this->config = array();
}
}
/** demonstration of default functionality in Extension
public function getAlias()
{
return self::ALIAS;
} */
}
namespace AppBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use AppBundle\DependencyInjection\AppExtension;
class AppCompilerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
//...
if (!$container->hasExtension(AppExtension::ALIAS)) {
//always make sure the extension exists
return;
}
$config = $container->getExtension(AppExtension::ALIAS)->getConfig();
dump($config);
//...
}
}
您可以将扩展名传递给编译器传递,而不是从容器中检索扩展名。
class AppBundle extends Bundle
{
public function build()
{
$container->addCompilerPass(new AppCompilerPass($this->getContainerExtension()));
}
}
use AppBundle\DependencyInjection\AppExtension;
class AppCompilerPass implements CompilerPassInterface
{
private $extension;
public function __construct(AppExtension $extension = null)
{
$this->extension = $extension;
}
public function process(ContainerBuilder $container)
{
//...
if (!$this->extension) {
//always make sure the extension exists
return;
}
$config = $this->extension->getConfig();
dump($config);
//...
}
}
我有点晚了,但这是我习惯于在编译器传递中检索配置的方式(这应该让每个人都开心;)。
首先,让我们在一个参数中设置配置(或其中的一部分):
<?php
namespace Me\Bundle\MyBundle\DependencyInjection;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\Yaml\Yaml;
class MyBundleExtension extends Extension
{
const CONFIG_PATH = __DIR__.'/../Resources/config';
/**
* {@inheritdoc}
*/
public function load(array $configs, ContainerBuilder $container)
{
$config = $this->processConfiguration($this->getConfiguration($configs, $container), $configs);
$loader = new YamlFileLoader($container, new FileLocator(self::CONFIG_PATH));
$container->setParameter('my_bundle.config', $config);
}
}
然后,您可以像在编译器传递中那样使用它:
<?php
namespace Me\Bundle\MyBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
class UseConfigPass implements CompilerPassInterface
{
/**
* {@inheritdoc}
*/
public function process(ContainerBuilder $container)
{
// ...
$config = $container->getParameter('my_bundle.config');
// ...
}
}
这样,config 只在扩展文件中处理,您不需要询问第一个元素!
请注意,如果您希望更改另一个捆绑包的配置,您可能需要查看prepend extension。
这是一个老问题,但到目前为止我正在使用这个:
use Symfony\Component\Config\Definition\Processor;
...
public function process(ContainerBuilder $container)
{
$config = $this->getConfiguration($container);
...
}
/**
* @param ContainerBuilder $container
* @return array
*/
private function getConfiguration(ContainerBuilder $container)
{
$parameterBag = $container->getParameterBag();
$processor = new Processor();
$configuration = new Configuration();
return $processor->processConfiguration($configuration, $parameterBag->resolveValue($container->getExtensionConfig('YOUR_EXTENSION')));
}
是的,对于每个 CompilerPass,它都会处理配置,但就我而言,我只有一个,所以没什么大不了的。
@xPheRe 在编译器传递中加载配置不是一个好的解决方案。这意味着如果您有多个编译器,您将多次加载配置。配置应该在扩展中加载一次。
正如@Peter 所说,如果您确定配置存在,请执行以下操作:
$config = $container->getExtensionConfig('acme_demo')[0];
然后你可以做这样的事情:
$definition = new Definition('your_service_id');
$definition->setArgument(0, $config);