How to Load Service Configuration inside a Bundle

Services created by bundles are not defined in the main config/services.yaml file used by the application but in the bundles themselves. This article explains how to create and load service files using the bundle directory structure.

バンドルによって作成されたサービスは、アプリケーションによって使用されるメインの config/services.yaml ファイルではなく、バンドル自体で定義されます。この記事では、バンドル ディレクトリ構造を使用してサービス ファイルを作成およびロードする方法について説明します。

Creating an Extension Class

In order to load service configuration, you have to create a Dependency Injection (DI) Extension for your bundle. By default, the Extension class must follow these conventions (but later you'll learn how to skip them if needed):

サービス構成をロードするには、バンドルの DependencyInjection (DI) 拡張機能を作成する必要があります。デフォルトでは、Extension クラスは次の規則に従う必要があります (ただし、後で必要に応じてスキップする方法を学習します)。
  • It has to live in the DependencyInjection namespace of the bundle;
    バンドルの DependencyInjection 名前空間に存在する必要があります。
  • It has to implement the ExtensionInterface, which is usually achieved by extending the Extension class;
    通常、Extension クラスを拡張することによって実現される ExtensionInterface を実装する必要があります。
  • The name is equal to the bundle name with the Bundle suffix replaced by Extension (e.g. the Extension class of the AcmeBundle would be called AcmeExtension and the one for AcmeHelloBundle would be called AcmeHelloExtension).
    この名前は、バンドルの接尾辞を Extension に置き換えたバンドル名と同じです (たとえば、AcmeBundle の Extension クラスは AcmeExtension と呼ばれ、AcmeHelloBundle の拡張クラスは AcmeHelloExtension と呼ばれます)。

This is how the extension of an AcmeHelloBundle should look like:

AcmeHelloBundle の拡張は次のようになります。
1
2
3
4
5
6
7
8
9
10
11
12
13
// src/DependencyInjection/AcmeHelloExtension.php
namespace Acme\HelloBundle\DependencyInjection;

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\Extension;

class AcmeHelloExtension extends Extension
{
    public function load(array $configs, ContainerBuilder $container)
    {
        // ... you'll load the files here later
    }
}

Manually Registering an Extension Class

When not following the conventions, you will have to manually register your extension. To do this, you should override the Bundle::getContainerExtension() method to return the instance of the extension:

規約に従わない場合は、拡張機能を手動で登録する必要があります。これを行うには、Bundle::getContainerExtension() メソッドをオーバーライドして、拡張機能のインスタンスを返す必要があります。
1
2
3
4
5
6
7
8
9
10
// ...
use Acme\HelloBundle\DependencyInjection\UnconventionalExtensionClass;

class AcmeHelloBundle extends Bundle
{
    public function getContainerExtension()
    {
        return new UnconventionalExtensionClass();
    }
}

In addition, when the new Extension class name doesn't follow the naming conventions, you must also override the Extension::getAlias() method to return the correct DI alias. The DI alias is the name used to refer to the bundle in the container (e.g. in the config/packages/ files). By default, this is done by removing the Extension suffix and converting the class name to underscores (e.g. AcmeHelloExtension's DI alias is acme_hello).

さらに、新しい Extension クラス名が命名規則に従っていない場合は、Extension::getAlias() メソッドをオーバーライドして正しい DI エイリアスを返す必要もあります。 DI エイリアスは、コンテナー内のバンドルを参照するために使用される名前です (例: config/packages/ ファイル内)。デフォルトでは、これは Extension サフィックスを削除し、クラス名をアンダースコアに変換することによって行われます (例: AcmeHelloExtension の DI エイリアス isacme_hello)。

Using the load() Method

In the load() method, all services and parameters related to this extension will be loaded. This method doesn't get the actual container instance, but a copy. This container only has the parameters from the actual container. After loading the services and parameters, the copy will be merged into the actual container, to ensure all services and parameters are also added to the actual container.

load() メソッドでは、この拡張機能に関連するすべてのサービスとパラメーターが読み込まれます。このメソッドは、実際のコンテナ インスタンスを取得するのではなく、コピーを取得します。このコンテナーには、実際のコンテナーのパラメーターのみが含まれます。サービスとパラメーターをロードした後、コピーは実際のコンテナーにマージされ、すべてのサービスとパラメーターが実際のコンテナーにも追加されるようにします。

In the load() method, you can use PHP code to register service definitions, but it is more common if you put these definitions in a configuration file (using the YAML, XML or PHP format).

