7

同じバンドルのコンパイラパス中に解釈する必要があるバンドルのセマンティック構成があります。

中間コンテナ変数に格納せずにアクセスすることは可能ですか?

4

7 に答える 7

8

はい、種類:

<?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によって定義された値)。

ここここを参照してください

于 2013-07-22T15:25:18.417 に答える
6

@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);
    }
}
于 2015-09-14T11:38:11.757 に答える
4

これは古い投稿であることに気付きましたが、同じ情報を探していたところ、最終的にこれが単一のパラメーターで機能することがわかりました。

$cfgVal = $container
  ->getParameterBag()
  ->resolveValue( $container->getParameter( 'param_name' ));

もちろん、この機能は元の投稿の後に追加された可能性があります。

于 2015-07-09T20:13:50.957 に答える
4

後で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);
        //...
    }
}
于 2018-12-21T17:59:52.743 に答える
1

@xPheReコンパイラパスで構成をロードするのは良い解決策ではありません。これは、複数のコンパイラがある場合、構成を数回ロードすることを意味します。構成は、拡張機能に1回ロードする必要があります。

@Peterが言ったように、構成が存在することが確実な場合は、次のようにします。

$config = $container->getExtensionConfig('acme_demo')[0];

次に、次のようなことを行うことができます。

$definition = new Definition('your_service_id');
$definition->setArgument(0, $config);
于 2018-04-07T02:09:16.637 に答える
1

私は少し遅れていますが、コンパイラパスで設定を取得するために使用する方法は次のとおりです(これでみんなが幸せになるはずです;)。

まず、構成(またはその一部)をパラメーターに設定しましょう。

<?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を確認することをお勧めします。

于 2018-08-01T09:35:06.763 に答える
1

これは古い質問ですが、私はこれまでこれを使用しています:

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つしかないので、大したことではありません。

于 2020-04-29T09:08:21.067 に答える