The Symfony Framework Best Practices

This article describes the best practices for developing web applications with Symfony that fit the philosophy envisioned by the original Symfony creators.

この記事では、元の Symfony 作成者が思い描いた哲学に適合する、Symfony を使用して Web アプリケーションを開発するためのベスト プラクティスについて説明します。

If you don't agree with some of these recommendations, they might be a good starting point that you can then extend and fit to your specific needs. You can even ignore them completely and continue using your own best practices and methodologies. Symfony is flexible enough to adapt to your needs.

これらの推奨事項の一部に同意できない場合は、特定のニーズに合わせて拡張して適合させることができる出発点として適している可能性があります。それらを完全に無視して、独自のベスト プラクティスと方法論を引き続き使用することもできます。 symfony は、ニーズに適応するのに十分な柔軟性を備えています。

This article assumes that you already have experience developing Symfony applications. If you don't, read first the Getting Started section of the documentation.

この記事は、Symfony アプリケーションの開発経験があることを前提としています。そうでない場合は、最初にドキュメントの「はじめに」セクションをお読みください。

Tip

ヒント

Symfony provides a sample application called Symfony Demo that follows all these best practices, so you can experience them in practice.

Symfony は、これらすべてのベスト プラクティスに従う Symfony Demo と呼ばれるサンプル アプリケーションを提供しているため、実際にそれらを体験できます。

Creating the Project

Use the Symfony Binary to Create Symfony Applications

The Symfony binary is an executable command created in your machine when you download Symfony. It provides multiple utilities, including the simplest way to create new Symfony applications:

Symfony バイナリは、Symfony をダウンロードしたときにマシンに作成される実行可能なコマンドです。新しい Symfony アプリケーションを作成する最も簡単な方法を含む、複数のユーティリティを提供します。
1
$ symfony new my_project_directory

Under the hood, this Symfony binary command executes the needed Composer command to create a new Symfony application based on the current stable version.

内部的には、この Symfony バイナリ コマンドは必要な Composer コマンドを実行して、現在の安定バージョンに基づいて新しい Symfony アプリケーションを作成します。

Use the Default Directory Structure

Unless your project follows a development practice that imposes a certain directory structure, follow the default Symfony directory structure. It's flat, self-explanatory and not coupled to Symfony:

あなたのプロジェクトが特定のディレクトリ構造を強制する開発慣行に従わない限り、デフォルトの Symfony ディレクトリ構造に従ってください。それはフラットで自明であり、Symfony に結合されていません:
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
your_project/
├─ assets/
├─ bin/
│  └─ console
├─ config/
│  ├─ packages/
│  └─ services.yaml
├─ migrations/
├─ public/
│  ├─ build/
│  └─ index.php
├─ src/
│  ├─ Kernel.php
│  ├─ Command/
│  ├─ Controller/
│  ├─ DataFixtures/
│  ├─ Entity/
│  ├─ EventSubscriber/
│  ├─ Form/
│  ├─ Repository/
│  ├─ Security/
│  └─ Twig/
├─ templates/
├─ tests/
├─ translations/
├─ var/
│  ├─ cache/
│  └─ log/
└─ vendor/

Configuration

Use Environment Variables for Infrastructure Configuration

The values of these options change from one machine to another (e.g. from your development machine to the production server), but they don't modify the application behavior.

これらのオプションの値は、あるマシンから別のマシン (たとえば、開発マシンから実稼働サーバー) に変更されますが、アプリケーションの動作は変更されません。

Use env vars in your project to define these options and create multiple .env files to configure env vars per environment.

プロジェクトで環境変数を使用してこれらのオプションを定義し、複数の .env ファイルを作成して環境ごとに環境変数を構成します。

Use Secrets for Sensitive Information

When your application has sensitive configuration, like an API key, you should store those securely via Symfony’s secrets management system.

アプリケーションに API キーのような機密性の高い構成がある場合、Symfony のシークレット管理システムを介してそれらを安全に保管する必要があります。

Use Parameters for Application Configuration

These are the options used to modify the application behavior, such as the sender of email notifications, or the enabled feature toggles. Their value doesn't change per machine, so don't define them as environment variables.

これらは、電子メール通知の送信者や有効な機能の切り替えなど、アプリケーションの動作を変更するために使用されるオプションです。それらの値はマシンごとに変わらないため、環境変数として定義しないでください。

Define these options as parameters in the config/services.yaml file. You can override these options per environment in the config/services_dev.yaml and config/services_prod.yaml files.

config/services.yaml ファイルでこれらのオプションをパラメーターとして定義します。これらのオプションは、config/services_dev.yam および config/services_prod.yaml ファイルで環境ごとにオーバーライドできます。

