同じバンドルのコンパイラパス中に解釈する必要があるバンドルのセマンティック構成があります。
中間コンテナ変数に格納せずにアクセスすることは可能ですか?
同じバンドルのコンパイラパス中に解釈する必要があるバンドルのセマンティック構成があります。
中間コンテナ変数に格納せずにアクセスすることは可能ですか?
はい、種類:
<?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);
//...
}
}
@xPheReコンパイラパスで構成をロードするのは良い解決策ではありません。これは、複数のコンパイラがある場合、構成を数回ロードすることを意味します。構成は、拡張機能に1回ロードする必要があります。
@Peterが言ったように、構成が存在することが確実な場合は、次のようにします。
$config = $container->getExtensionConfig('acme_demo')[0];
次に、次のようなことを行うことができます。
$definition = new Definition('your_service_id');
$definition->setArgument(0, $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は拡張ファイルでのみ処理され、最初の要素を要求する必要はありません。
別のバンドルの構成を変更したい場合は、prependextensionを確認することをお勧めします。
これは古い質問ですが、私はこれまでこれを使用しています:
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ごとに構成が処理されますが、私の場合は1つしかないので、大したことではありません。