How to Create Friendly Configuration for a Bundle

If you open your main application configuration directory (usually config/packages/), you'll see a number of different files, such as framework.yaml, twig.yaml and doctrine.yaml. Each of these configures a specific bundle, allowing you to define options at a high level and then let the bundle make all the low-level, complex changes based on your settings.

メインのアプリケーション構成ディレクトリ (通常は config/packages/) を開くと、framework.yaml、twig.yaml、doctrine.yaml などのさまざまなファイルが表示されます。これらのそれぞれが特定のバンドルを構成し、高レベルでオプションを定義してから、設定に基づいて低レベルの複雑な変更をすべてバンドルに任せることができます。

For example, the following configuration tells the FrameworkBundle to enable the form integration, which involves the definition of quite a few services as well as integration of other related components:

たとえば、次の構成は、FrameworkBundle にフォーム統合を有効にするように指示します。これには、かなりの数のサービスの定義と他の関連コンポーネントの統合が含まれます。
  • YAML
    YAML
  • XML
    XML
  • PHP
    PHP
1
2
3
# config/packages/framework.yaml
framework:
    form: true

Using the Bundle Extension

Imagine you are creating a new bundle - AcmeSocialBundle - which provides integration with Twitter. To make your bundle configurable to the user, you can add some configuration that looks like this:

Twitter との統合を提供する新しいバンドル AcmeSocialBundle を作成しているとします。バンドルをユーザーが構成できるようにするには、次のような構成を追加します。
  • YAML
    YAML
  • XML
    XML
  • PHP
    PHP
1
2
3
4
5
# config/packages/acme_social.yaml
acme_social:
    twitter:
        client_id: 123
        client_secret: your_secret

The basic idea is that instead of having the user override individual parameters, you let the user configure just a few, specifically created, options. As the bundle developer, you then parse through that configuration and load correct services and parameters inside an "Extension" class.

基本的な考え方は、ユーザーが個々のパラメーターをオーバーライドする代わりに、ユーザーが特別に作成されたいくつかのオプションのみを構成できるようにすることです。バンドル開発者として、その構成を解析し、「拡張」クラス内に正しいサービスとパラメーターをロードします。

Note

ノート