Use Short and Prefixed Parameter Names

Consider using app. as the prefix of your parameters to avoid collisions with Symfony and third-party bundles/libraries parameters. Then, use just one or two words to describe the purpose of the parameter:

アプリの使用を検討してください。パラメータのプレフィックスとして、Symfony およびサードパーティのバンドル/ライブラリ パラメータとの衝突を回避します。次に、1 つまたは 2 つの単語を使用して、パラメータの目的を説明します。
1
2
3
4
5
6
7
8
9
10
# config/services.yaml
parameters:
    # don't do this: 'dir' is too generic, and it doesn't convey any meaning
    app.dir: '...'
    # do this: short but easy to understand names
    app.contents_dir: '...'
    # it's OK to use dots, underscores, dashes or nothing, but always
    # be consistent and use the same format for all the parameters
    app.dir.contents: '...'
    app.contents-dir: '...'

Use Constants to Define Options that Rarely Change

Configuration options like the number of items to display in some listing rarely change. Instead of defining them as configuration parameters, define them as PHP constants in the related classes. Example:

一部のリストに表示するアイテムの数などの構成オプションはほとんど変更されません。それらを構成パラメーターとして定義する代わりに、関連するクラスで PHP 定数として定義します。例:
1
2
3
4
5
6
7
8
9
// src/Entity/Post.php
namespace App\Entity;

class Post
{
    public const NUMBER_OF_ITEMS = 10;

    // ...
}

The main advantage of constants is that you can use them everywhere, including Twig templates and Doctrine entities, whereas parameters are only available from places with access to the service container.

定数の主な利点は、Twig テンプレートや Doctrine エンティティを含むあらゆる場所で定数を使用できることですが、パラメーターはサービス コンテナーにアクセスできる場所からのみ使用できます。

The only notable disadvantage of using constants for this kind of configuration values is that it's complicated to redefine their values in your tests.

この種の構成値に定数を使用することの唯一の顕著な欠点は、テストで値を再定義するのが複雑であることです。

Business Logic

Don't Create any Bundle to Organize your Application Logic

When Symfony 2.0 was released, applications used bundles to divide their code into logical features: UserBundle, ProductBundle, InvoiceBundle, etc. However, a bundle is meant to be something that can be reused as a stand-alone piece of software.

Symfony 2.0 がリリースされたとき、アプリケーションはバンドルを使用してコードを論理機能 (UserBundle、ProductBundle、InvoiceBundle など) に分割しました。ただし、バンドルはスタンドアロンのソフトウェアとして再利用できるものを意味します。

If you need to reuse some feature in your projects, create a bundle for it (in a private repository, do not make it publicly available). For the rest of your application code, use PHP namespaces to organize code instead of bundles.

プロジェクトで一部の機能を再利用する必要がある場合は、そのバンドルを作成します (プライベート リポジトリでは、公開しないでください)。アプリケーション コードの残りの部分については、バンドルの代わりに PHP 名前空間を使用してコードを整理します。

Use Autowiring to Automate the Configuration of Application Services

Service autowiring is a feature that reads the type-hints on your constructor (or other methods) and automatically passes the correct services to each method, making it unnecessary to configure services explicitly and simplifying the application maintenance.

サービスの自動配線は、コンストラクター (または他のメソッド) の型ヒントを読み取り、正しいサービスを各メソッドに自動的に渡す機能です。これにより、サービスを明示的に構成する必要がなくなり、アプリケーションのメンテナンスが簡素化されます。

Use it in combination with service autoconfiguration to also add service tags to the services needing them, such as Twig extensions, event subscribers, etc.

サービスの自動構成と組み合わせて使用​​し、Twig 拡張機能、イベント サブスクライバーなど、必要なサービスにサービス タグを追加します。

Services Should be Private Whenever Possible

Make services private to prevent you from accessing those services via $container->get(). Instead, you will need to use proper dependency injection.

サービスを非公開にして、$container->get() 経由でこれらのサービスにアクセスできないようにします。代わりに、適切な依存性注入を使用する必要があります。

Use the YAML Format to Configure your own Services

If you use the default services.yaml configuration, most services will be configured automatically. However, in some edge cases you'll need to configure services (or parts of them) manually.

デフォルトの services.yaml 構成を使用すると、ほとんどのサービスが自動的に構成されます。ただし、一部のエッジ ケースでは、サービス (ま​​たはその一部) を手動で構成する必要があります。

YAML is the format recommended configuring services because it's friendly to newcomers and concise, but Symfony also supports XML and PHP configuration.