load() メソッドでは、PHP コードを使用してサービス定義を登録できますが、これらの定義を (YAML、XML、または PHP 形式を使用して) 構成ファイルに入れる方がより一般的です。

For instance, assume you have a file called services.xml in the config/ directory of your bundle, your load() method looks like:

たとえば、バンドルの config/ ディレクトリに services.xml というファイルがあるとします。load() メソッドは次のようになります。
1
2
3
4
5
6
7
8
9
10
11
12
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;

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

The other available loaders are YamlFileLoader and PhpFileLoader.

他の使用可能なローダーは、YamlFileLoader と PhpFileLoader です。

Using Configuration to Change the Services

The Extension is also the class that handles the configuration for that particular bundle (e.g. the configuration in config/packages/<bundle_alias>.yaml). To read more about it, see the "How to Create Friendly Configuration for a Bundle" article.

拡張機能は、その特定のバンドルの構成を処理するクラスでもあります (例: config/packages/.yaml の構成)。詳細については、「バンドルのわかりやすい構成を作成する方法」の記事を参照してください。

Loading Services directly in your Bundle class

6.1

6.1

The AbstractBundle class was introduced in Symfony 6.1.

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

Alternatively, you can define and load services configuration directly in a bundle class instead of creating a specific Extension class. You can do this by extending from AbstractBundle and defining the loadExtension() method:

または、特定の Extension クラスを作成する代わりに、サービス構成を abundle クラスで直接定義してロードすることもできます。これは、AbstractBundle から拡張して loadExtension() メソッドを定義することで実行できます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// ...
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use Symfony\Component\HttpKernel\Bundle\AbstractBundle;

class AcmeHelloBundle extends AbstractBundle
{
    public function loadExtension(array $config, ContainerConfigurator $container, ContainerBuilder $builder): void
    {
        // load an XML, PHP or Yaml file
        $container->import('../config/services.xml');

        // you can also add or replace parameters and services
        $container->parameters()
            ->set('acme_hello.phrase', $config['phrase'])
        ;

        if ($config['scream']) {
            $container->services()
                ->get('acme_hello.printer')
                    ->class(ScreamingPrinter::class)
            ;
        }
    }
}

This method works similar to the Extension::load() method, but it uses a new API to define and import service configuration.

このメソッドは Extension::load() メソッドと同様に機能しますが、新しい API を使用してサービス構成を定義およびインポートします。

Note

ノート

Contrary to the $configs parameter in Extension::load(), the $config parameter is already merged and processed by the AbstractBundle.

Extension::load() の $configs パラメーターとは対照的に、$config パラメーターは、AbstractBundle によって既にマージおよび処理されています。

Note

ノート

The loadExtension() is called only at compile time.

loadExtension() はコンパイル時にのみ呼び出されます。

Adding Classes to Compile

Bundles can hint Symfony about which of their classes contain annotations so they are compiled when generating the application cache to improve the overall performance. Define the list of annotated classes to compile in the addAnnotatedClassesToCompile() method:

バンドルは、どのクラスにアノテーションが含まれているかについて Symfony にヒントを与えることができるため、アプリケーション キャッシュを生成するときにそれらがコンパイルされ、全体的なパフォーマンスが向上します。 addAnnotatedClassesToCompile() メソッドでコンパイルするアノテーション付きクラスのリストを定義します。
1
2
3
4
5
6
7
8
9
10
11
12
13
public function load(array $configs, ContainerBuilder $container)
{
    // ...

    $this->addAnnotatedClassesToCompile([
        // you can define the fully qualified class names...
        'App\\Controller\\DefaultController',
        // ... but glob patterns are also supported:
        '**Bundle\\Controller\\',

        // ...
    ]);
}

Note

ノート

If some class extends from other classes, all its parents are automatically included in the list of classes to compile.

一部のクラスが他のクラスから拡張されている場合、そのすべての親がコンパイルするクラスのリストに自動的に含まれます。

Patterns are transformed into the actual class namespaces using the classmap generated by Composer. Therefore, before using these patterns, you must generate the full classmap executing the dump-autoload command of Composer.

パターンは、Composer によって生成されたクラスマップを使用して、実際のクラスの名前空間に変換されます。したがって、これらのパターンを使用する前に、Composer の dump-autoload コマンドを実行して完全なクラスマップを生成する必要があります。

Caution

注意

This technique can't be used when the classes to compile use the __DIR__ or __FILE__ constants, because their values will change when loading these classes from the classes.php file.

この手法は、コンパイルするクラスが __DIR__ または __FILE__ 定数を使用する場合は使用できません。これらのクラスを classes.php ファイルからロードすると値が変更されるためです。