The root key of your bundle configuration (acme_social in the previous example) is automatically determined from your bundle name (it's the snake case of the bundle name without the Bundle suffix ).

バンドル構成のルート キー (前の例の acme_social ) は、バンドル名から自動的に決定されます (これは、 Bundle suffix のないバンドル名のスネーク ケースです)。

See also

こちらもご覧ください

Read more about the extension in How to Load Service Configuration inside a Bundle.

拡張機能の詳細については、バンドル内にサービス構成を読み込む方法を参照してください。

Tip

ヒント

If a bundle provides an Extension class, then you should not generally override any service container parameters from that bundle. The idea is that if an Extension class is present, every setting that should be configurable should be present in the configuration made available by that class. In other words, the extension class defines all the public configuration settings for which backward compatibility will be maintained.

バンドルが拡張クラスを提供する場合、通常、そのバンドルのサービス コンテナ パラメータをオーバーライドしないでください。拡張クラスが存在する場合、構成可能であるべきすべての設定が、そのクラスによって使用可能になる構成に存在する必要があるという考えです。つまり、拡張クラスは、下位互換性が維持されるすべての publicconfiguration 設定を定義します。

See also

こちらもご覧ください

For parameter handling within a dependency injection container see Using Parameters within a Dependency Injection Class.

依存性注入コンテナー内のパラメーター処理については、依存性注入クラス内でのパラメーターの使用を参照してください。

Processing the $configs Array

First things first, you have to create an extension class as explained in How to Load Service Configuration inside a Bundle.

まず最初に、バンドル内にサービス構成をロードする方法で説明されているように、拡張クラスを作成する必要があります。

Whenever a user includes the acme_social key (which is the DI alias) in a configuration file, the configuration under it is added to an array of configurations and passed to the load() method of your extension (Symfony automatically converts XML and YAML to an array).

ユーザーが構成ファイルに acme_social キー (DI エイリアス) を含めるたびに、その下の構成が構成の配列に追加され、拡張機能の load() メソッドに渡されます (Symfony は自動的に XML と YAML を配列に変換します)。

For the configuration example in the previous section, the array passed to your load() method will look like this:

前のセクションの構成例では、 yourload() メソッドに渡される配列は次のようになります。
1
2
3
4
5
6
7
8
[
    [
        'twitter' => [
            'client_id' => 123,
            'client_secret' => 'your_secret',
        ],
    ],
]

Notice that this is an array of arrays, not just a single flat array of the configuration values. This is intentional, as it allows Symfony to parse several configuration resources. For example, if acme_social appears in another configuration file - say config/packages/dev/acme_social.yaml - with different values beneath it, the incoming array might look like this:

これは、構成値の単一のフラットな配列ではなく、配列の配列であることに注意してください。これは、Symfony が複数の構成リソースを解析できるようにするため、意図的なものです。たとえば、acme_social が別の構成ファイル (config/packages/dev/acme_social.yaml など) に表示され、その下に異なる値がある場合、受信配列は次のようになります。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[
    // values from config/packages/acme_social.yaml
    [
        'twitter' => [
            'client_id' => 123,
            'client_secret' => 'your_secret',
        ],
    ],
    // values from config/packages/dev/acme_social.yaml
    [
        'twitter' => [
            'client_id' => 456,
        ],
    ],
]

The order of the two arrays depends on which one is set first.

2 つの配列の順序は、どちらが最初に設定されたかによって異なります。

But don't worry! Symfony's Config component will help you merge these values, provide defaults and give the user validation errors on bad configuration. Here's how it works. Create a Configuration class in the DependencyInjection directory and build a tree that defines the structure of your bundle's configuration.

しかし、心配しないでください! Symfony の Config コンポーネントは、これらの値をマージし、デフォルトを提供し、不適切な構成でユーザー検証エラーを与えるのに役立ちます。 DependencyInjection ディレクトリに構成クラスを作成し、バンドルの構成の構造を定義するツリーを構築します。

The Configuration class to handle the sample configuration looks like:

サンプル構成を処理する Configuration クラスは次のようになります。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// src/Acme/SocialBundle/DependencyInjection/Configuration.php
namespace Acme\SocialBundle\DependencyInjection;

use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;

class Configuration implements ConfigurationInterface
{
    public function getConfigTreeBuilder()
    {
        $treeBuilder = new TreeBuilder('acme_social');

        $treeBuilder->getRootNode()
            ->children()
                ->arrayNode('twitter')
                    ->children()
                        ->integerNode('client_id')->end()
                        ->scalarNode('client_secret')->end()
                    ->end()
                ->end() // twitter
            ->end()
        ;

        return $treeBuilder;
    }
}

See also

こちらもご覧ください

The Configuration class can be much more complicated than shown here, supporting "prototype" nodes, advanced validation, XML-specific normalization and advanced merging. You can read more about this in the Config component documentation. You can also see it in action by checking out some core Configuration classes, such as the one from the FrameworkBundle Configuration or the TwigBundle Configuration.

構成クラスは、「プロトタイプ」ノード、高度な検証、XML 固有の正規化、および高度なマージをサポートする、ここに示すよりもはるかに複雑になる可能性があります。詳細については、Config コンポーネントのドキュメントを参照してください。また、FrameworkBundle Configuration や TwigBundle Configuration からのものなど、いくつかのコア Configurationclass をチェックアウトすることで、実際の動作を確認することもできます。

This class can now be used in your load() method to merge configurations and force validation (e.g. if an additional option was passed, an exception will be thrown):

このクラスを load() メソッドで使用して、構成をマージし、検証を強制できます (たとえば、追加のオプションが渡された場合、例外がスローされます)。
1
2
3
4
5
6
7
8
9
10
// src/Acme/SocialBundle/DependencyInjection/AcmeSocialExtension.php
public function load(array $configs, ContainerBuilder $container)
{
    $configuration = new Configuration();

    $config = $this->processConfiguration($configuration, $configs);

    // you now have these 2 config keys
    // $config['twitter']['client_id'] and $config['twitter']['client_secret']
}

The processConfiguration() method uses the configuration tree you've defined in the Configuration class to validate, normalize and merge all the configuration arrays together.

processConfiguration() メソッドは、Configuration クラスで定義した構成ツリーを使用して、すべての構成配列を検証、正規化、マージします。

Now, you can use the $config variable to modify a service provided by your bundle. For example, imagine your bundle has the following example config:

$config 変数を使用して、バンドルによって提供されるサービスを変更できるようになりました。たとえば、バンドルに次の例の構成があるとします。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!-- src/Acme/SocialBundle/Resources/config/services.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://symfony.com/schema/dic/services
        https://symfony.com/schema/dic/services/services-1.0.xsd"
>
    <services>
        <service id="acme.social.twitter_client" class="Acme\SocialBundle\TwitterClient">
            <argument></argument> <!-- will be filled in with client_id dynamically -->
            <argument></argument> <!-- will be filled in with client_secret dynamically -->
        </service>
    </services>
</container>

In your extension, you can load this and dynamically set its arguments:

拡張機能では、これをロードして、その引数を動的に設定できます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// src/Acme/SocialBundle/DependencyInjection/AcmeSocialExtension.php
// ...

use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;

public function load(array $configs, ContainerBuilder $container)
{
    $loader = new XmlFileLoader($container, new FileLocator(dirname(__DIR__).'/Resources/config'));
    $loader->load('services.xml');

    $configuration = new Configuration();
    $config = $this->processConfiguration($configuration, $configs);

    $definition = $container->getDefinition('acme.social.twitter_client');
    $definition->replaceArgument(0, $config['twitter']['client_id']);
    $definition->replaceArgument(1, $config['twitter']['client_secret']);
}

Tip

ヒント

Instead of calling processConfiguration() in your extension each time you provide some configuration options, you might want to use the ConfigurableExtension to do this automatically for you:

いくつかの設定オプションを提供するたびに拡張機能で processConfiguration() を呼び出す代わりに、ConfigurableExtension を使用してこれを自動的に行うことができます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// src/Acme/HelloBundle/DependencyInjection/AcmeHelloExtension.php
namespace Acme\HelloBundle\DependencyInjection;

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\DependencyInjection\ConfigurableExtension;

class AcmeHelloExtension extends ConfigurableExtension
{
    // note that this method is called loadInternal and not load
    protected function loadInternal(array $mergedConfig, ContainerBuilder $container)
    {
        // ...
    }
}

This class uses the getConfiguration() method to get the Configuration instance.

このクラスは、getConfiguration() メソッドを使用して Configuration インスタンスを取得します。
自分で構成を処理する

Using the Config component is fully optional. The load() method gets an array of configuration values. You can instead parse these arrays yourself (e.g. by overriding configurations and using isset to check for the existence of a value). Be aware that it'll be very hard to support XML:

Config コンポーネントの使用は完全にオプションです。 load() メソッドは、構成値の配列を取得します。代わりに、これらの配列を自分で解析できます (たとえば、構成をオーバーライドし、 isset を使用して値の存在を確認します)。 XML をサポートするのは非常に難しいことに注意してください。
1
2
3
4
5
6
7
8
9
10
public function load(array $configs, ContainerBuilder $container)
{
    $config = [];
    // let resources override the previous set value
    foreach ($configs as $subConfig) {
        $config = array_merge($config, $subConfig);
    }

    // ... now use the flat $config array
}

Using the Bundle Class

6.1

6.1

The AbstractBundle class was introduced in Symfony 6.1.

AbstractBundle クラスは Symfony 6.1 で導入されました。

Instead of creating an extension and configuration class, you can also extend AbstractBundle to add this logic to the bundle class directly:

拡張機能と構成クラスを作成する代わりに、AbstractBundle を拡張して、このロジックをバンドル クラスに直接追加することもできます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// src/AcmeSocialBundle.php
namespace Acme\SocialBundle;

use Symfony\Component\Config\Definition\Configurator\DefinitionConfigurator;
use Symfony\Component\HttpKernel\Bundle\AbstractBundle;

class AcmeSocialBundle extends AbstractBundle
{
    public function configure(DefinitionConfigurator $definition): void
    {
        $definition->rootNode()
            ->children()
                ->arrayNode('twitter')
                    ->children()
                        ->integerNode('client_id')->end()
                        ->scalarNode('client_secret')->end()
                    ->end()
                ->end() // twitter
            ->end()
        ;
    }

    public function loadExtension(array $config, ContainerConfigurator $container, ContainerBuilder $builder): void
    {
        // Contrary to the Extension class, the "$config" variable is already merged
        // and processed. You can use it directly to configure the service container.
        $container->services()
            ->get('acme.social.twitter_client')
            ->arg(0, $config['twitter']['client_id'])
            ->arg(1, $config['twitter']['client_secret'])
        ;
    }
}

Note

ノート

The configure() and loadExtension() methods are called only at compile time.

configure() および loadExtension() メソッドは、コンパイル時にのみ呼び出されます。

Tip

ヒント

The AbstractBundle::configure() method also allows to import the configuration definition from one or more files:

AbstractBundle::configure() メソッドを使用すると、1 つ以上のファイルから構成定義をインポートすることもできます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// src/AcmeSocialBundle.php

// ...
class AcmeSocialBundle extends AbstractBundle
{
    public function configure(DefinitionConfigurator $definition): void
    {
        $definition->import('../config/definition.php');
        // you can also use glob patterns
        //$definition->import('../config/definition/*.php');
    }

    // ...
}
1
2
3
4
5
6
7
8
9
10
// config/definition.php
use Symfony\Component\Config\Definition\Configurator\DefinitionConfigurator;

return static function (DefinitionConfigurator $definition) {
    $definition->rootNode()
        ->children()
            ->scalarNode('foo')->defaultValue('bar')->end()
        ->end()
    ;
};

Modifying the Configuration of Another Bundle

If you have multiple bundles that depend on each other, it may be useful to allow one Extension class to modify the configuration passed to another bundle's Extension class. This can be achieved using a prepend extension. For more details, see How to Simplify Configuration of Multiple Bundles.

互いに依存する複数のバンドルがある場合、1 つの Extension クラスが別のバンドルの Extension クラスに渡された構成を変更できるようにすると便利な場合があります。これは、プリペンド拡張機能を使用して実現できます。詳細については、「複数のバンドルの構成を簡素化する方法」を参照してください。

Dump the Configuration

The config:dump-reference command dumps the default configuration of a bundle in the console using the Yaml format.

config:dump-reference コマンドは、Yaml 形式を使用してコンソールに abundle のデフォルト設定をダンプします。

As long as your bundle's configuration is located in the standard location (YourBundle\DependencyInjection\Configuration) and does not have a constructor, it will work automatically. If you have something different, your Extension class must override the Extension::getConfiguration() method and return an instance of your Configuration.

バンドルの構成が標準の場所 (YourBundle\DependencyInjection\Configuration) にあり、コンストラクターがない限り、自動的に機能します。何か違う場合は、Extension クラスが Extension::getConfiguration() メソッドをオーバーライドし、Configuration のインスタンスを返す必要があります。

Supporting XML

Symfony allows people to provide the configuration in three different formats: Yaml, XML and PHP. Both Yaml and PHP use the same syntax and are supported by default when using the Config component. Supporting XML requires you to do some more things. But when sharing your bundle with others, it is recommended that you follow these steps.

Symfony では、Yaml、XML、および PHP の 3 つの異なる形式で構成を提供できます。 Yaml と PHP はどちらも同じ構文を使用し、Config コンポーネントを使用する場合はデフォルトでサポートされます。 XML をサポートするには、さらにいくつかのことを行う必要があります。ただし、バンドルを他のユーザーと共有する場合は、次の手順に従うことをお勧めします。

Make your Config Tree ready for XML

The Config component provides some methods by default to allow it to correctly process XML configuration. See "Defining and Processing Configuration Values" of the component documentation. However, you can do some optional things as well, this will improve the experience of using XML configuration:

Config コンポーネントは、XML 構成を正しく処理できるように、デフォルトでいくつかのメソッドを提供します。コンポーネントのドキュメントの「構成値の定義と処理」を参照してください。ただし、いくつかのオプションのことも実行できます。これにより、XML 構成の使用体験が向上します。

Choosing an XML Namespace

In XML, the XML namespace is used to determine which elements belong to the configuration of a specific bundle. The namespace is returned from the Extension::getNamespace() method. By convention, the namespace is a URL (it doesn't have to be a valid URL nor does it need to exist). By default, the namespace for a bundle is http://example.org/schema/dic/DI_ALIAS, where DI_ALIAS is the DI alias of the extension. You might want to change this to a more professional URL:

XML では、XML 名前空間を使用して、特定のバンドルの構成に属する要素を判別します。名前空間は、Extension::getNamespace() メソッドから返されます。慣例により、名前空間は URL です (有効な URL である必要はなく、存在する必要もありません)。デフォルトでは、バンドルの名前空間は http://example.org/schema/dic/DI_ALIAS です。ここで、DI_ALIAS は拡張機能の DI エイリアスです。これをより専門的な URL に変更することをお勧めします。
1
2
3
4
5
6
7
8
9
10
11
12
// src/Acme/HelloBundle/DependencyInjection/AcmeHelloExtension.php

// ...
class AcmeHelloExtension extends Extension
{
    // ...

    public function getNamespace()
    {
        return 'http://acme_company.com/schema/dic/hello';
    }
}

Providing an XML Schema

XML has a very useful feature called XML schema. This allows you to describe all possible elements and attributes and their values in an XML Schema Definition (an XSD file). This XSD file is used by IDEs for auto completion and it is used by the Config component to validate the elements.

XML には、XML スキーマと呼ばれる非常に便利な機能があります。これにより、可能なすべての要素と属性、およびそれらの値を XML SchemaDefinition (XSD ファイル) で記述できます。この XSD ファイルは、IDE でオート コンプリートに使用され、Config コンポーネントで要素を検証するために使用されます。

In order to use the schema, the XML configuration file must provide an xsi:schemaLocation attribute pointing to the XSD file for a certain XML namespace. This location always starts with the XML namespace. This XML namespace is then replaced with the XSD validation base path returned from Extension::getXsdValidationBasePath() method. This namespace is then followed by the rest of the path from the base path to the file itself.

スキーマを使用するために、XML 構成ファイルは、特定の XMLnamespace の XSD ファイルを指す anxsi:schemaLocation 属性を提供する必要があります。この場所は、常に XML 名前空間で始まります。この XML 名前空間は、Extension::getXsdValidationBasePath() メソッドから返された XSD 検証ベース パスに置き換えられます。この名前空間の後には、ベースパスからファイル自体への残りのパスが続きます。

By convention, the XSD file lives in the Resources/config/schema/, but you can place it anywhere you like. You should return this path as the base path:

慣例により、XSD ファイルは Resources/config/schema/ にありますが、好きな場所に配置できます。このパスをベース パスとして返す必要があります。
1
2
3
4
5
6
7
8
9
10
11
12
// src/Acme/HelloBundle/DependencyInjection/AcmeHelloExtension.php

// ...
class AcmeHelloExtension extends Extension
{
    // ...

    public function getXsdValidationBasePath()
    {
        return __DIR__.'/../Resources/config/schema';
    }
}

Assuming the XSD file is called hello-1.0.xsd, the schema location will be https://acme_company.com/schema/dic/hello/hello-1.0.xsd:

XSD ファイルの名前が hello-1.0.xsd であるとすると、スキーマの場所は https://acme_company.com/schema/dic/hello/hello-1.0.xsd になります。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!-- config/packages/acme_hello.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:acme-hello="http://acme_company.com/schema/dic/hello"
    xsi:schemaLocation="http://symfony.com/schema/dic/services
        https://symfony.com/schema/dic/services/services-1.0.xsd
        http://acme_company.com/schema/dic/hello
        https://acme_company.com/schema/dic/hello/hello-1.0.xsd"
>
    <acme-hello:config>
        <!-- ... -->
    </acme-hello:config>

    <!-- ... -->
</container>