YAML は初心者にやさしく簡潔なので、サービスを構成する際に推奨される形式ですが、Symfony は XML と PHP の構成もサポートしています。

Use Attributes to Define the Doctrine Entity Mapping

Doctrine entities are plain PHP objects that you store in some "database". Doctrine only knows about your entities through the mapping metadata configured for your model classes.

Doctrine エンティティは、いくつかの「データベース」に保存するプレーンな PHP オブジェクトです。Doctrine は、モデル クラス用に構成されたマッピング メタデータを通じてエンティティについてのみ認識します。

Doctrine supports several metadata formats, but it's recommended to use PHP attributes because they are by far the most convenient and agile way of setting up and looking for mapping information.

Doctrine はいくつかのメタデータ形式をサポートしていますが、PHPattributes を使用することをお勧めします。これは、マッピング情報をセットアップして検索する最も便利で機敏な方法だからです。

If your PHP version doesn't support attributes yet, use annotations, which is similar but requires installing some extra dependencies in your project.

PHP バージョンがまだ属性をサポートしていない場合は、アノテーションを使用します。これは似ていますが、プロジェクトに追加の依存関係をインストールする必要があります。

Controllers

Make your Controller Extend the AbstractController Base Controller

Symfony provides a base controller which includes shortcuts for the most common needs such as rendering templates or checking security permissions.

Symfony は、テンプレートのレンダリングやセキュリティ権限のチェックなど、最も一般的なニーズに対するショートカットを含む基本コントローラーを提供します。

Extending your controllers from this base controller couples your application to Symfony. Coupling is generally wrong, but it may be OK in this case because controllers shouldn't contain any business logic. Controllers should contain nothing more than a few lines of glue-code, so you are not coupling the important parts of your application.

このベースコントローラーからコントローラーを拡張すると、アプリケーションが Symfony に結合されます。カップリングは一般的に間違っていますが、この場合は問題ないかもしれません。なぜなら、コントローラーにはビジネス ロジックを含めるべきではないからです。コントローラーには、数行のグルー コードのみを含める必要があるため、アプリケーションの重要な部分を結合することはありません。

Use Attributes or Annotations to Configure Routing, Caching, and Security

Using attributes or annotations for routing, caching, and security simplifies configuration. You don't need to browse several files created with different formats (YAML, XML, PHP): all the configuration is just where you require it, and it only uses one format.

ルーティング、キャッシング、およびセキュリティに属性または注釈を使用すると、構成が簡素化されます。異なる形式 (YAML、XML、PHP) で作成された複数のファイルを参照する必要はありません。すべての構成は必要な場所にあり、1 つの形式のみを使用します。

Use Dependency Injection to Get Services

If you extend the base AbstractController, you can only get access to the most common services (e.g twig, router, doctrine, etc.), directly from the container via $this->container->get(). Instead, you must use dependency injection to fetch services by type-hinting action method arguments or constructor arguments.

ベースの AbstractController を拡張すると、$this->container->get() を介してコンテナから直接、最も一般的なサービス (twig、router、doctrine など) にのみアクセスできます。代わりに、依存性注入を使用する必要があります。タイプヒントアクションメソッドの引数またはコンストラクターの引数によってサービスを取得します。

Use Entity Value Resolvers If They Are Convenient

If you're using Doctrine, then you can optionally use the EntityValueResolver to automatically query for an entity and pass it as an argument to your controller. It will also show a 404 page if no entity can be found.

Doctrine を使用している場合は、必要に応じて EntityValueResolver を使用してエンティティを自動的にクエリし、それを引数としてコントローラーに渡すことができます。エンティティが見つからない場合は、404 ページも表示されます。

If the logic to get an entity from a route variable is more complex, instead of configuring the EntityValueResolver, it's better to make the Doctrine query inside the controller (e.g. by calling to a Doctrine repository method).

ルート変数からエンティティを取得するロジックがより複雑な場合は、EntityValueResolver を構成する代わりに、コントローラー内で Doctrine クエリを作成することをお勧めします (たとえば、Doctrine リポジトリ メソッドを呼び出すことによって)。

Templates

Use Snake Case for Template Names and Variables

Use lowercase snake_case for template names, directories, and variables (e.g. user_profile instead of userProfile and product/edit_form.html.twig instead of Product/EditForm.html.twig).

テンプレート名、ディレクトリ、および変数には小文字の snake_case を使用します (たとえば、userProfile の代わりに user_profile を使用し、Product/EditForm.html.twig の代わりに product/edit_form.html.twigin を使用します)。

Prefix Template Fragments with an Underscore

