Best Practices for Reusable Bundles

This article is all about how to structure your reusable bundles to be configurable and extendable. Reusable bundles are those meant to be shared privately across many company projects or publicly so any Symfony project can install them.

この記事では、再利用可能なバンドルを構成および拡張可能に構成する方法について説明します。再利用可能なバンドルは、多くの会社のプロジェクト間で非公開で共有することを意図したもの、またはどの Symfony プロジェクトでもそれらをインストールできるように公に共有することを意図したものです。

Bundle Name

A bundle is also a PHP namespace. The namespace must follow the PSR-4 interoperability standard for PHP namespaces and class names: it starts with a vendor segment, followed by zero or more category segments, and it ends with the namespace short name, which must end with Bundle.

バンドルも PHP 名前空間です。名前空間は、PHP の名前空間とクラス名の PSR-4 相互運用性標準に準拠する必要があります。名前空間は avendor セグメントで始まり、その後に 0 個以上のカテゴリ セグメントが続き、名前空間の短い名前で終わります。これは Bundle で終わる必要があります。

A namespace becomes a bundle as soon as you add "a bundle class" to it (which is a class that extends Bundle). The bundle class name must follow these rules:

名前空間は、「バンドル クラス」 (Bundle を拡張するクラス) を追加するとすぐにバンドルになります。バンドル クラス名は、次の規則に従う必要があります。
  • Use only alphanumeric characters and underscores;
    英数字とアンダースコアのみを使用してください。
  • Use a StudlyCaps name (i.e. camelCase with an uppercase first letter);
    StudlyCaps 名を使用します (つまり、最初の文字が大文字のキャメルケース)。
  • Use a descriptive and short name (no more than two words);
    説明的で短い名前 (2 語以内) を使用してください。
  • Prefix the name with the concatenation of the vendor (and optionally the category namespaces);
    名前の前にベンダー (およびオプションでカテゴリ名前空間) を連結したものを付けます。
  • Suffix the name with Bundle.
    名前の末尾に Bundle を付けます。

Here are some valid bundle namespaces and class names:

有効なバンドルの名前空間とクラス名は次のとおりです。
Namespace Bundle Class Name
Acme\Bundle\BlogBundle AcmeBlogBundle
Acme\BlogBundle AcmeBlogBundle

By convention, the getName() method of the bundle class should return the class name.

慣例により、バンドル クラスの getName() メソッドはクラス名を返す必要があります。

Note

ノート

If you share your bundle publicly, you must use the bundle class name as the name of the repository (AcmeBlogBundle and not BlogBundle for instance).

バンドルを公に共有する場合は、バンドル クラス名をリポジトリの名前として使用する必要があります (たとえば、BlogBu​​ndle ではなく AcmeBlogBu​​ndle)。

Note

ノート

Symfony core Bundles do not prefix the Bundle class with Symfony and always add a Bundle sub-namespace; for example: FrameworkBundle.

Symfony コア バンドルは Bundle クラスの前に Symfony を付けず、常に Bundle サブ名前空間を追加します。例:FrameworkBundle。

Each bundle has an alias, which is the lower-cased short version of the bundle name using underscores (acme_blog for AcmeBlogBundle). This alias is used to enforce uniqueness within a project and for defining bundle's configuration options (see below for some usage examples).

各バンドルにはエイリアスがあります。これは、アンダースコアを使用した小文字の短いバージョンのバンドル名です (AcmeBlogBu​​ndle の場合は acme_blog)。このエイリアスは、プロジェクト内で一意性を確保するため、およびバンドルの構成オプションを定義するために使用されます (使用例については、以下を参照してください)。

Directory Structure

The following is the recommended directory structure of an AcmeBlogBundle:

AcmeBlogBu​​ndle の推奨ディレクトリ構造は次のとおりです。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/
├── config/
├── docs/
│   └─ index.md
├── public/
├── src/
│   ├── Controller/
│   ├── DependencyInjection/
│   └── AcmeBlogBundle.php
├── templates/
├── tests/
├── translations/
├── LICENSE
└── README.md

This directory structure requires to configure the bundle path to its root directory as follows:

このディレクトリ構造では、ルート ディレクトリへのバンドル パスを次のように構成する必要があります。
1
2
3
4
5
6
7
class AcmeBlogBundle extends Bundle
{
    public function getPath(): string
    {
        return \dirname(__DIR__);
    }
}

The following files are mandatory, because they ensure a structure convention that automated tools can rely on:

次のファイルは、自動化ツールが依存できる構造規則を保証するため、必須です。
  • src/AcmeBlogBundle.php: This is the class that transforms a plain directory into a Symfony bundle (change this to your bundle's name);
    src/AcmeBlogBu​​ndle.php: これはプレーン ディレクトリを Symfony バンドルに変換するクラスです (これをバンドルの名前に変更します)。
  • README.md: This file contains the basic description of the bundle and it usually shows some basic examples and links to its full documentation (it can use any of the markup formats supported by GitHub, such as README.rst);
    README.md: このファイルには、バンドルの基本的な説明が含まれており、通常、いくつかの基本的な例と完全なドキュメントへのリンクが示されています (README.rst など、GitHub でサポートされている任意のマークアップ形式を使用できます)。
  • LICENSE: The full contents of the license used by the code. Most third-party bundles are published under the MIT license, but you can choose any license;
    LICENSE: コードで使用されるライセンスの完全な内容。ほとんどのサードパーティ バンドルは MIT ライセンスの下で公開されていますが、任意のライセンスを選択できます。
  • docs/index.md: The root file for the Bundle documentation.
    docs/index.md: バンドル ドキュメントのルート ファイル。

The depth of subdirectories should be kept to a minimum for the most used classes and files. Two levels is the maximum.

サブディレクトリの深さは、最も使用されるクラスとファイルのために最小限に保つ必要があります。 2 レベルが最大です。

The bundle directory is read-only. If you need to write temporary files, store them under the cache/ or log/ directory of the host application. Tools can generate files in the bundle directory structure, but only if the generated files are going to be part of the repository.

バンドル ディレクトリは読み取り専用です。一時ファイルを書き込む必要がある場合は、それらをホスト アプリケーションの cache/ または log/ ディレクトリに保存します。ツールは、バンドル ディレクトリ構造にファイルを生成できますが、生成されたファイルがリポジトリの一部になる場合のみです。

The following classes and files have specific emplacements (some are mandatory and others are just conventions followed by most developers):

次のクラスとファイルには特定の配置があります (必須のものもあれば、ほとんどの開発者が従う慣習にすぎないものもあります)。
Type Directory
Commands src/Command/
Controllers src/Controller/
Service Container Extensions src/DependencyInjection/
Doctrine ORM entities src/Entity/
Doctrine ODM documents src/Document/
Event Listeners src/EventListener/
Configuration (routes, services, etc.) config/
Web Assets (CSS, JS, images) public/
Translation files translations/
Validation (when not using annotations) config/validation/
Serialization (when not using annotations) config/serialization/
Templates templates/
Unit and Functional Tests tests/

Classes

The bundle directory structure is used as the namespace hierarchy. For instance, a ContentController controller which is stored in src/Controller/ContentController.php would have the fully qualified class name of Acme\BlogBundle\Controller\ContentController.

バンドル ディレクトリ構造は、名前空間の階層として使用されます。たとえば、insrc/Controller/ContentController.php に格納されている ContentController コントローラは、Acme\BlogBu​​ndle\Controller\ContentController の完全修飾クラス名を持ちます。

All classes and files must follow the Symfony coding standards.

すべてのクラスとファイルは、Symfony コーディング標準に従う必要があります。

Some classes should be seen as facades and should be as short as possible, like Commands, Helpers, Listeners and Controllers.

Commands、Helpers、Listeners、Controllers のように、一部のクラスはファサードとして見なされ、できるだけ短くする必要があります。

Classes that connect to the event dispatcher should be suffixed with Listener.

イベント ディスパッチャーに接続するクラスには、withListener というサフィックスを付ける必要があります。

Exception classes should be stored in an Exception sub-namespace.

例外クラスは、Exception サブ名前空間に格納する必要があります。

Vendors

A bundle must not embed third-party PHP libraries. It should rely on the standard Symfony autoloading instead.

バンドルにサードパーティの PHP ライブラリを埋め込んではなりません。代わりに、標準の Symfony オートローディングに依存する必要があります。

A bundle should also not embed third-party libraries written in JavaScript, CSS or any other language.

また、バンドルには、JavaScript、CSS、またはその他の言語で記述されたサードパーティ ライブラリを埋め込んではなりません。

Doctrine Entities/Documents

If the bundle includes Doctrine ORM entities and/or ODM documents, it's recommended to define their mapping using XML files stored in Resources/config/doctrine/. This allows to override that mapping using the standard Symfony mechanism to override bundle parts. This is not possible when using annotations/attributes to define the mapping.

バンドルに Doctrine ORM エンティティおよび/または ODM ドキュメントが含まれている場合、Resources/config/doctrine/ に保存されている XML ファイルを使用してそれらのマッピングを定義することをお勧めします。これにより、標準の Symfony メカニズムを使用してそのマッピングをオーバーライドし、バンドル パーツをオーバーライドできます。注釈/属性を使用してマッピングを定義する場合、これは不可能です。

Tests

A bundle should come with a test suite written with PHPUnit and stored under the tests/ directory. Tests should follow the following principles:

バンドルには、PHPUnit で作成され、tests/ ディレクトリに保存されたテスト スイートが含まれている必要があります。テストは次の原則に従う必要があります。
  • The test suite must be executable with a simple phpunit command run from a sample application;
    テスト スイートは、サンプル アプリケーションから実行される単純な phpunit コマンドで実行可能である必要があります。
  • The functional tests should only be used to test the response output and some profiling information if you have some;
    機能テストは、応答出力とプロファイリング情報 (ある場合) をテストするためにのみ使用する必要があります。
  • The tests should cover at least 95% of the code base.
    テストは、コード ベースの少なくとも 95% をカバーする必要があります。

Note

ノート

A test suite must not contain AllTests.php scripts, but must rely on the existence of a phpunit.xml.dist file.

テスト スイートに AllTests.php スクリプトを含めることはできませんが、phpunit.xml.dist ファイルの存在に依存する必要があります。

Continuous Integration

Testing bundle code continuously, including all its commits and pull requests, is a good practice called Continuous Integration. There are several services providing this feature for free for open source projects, like GitHub Actions and Travis CI.

すべてのコミットとプル リクエストを含め、バンドル コードを継続的にテストすることは、継続的インテグレーションと呼ばれる優れたプラクティスです。 GitHub Actions や Travis CI など、オープン ソース プロジェクト向けにこの機能を無料で提供するサービスがいくつかあります。

A bundle should at least test:

バンドルは、少なくとも以下をテストする必要があります。
  • The lower bound of their dependencies (by running composer update --prefer-lowest);
    依存関係の下限 (composer update --prefer-lowest を実行)。
  • The supported PHP versions;
    サポートされている PHP バージョン。
  • All supported major Symfony versions (e.g. both 4.x and 5.x if support is claimed for both).
    サポートされているすべての主要な Symfony バージョン (例: 4.x と 5.x の両方がサポートされている場合)。

Thus, a bundle supporting PHP 7.3, 7.4 and 8.0, and Symfony 4.4 and 5.x should have at least this test matrix:

したがって、PHP 7.3、7.4、8.0、および Symfony 4.4、5.x をサポートするバンドルには、少なくとも次のテスト マトリックスが必要です。
PHP version Symfony version Composer flags
7.3 4.* --prefer-lowest
7.4 5.*  
8.0 5.*  

Tip

ヒント

The tests should be run with the SYMFONY_DEPRECATIONS_HELPER env variable set to max[direct]=0. This ensures no code in the bundle uses deprecated features directly.

テストは、SYMFONY_DEPRECATIONS_HELPERenv 変数を max[direct]=0 に設定して実行する必要があります。これにより、バンドル内のコードが非推奨の機能を直接使用しないことが保証されます。

The lowest dependency tests can be run with this variable set to disabled=1.

最も低い依存関係のテストは、この変数をdisabled=1に設定して実行できます。

Require a Specific Symfony Version

You can use the special SYMFONY_REQUIRE environment variable together with Symfony Flex to install a specific Symfony version:

特別な SYMFONY_REQUIRE 環境変数を Symfony Flex と一緒に使用して、特定の Symfony バージョンをインストールできます。
1
2
3
4
5
6
7
8
9
10
11
12
# this requires Symfony 5.x for all Symfony packages
export SYMFONY_REQUIRE=5.*
# alternatively you can run this command to update composer.json config
# composer config extra.symfony.require "5.*"

# install Symfony Flex in the CI environment
composer global config --no-plugins allow-plugins.symfony/flex true
composer global require --no-progress --no-scripts --no-plugins symfony/flex

# install the dependencies (using --prefer-dist and --no-progress is
# recommended to have a better output and faster download time)
composer update --prefer-dist --no-progress

Caution

注意

If you want to cache your Composer dependencies, do not cache the vendor/ directory as this has side-effects. Instead cache $HOME/.composer/cache/files.

Composer の依存関係をキャッシュする場合は、vendor/ ディレクトリをキャッシュしないでください。これには副作用があります。代わりに cache$HOME/.composer/cache/files.

Installation

Bundles should set "type": "symfony-bundle" in their composer.json file. With this, Symfony Flex will be able to automatically enable your bundle when it's installed.

バンドルは composer.json ファイルで "type": "symfony-bundle" を設定する必要があります。これにより、Symfony Flex はインストール時にバンドルを自動的に有効にすることができます。

If your bundle requires any setup (e.g. configuration, new files, changes to .gitignore, etc), then you should create a Symfony Flex recipe.

バンドルに何らかの設定 (構成、新しいファイル、.gitignore への変更など) が必要な場合は、Symfony Flex レシピを作成する必要があります。

Documentation

All classes and functions must come with full PHPDoc.

すべてのクラスと関数には、完全な PHPDoc が付属している必要があります。

Extensive documentation should also be provided in the docs/ directory. The index file (for example docs/index.rst or docs/index.md) is the only mandatory file and must be the entry point for the documentation. The reStructuredText (rST) is the format used to render the documentation on the Symfony website.

広範なドキュメントも docs/directory で提供する必要があります。インデックス ファイル (docs/index.rst または docs/index.md など) は唯一の必須ファイルであり、ドキュメントのエントリポイントである必要があります。 ThereStructuredText (rST) は、Symfony Web サイトでドキュメントをレンダリングするために使用される形式です。

Installation Instructions

In order to ease the installation of third-party bundles, consider using the following standardized instructions in your README.md file.

サードパーティのバンドルのインストールを容易にするために、README.md ファイルで次の標準化された手順を使用することを検討してください。
  • Markdown
    マークダウン
  • RST
    RST
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
34
35
36
37
38
39
40
41
Installation
============

Make sure Composer is installed globally, as explained in the
[installation chapter](https://getcomposer.org/doc/00-intro.md)
of the Composer documentation.

Applications that use Symfony Flex
----------------------------------

Open a command console, enter your project directory and execute:

```console
$ composer require <package-name>
```

Applications that don't use Symfony Flex
----------------------------------------

### Step 1: Download the Bundle

Open a command console, enter your project directory and execute the
following command to download the latest stable version of this bundle:

```console
$ composer require <package-name>
```

### Step 2: Enable the Bundle

Then, enable the bundle by adding it to the list of registered bundles
in the `config/bundles.php` file of your project:

```php
// config/bundles.php

return [
    // ...
    <vendor>\<bundle-name>\<bundle-long-name>::class => ['all' => true],
];
```

The example above assumes that you are installing the latest stable version of the bundle, where you don't have to provide the package version number (e.g. composer require friendsofsymfony/user-bundle). If the installation instructions refer to some past bundle version or to some unstable version, include the version constraint (e.g. composer require friendsofsymfony/user-bundle "~2.0@dev").

上記の例では、パッケージのバージョン番号を提供する必要のないバンドルの最新の安定バージョンをインストールしていると想定しています (例: composer require friendsofsymfony/user-bundle)。インストール手順が過去のバンドル バージョンまたは不安定なバージョンに言及している場合は、バージョンの制約を含めます (例: composer require friendsofsymfony/user-bundle "~2.0@dev")。

Optionally, you can add more installation steps (Step 3, Step 4, etc.) to explain other required installation tasks, such as registering routes or dumping assets.

必要に応じて、さらにインストール手順 (手順 3、手順 4 など) を追加して、ルートの登録やアセットのダンプなど、他の必要なインストール タスクについて説明することができます。

Routing

If the bundle provides routes, they must be prefixed with the bundle alias. For example, if your bundle is called AcmeBlogBundle, all its routes must be prefixed with acme_blog_.

バンドルがルートを提供する場合、それらにはバンドル エイリアスをプレフィックスとして付ける必要があります。

Templates

If a bundle provides templates, they must use Twig. A bundle must not provide a main layout, except if it provides a full working application.

バンドルがテンプレートを提供する場合、Twig を使用する必要があります。バンドルは、完全に機能するアプリケーションを提供する場合を除き、メイン レイアウトを提供してはなりません。

Translation Files

If a bundle provides message translations, they must be defined in the XLIFF format; the domain should be named after the bundle name (acme_blog).

バンドルがメッセージ翻訳を提供する場合、XLIFF 形式で定義する必要があります。ドメインは、バンドル名 (acme_blog) にちなんで命名する必要があります。

A bundle must not override existing messages from another bundle.

バンドルは、別のバンドルからの既存のメッセージをオーバーライドしてはなりません。

Configuration

To provide more flexibility, a bundle can provide configurable settings by using the Symfony built-in mechanisms.

柔軟性を高めるために、バンドルは Symfony の組み込みメカニズムを使用して構成可能な設定を提供できます。

For simple configuration settings, rely on the default parameters entry of the Symfony configuration. Symfony parameters are simple key/value pairs; a value being any valid PHP value. Each parameter name should start with the bundle alias, though this is just a best-practice suggestion. The rest of the parameter name will use a period (.) to separate different parts (e.g. acme_blog.author.email).

単純な構成設定については、Symfony 構成のデフォルトのパラメーター エントリに依存します。 symfony のパラメーターは単純なキーと値のペアです。 avalue は任意の有効な PHP 値です。各パラメーター名はバンドル エイリアスで始まる必要がありますが、これはベスト プラクティスの提案にすぎません。パラメータ名の残りの部分では、ピリオド (.) を使用して異なる部分を区切ります (例: acme_blog.author.email)。

The end user can provide values in any configuration file:

エンド ユーザーは、任意の構成ファイルに値を指定できます。
  • YAML
    YAML
  • XML
    XML
  • PHP
    PHP
1
2
3
# config/services.yaml
parameters:
    acme_blog.author.email: 'fabien@example.com'

Retrieve the configuration parameters in your code from the container:

コンテナーからコード内の構成パラメーターを取得します。
1
$container->getParameter('acme_blog.author.email');

While this mechanism requires the least effort, you should consider using the more advanced semantic bundle configuration to make your configuration more robust.

このメカニズムは最小限の労力で済みますが、構成をより堅牢にするために、より高度なセマンティック バンドル構成の使用を検討する必要があります。

Versioning

Bundles must be versioned following the Semantic Versioning Standard.

バンドルは、セマンティック バージョニング標準に従ってバージョン管理する必要があります。

Services

If the bundle defines services, they must be prefixed with the bundle alias instead of using fully qualified class names like you do in your project services. For example, AcmeBlogBundle services must be prefixed with acme_blog. The reason is that bundles shouldn't rely on features such as service autowiring or autoconfiguration to not impose an overhead when compiling application services.

バンドルがサービスを定義する場合、projectservices で行うように完全修飾クラス名を使用する代わりに、バンドル エイリアスを接頭辞として付ける必要があります。たとえば、AcmeBlogBu​​ndle サービスには acme_blog というプレフィックスを付ける必要があります。その理由は、アプリケーション サービスをコンパイルするときにオーバーヘッドを課さないように、バンドルがサービスの自動配線や自動構成などの機能に依存してはならないからです。

In addition, services not meant to be used by the application directly, should be defined as private. For public services, aliases should be created from the interface/class to the service id. For example, in MonologBundle, an alias is created from Psr\Log\LoggerInterface to logger so that the LoggerInterface type-hint can be used for autowiring.

さらに、アプリケーションが直接使用することを意図していないサービスは、プライベートとして定義する必要があります。パブリック サービスの場合、インターフェイス/クラスからサービス ID へのエイリアスを作成する必要があります。たとえば、MonologBu​​ndle では、Psr\Log\LoggerInterface から logger へのエイリアスが作成されるため、LoggerInterface のタイプ ヒントをオートワイヤリングに使用できます。

Services should not use autowiring or autoconfiguration. Instead, all services should be defined explicitly.

サービスは自動配線または自動構成を使用しないでください。代わりに、すべてのサービスを明示的に定義する必要があります。

See also

こちらもご覧ください

You can learn much more about service loading in bundles reading this article: How to Load Service Configuration inside a Bundle.

この記事を読むと、バンドルでのサービスのロードについてさらに詳しく知ることができます: バンドル内でサービス構成をロードする方法。

Composer Metadata

The composer.json file should include at least the following metadata:

composer.json ファイルには、少なくとも次のメタデータが含まれている必要があります。
name
Consists of the vendor and the short bundle name. If you are releasing the bundle on your own instead of on behalf of a company, use your personal name (e.g. johnsmith/blog-bundle). Exclude the vendor name from the bundle short name and separate each word with a hyphen. For example: AcmeBlogBundle is transformed into blog-bundle and AcmeSocialConnectBundle is transformed into social-connect-bundle.
ベンダーと短いバンドル名で構成されます。会社を代表するのではなく、自分でバンドルをリリースする場合は、個人名 (例: johnsmith/blog-bundle) を使用してください。 bundleshort 名からベンダー名を除外し、各単語をハイフンで区切ります。例: AcmeBlogBu​​ndle は blog-bundle に変換され、AcmeSocialConnectBundle は social-connect-bundle に変換されます。
description
A brief explanation of the purpose of the bundle.
バンドルの目的の簡単な説明。
type
Use the symfony-bundle value.
symfony-bundle 値を使用します。
license
a string (or array of strings) with a valid license identifier, such as MIT.
MIT などの有効なライセンス識別子を含む文字列 (または文字列の配列)。
autoload

This information is used by Symfony to load the classes of the bundle. It's recommended to use the PSR-4 autoload standard: use the namespace as key, and the location of the bundle's main class (relative to composer.json) as value. As the main class is located in the src/ directory of the bundle:

この情報は、バンドルのクラスをロードするために Symfony によって使用されます。 PSR-4 autoload 標準を使用することをお勧めします。名前空間をキーとして使用し、バンドルのメイン クラスの場所 (composer.json からの相対位置) を値として使用します。メインクラスはバンドルの src/ ディレクトリにあるため:
1
2
3
4
5
6
7
8
9
10
11
12
{
    "autoload": {
        "psr-4": {
            "Acme\\BlogBundle\\": "src/"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "Acme\\BlogBundle\\Tests\\": "tests/"
        }
    }
}

In order to make it easier for developers to find your bundle, register it on Packagist, the official repository for Composer packages.

開発者がバンドルを見つけやすくするために、Composer パッケージの公式リポジトリである Packagist に登録してください。

Resources

If the bundle references any resources (config files, translation files, etc.), don't use physical paths (e.g. __DIR__/config/services.xml) but logical paths (e.g. @AcmeBlogBundle/config/services.xml).

バンドルがリソース (構成ファイル、翻訳ファイルなど) を参照する場合は、物理パス (例: __DIR__/config/services.xml) ではなく、論理パス (例: @AcmeBlogBu​​ndle/config/services.xml) を使用します。

The logical paths are required because of the bundle overriding mechanism that lets you override any resource/file of any bundle. See The HttpKernel Component for more details about transforming physical paths into logical paths.

任意のバンドルの任意のリソース/ファイルをオーバーライドできるバンドル オーバーライド メカニズムのために、論理パスが必要です。物理パスを論理パスに変換する方法の詳細については、HttpKernel コンポーネントを参照してください。

Beware that templates use a simplified version of the logical path shown above. For example, an index.html.twig template located in the templates/Default/ directory of the AcmeBlogBundle, is referenced as @AcmeBlog/Default/index.html.twig.

テンプレートは、上記の論理パスの単純化されたバージョンを使用することに注意してください。たとえば、AcmeBlogBu​​ndle の templates/Default/directory にある index.html.twig テンプレートは、@AcmeBlog/Default/index.html.twig として参照されます。

Learn more