Template fragments, also called "partial templates", allow to reuse template contents. Prefix their names with an underscore to better differentiate them from complete templates (e.g. _user_metadata.html.twig or _caution_message.html.twig).

「部分テンプレート」とも呼ばれるテンプレート フラグメントを使用すると、テンプレートの内容を再利用できます。完全なテンプレート (例: _user_metadata.html.twig または _caution_message.html.twig) と区別しやすくするために、名前の前にアンダースコアを付けます。

Forms

Define your Forms as PHP Classes

Creating forms in classes allows reusing them in different parts of the application. Besides, not creating forms in controllers simplifies the code and maintenance of the controllers.

クラスでフォームを作成すると、アプリケーションのさまざまな部分でフォームを再利用できます。さらに、コントローラでフォームを作成しないことで、コントローラのコードとメンテナンスが簡素化されます。

Add Form Buttons in Templates

Form classes should be agnostic to where they will be used. For example, the button of a form used to both create and edit items should change from "Add new" to "Save changes" depending on where it's used.

フォーム クラスは、どこで使用されるかにとらわれないようにする必要があります。たとえば、アイテムの作成と編集の両方に使用されるフォームのボタンは、使用場所に応じて「新規追加」から「変更の保存」に変更する必要があります。

Instead of adding buttons in form classes or the controllers, it's recommended to add buttons in the templates. This also improves the separation of concerns because the button styling (CSS class and other attributes) is defined in the template instead of in a PHP class.

フォーム クラスまたはコントローラーにボタンを追加する代わりに、テンプレートにボタンを追加することをお勧めします。ボタンのスタイル (CSS クラスおよびその他の属性) が PHP クラスではなくテンプレートで定義されるため、これにより関心の分離も改善されます。

However, if you create a form with multiple submit buttons you should define them in the controller instead of the template. Otherwise, you won't be able to check which button was clicked when handling the form in the controller.

ただし、複数の送信ボタンを含むフォームを作成する場合は、テンプレートではなくコントローラーで定義する必要があります。そうしないと、コントローラーでフォームを処理するときにどのボタンがクリックされたかを確認できません。

Define Validation Constraints on the Underlying Object

Attaching validation constraints to form fields instead of to the mapped object prevents the validation from being reused in other forms or other places where the object is used.

マップされたオブジェクトではなくフォーム フィールドに検証制約をアタッチすると、オブジェクトが使用される別のフォームや場所で検証が再利用されるのを防ぐことができます。

Use a Single Action to Render and Process the Form

Rendering forms and processing forms are two of the main tasks when handling forms. Both are too similar (most of the time, almost identical), so it's much simpler to let a single controller action handle both.

フォームのレンダリングとフォームの処理は、フォームを処理する際の 2 つの主要なタスクです。どちらもあまりにも似ている (ほとんどの場合、ほぼ同じ) ため、1 つのコントローラー アクションで両方を処理できるようにする方がはるかに簡単です。

Internationalization

Use the XLIFF Format for Your Translation Files

Of all the translation formats supported by Symfony (PHP, Qt, .po, .mo, JSON, CSV, INI, etc.), XLIFF and gettext have the best support in the tools used by professional translators. And since it's based on XML, you can validate XLIFF file contents as you write them.

Symfony でサポートされているすべての翻訳形式 (PHP、Qt、.po、.mo、JSON、CSV、INI など) の中で、XLIFF と gettext は、プロの翻訳者が使用するツールで最もよくサポートされています。また、XML に基づいているため、XLIFFfile の内容を記述しながら検証できます。

Symfony also supports notes in XLIFF files, making them more user-friendly for translators. At the end, good translations are all about context, and these XLIFF notes allow you to define that context.

symfony は XLIFF ファイルのメモもサポートしているため、翻訳者にとってより使いやすくなっています。最後に、優れた翻訳はすべてコンテキストに関するものであり、これらの XLIFF ノートを使用すると、そのコンテキストを定義できます。

Use Keys for Translations Instead of Content Strings

Using keys simplifies the management of the translation files because you can change the original contents in templates, controllers, and services without having to update all the translation files.

キーを使用すると、すべての翻訳ファイルを更新しなくても、テンプレート、コントローラ、およびサービスの元のコンテンツを変更できるため、翻訳ファイルの管理が簡素化されます。

Keys should always describe their purpose and not their location. For example, if a form has a field with the label "Username", then a nice key would be label.username, not edit_form.label.username.

キーは、その場所ではなく、常にその目的を説明する必要があります。たとえば、フォームに「Username」というラベルのフィールドがある場合、適切なキーは、edit_form.label.username ではなく、label.username になります。

Security

Define a Single Firewall

Unless you have two legitimately different authentication systems and users (e.g. form login for the main site and a token system for your API only), it's recommended to have only one firewall to keep things simple.

正当に異なる 2 つの認証システムとユーザー (たとえば、メイン サイトのフォーム ログインと API のみのトークン システム) を使用していない限り、単純にするためにファイアウォールを 1 つだけにすることをお勧めします。

Additionally, you should use the anonymous key under your firewall. If you require users to be logged in for different sections of your site, use the access_control option.

さらに、ファイアウォールの下で匿名キーを使用する必要があります。サイトのさまざまなセクションにユーザーがログインする必要がある場合は、access_control オプションを使用します。

Use the auto Password Hasher

The auto password hasher automatically selects the best possible encoder/hasher depending on your PHP installation. Currently, the default auto hasher is bcrypt.

自動パスワード ハッシャーは、PHP のインストール状況に応じて、最適なエンコーダー/ハッシャーを自動的に選択します。現在、デフォルトの自動ハッシャーは bcrypt です。

Use Voters to Implement Fine-grained Security Restrictions

If your security logic is complex, you should create custom security voters instead of defining long expressions inside the #[Security] attribute.

セキュリティ ロジックが複雑な場合は、#[Security] 属性内で長い式を定義する代わりに、カスタム セキュリティ ボーターを作成する必要があります。

Web Assets

Use Webpack Encore to Process Web Assets

Web assets are things like CSS, JavaScript, and image files that make the frontend of your site look and work great. Webpack is the leading JavaScript module bundler that compiles, transforms and packages assets for usage in a browser.

Web アセットとは、CSS、JavaScript、画像ファイルなど、サイトのフロントエンドの見栄えや機能を向上させるものです。 Webpack は、ブラウザーで使用できるようにアセットをコンパイル、変換、およびパッケージ化する主要な JavaScript モジュール バンドラーです。

Webpack Encore is a JavaScript library that gets rid of most of Webpack complexity without hiding any of its features or distorting its usage and philosophy. It was created for Symfony applications, but it works for any application using any technology.

Webpack Encore は、Webpack の複雑さのほとんどを取り除く JavaScript ライブラリであり、その機能を隠したり、使用法や哲学を歪めたりすることはありません。これは Symfony アプリケーション用に作成されましたが、あらゆるテクノロジーを使用するあらゆるアプリケーションで機能します。

Tests

Smoke Test your URLs

In software engineering, smoke testing consists of "preliminary testing to reveal simple failures severe enough to reject a prospective software release". Using PHPUnit data providers you can define a functional test that checks that all application URLs load successfully:

ソフトウェア エンジニアリングでは、スモーク テストは「将来のソフトウェア リリースを拒否するほど重大な単純な障害を明らかにするための予備テスト」で構成されます。 PHPUnit データ プロバイダーを使用すると、すべてのアプリケーション URL が正常に読み込まれることを確認する機能テストを定義できます。
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
// tests/ApplicationAvailabilityFunctionalTest.php
namespace App\Tests;

use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;

class ApplicationAvailabilityFunctionalTest extends WebTestCase
{
    /**
     * @dataProvider urlProvider
     */
    public function testPageIsSuccessful($url)
    {
        $client = self::createClient();
        $client->request('GET', $url);

        $this->assertResponseIsSuccessful();
    }

    public function urlProvider()
    {
        yield ['/'];
        yield ['/posts'];
        yield ['/post/fixture-post-1'];
        yield ['/blog/category/fixture-category'];
        yield ['/archives'];
        // ...
    }
}

Add this test while creating your application because it requires little effort and checks that none of your pages returns an error. Later, you'll add more specific tests for each page.

アプリケーションの作成中にこのテストを追加します。これは、ほとんど労力を必要とせず、どのページもエラーを返さないことを確認するためです。後で、各ページにより具体的なテストを追加します。

Hard-code URLs in a Functional Test

In Symfony applications, it's recommended to generate URLs using routes to automatically update all links when a URL changes. However, if a public URL changes, users won't be able to browse it unless you set up a redirection to the new URL.

Symfony アプリケーションでは、ルートを使用して URL を生成し、URL が変更されたときにすべてのリンクを自動的に更新することをお勧めします。ただし、パブリック URL が変更された場合、新しい URL へのリダイレクトを設定しない限り、ユーザーはその URL を参照できません。

That's why it's recommended to use raw URLs in tests instead of generating them from routes. Whenever a route changes, tests will fail, and you'll know that you must set up a redirection.

そのため、ルートから URL を生成するのではなく、生の URL をテストで使用することをお勧めします。ルートが変更されるたびに、テストは失敗し、リダイレクトを設定する必要があることがわかります。