The Architecture

You are my hero! Who would have thought that you would still be here after the first two parts? Your efforts will be well-rewarded soon. The first two parts didn't look too deeply at the architecture of the framework. Because it makes Symfony stand apart from the framework crowd, let's dive into the architecture now.

あなたは私のヒーローです!最初の2つの部分の後、あなたがまだここにいると誰が思ったでしょうか?あなたの努力はすぐに報われます。最初の 2 つの部分では、フレームワークのアーキテクチャについてあまり詳しく説明しませんでした。 Symfony をフレームワーク群とは一線を画すものにしているので、ここでアーキテクチャーに飛び込みましょう。

Add Logging

A new Symfony app is micro: it's basically just a routing & controller system. But thanks to Flex, installing more features is simple.

新しい Symfony アプリはマイクロです。基本的には単なるルーティングとコントローラー システムです。しかし、Flex のおかげで、より多くの機能を簡単にインストールできます。

Want a logging system? No problem:

ロギングシステムが必要ですか?問題ない:
1
$ composer require logger

This installs and configures (via a recipe) the powerful Monolog library. To use the logger in a controller, add a new argument type-hinted with LoggerInterface:

これにより、(レシピを介して) 強力な Monolog ライブラリがインストールおよび構成されます。コントローラーでロガーを使用するには、LoggerInterface で型ヒントされた新しい引数を追加します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
// src/Controller/DefaultController.php
namespace App\Controller;

use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

class DefaultController extends AbstractController
{
    #[Route('/hello/{name}', methods: ['GET'])]
    public function index(string $name, LoggerInterface $logger): Response
    {
        $logger->info("Saying hello to $name!");

        // ...
    }
}

That's it! The new log message will be written to var/log/dev.log. The log file path or even a different method of logging can be configured by updating one of the config files added by the recipe.

それでおしまい!新しいログ メッセージは var/log/dev.log に書き込まれます。レシピによって追加された設定ファイルの 1 つを更新することで、ログファイルのパスや別のロギング方法を設定できます。

Services & Autowiring

But wait! Something very cool just happened. Symfony read the LoggerInterface type-hint and automatically figured out that it should pass us the Logger object! This is called autowiring.

ちょっと待って!とてもクールなことが起こりました。 symfony は LoggerInterfacetype-hint を読み取り、Logger オブジェクトを渡す必要があることを自動的に判断しました!これはオートワイヤーと呼ばれます。

Every bit of work that's done in a Symfony app is done by an object: the Logger object logs things and the Twig object renders templates. These objects are called services and they are tools that help you build rich features.

Symfony アプリで行われるすべての作業は、オブジェクトによって行われます。Logger オブジェクトはログを記録し、Twig オブジェクトはテンプレートをレンダリングします。これらのオブジェクトはサービスと呼ばれ、豊富な機能を構築するのに役立つツールです。

To make life awesome, you can ask Symfony to pass you a service by using a type-hint. What other possible classes or interfaces could you use? Find out by running:

生活を素晴らしいものにするために、Symfony に型ヒントを使用してサービスを渡すように依頼できます。他にどのようなクラスまたはインターフェースを使用できますか?次を実行して確認します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ php bin/console debug:autowiring

  # this is just a *small* sample of the output...

  Describes a logger instance.
  Psr\Log\LoggerInterface (monolog.logger)

  Request stack that controls the lifecycle of requests.
  Symfony\Component\HttpFoundation\RequestStack (request_stack)

  RouterInterface is the interface that all Router classes must implement.
  Symfony\Component\Routing\RouterInterface (router.default)

  [...]

This is just a short summary of the full list! And as you add more packages, this list of tools will grow!

これは、完全なリストの簡単な要約です。さらにパッケージを追加すると、このツールのリストは大きくなります!

Creating Services

To keep your code organized, you can even create your own services! Suppose you want to generate a random greeting (e.g. "Hello", "Yo", etc). Instead of putting this code directly in your controller, create a new class:

コードを整理しておくために、独自のサービスを作成することもできます!ランダムな挨拶 (「こんにちは」、「よ」など) を生成するとします。このコードをコントローラーに直接配置する代わりに、新しいクラスを作成します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
// src/GreetingGenerator.php
namespace App;

class GreetingGenerator
{
    public function getRandomGreeting(): string
    {
        $greetings = ['Hey', 'Yo', 'Aloha'];
        $greeting = $greetings[array_rand($greetings)];

        return $greeting;
    }
}

Great! You can use it immediately in your controller:

すごい!コントローラーですぐに使用できます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
// src/Controller/DefaultController.php
namespace App\Controller;

use App\GreetingGenerator;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

class DefaultController extends AbstractController
{
    #[Route('/hello/{name}', methods: ['GET'])]
    public function index(string $name, LoggerInterface $logger, GreetingGenerator $generator): Response
    {
        $greeting = $generator->getRandomGreeting();

        $logger->info("Saying $greeting to $name!");

        // ...
    }
}

That's it! Symfony will instantiate the GreetingGenerator automatically and pass it as an argument. But, could we also move the logger logic to GreetingGenerator? Yes! You can use autowiring inside a service to access other services. The only difference is that it's done in the constructor:

それでおしまい! symfony は GreetingGenerator を自動的にインスタンス化し、それを引数として渡します。しかし、ロガー ロジックを GreetingGenerator に移動することもできますか?はい!サービス内で自動配線を使用して、他のサービスにアクセスできます。唯一の違いは、コンストラクターで行われることです。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
  // src/GreetingGenerator.php
+ use Psr\Log\LoggerInterface;

  class GreetingGenerator
  {
+     public function __construct(private readonly LoggerInterface $logger)
+     {
+     }

      public function getRandomGreeting(): string
      {
          // ...

+        $this->logger->info('Using the greeting: '.$greeting);

           return $greeting;
      }
  }

Yes! This works too: no configuration, no time wasted. Keep coding!

はい!これもうまくいきます: 構成も時間の無駄もありません。コーディングを続けてください!

Twig Extension & Autoconfiguration

Thanks to Symfony's service handling, you can extend Symfony in many ways, like by creating an event subscriber or a security voter for complex authorization rules. Let's add a new filter to Twig called greet. How? Create a class that extends AbstractExtension:

Symfony のサービス処理のおかげで、イベント サブスクライバーや複雑な承認ルール用のセキュリティ ボーターを作成するなど、さまざまな方法で Symfony を拡張できます。挨拶と呼ばれる新しいフィルターを Twig に追加しましょう。どのように? AbstractExtension を拡張するクラスを作成します。
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
<?php
// src/Twig/GreetExtension.php
namespace App\Twig;

use App\GreetingGenerator;
use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;

class GreetExtension extends AbstractExtension
{
    public function __construct(private readonly GreetingGenerator $greetingGenerator)
    {
    }

    public function getFilters()
    {
        return [
            new TwigFilter('greet', [$this, 'greetUser']),
        ];
    }

    public function greetUser(string $name): string
    {
        $greeting =  $this->greetingGenerator->getRandomGreeting();

        return "$greeting $name!";
    }
}

After creating just one file, you can use this immediately:

ファイルを 1 つだけ作成したら、すぐに使用できます。
1
2
3
{# templates/default/index.html.twig #}
{# Will print something like "Hey Symfony!" #}
<h1>{{ name|greet }}</h1>

How does this work? Symfony notices that your class extends AbstractExtension and so automatically registers it as a Twig extension. This is called autoconfiguration, and it works for many many things. Create a class and then extend a base class (or implement an interface). Symfony takes care of the rest.

これはどのように作動しますか? symfony は、あなたのクラスが AbstractExtension を拡張していることに気づき、自動的にそれを Twig 拡張として登録します。これは自動構成と呼ばれ、多くの場合に機能します。クラスを作成してから、基本クラスを拡張します (またはインターフェイスを実装します)。 symfony が残りを処理します。

Blazing Speed: The Cached Container

After seeing how much Symfony handles automatically, you might be wondering: "Doesn't this hurt performance?" Actually, no! Symfony is blazing fast.

Symfony が自動的に処理する量を見た後、「これはパフォーマンスに悪影響を与えませんか?」と疑問に思うかもしれません。実は違う! symfony は非常に高速です。

How is that possible? The service system is managed by a very important object called the "container". Most frameworks have a container, but Symfony's is unique because it's cached. When you loaded your first page, all of the service information was compiled and saved. This means that the autowiring and autoconfiguration features add no overhead! It also means that you get great errors: Symfony inspects and validates everything when the container is built.

そんなことがあるものか?サービスシステムは、「コンテナ」と呼ばれる非常に重要なオブジェクトによって管理されます。ほとんどのフレームワークにはコンテナがありますが、Symfony のものはキャッシュされているためユニークです。最初のページを読み込んだときに、すべてのサービス情報がコンパイルされて保存されました。これは、自動配線および自動構成機能がオーバーヘッドを追加しないことを意味します!また、大きなエラーが発生することも意味します: Symfony は、コンテナーのビルド時にすべてを検査して検証します。

Now you might be wondering what happens when you update a file and the cache needs to rebuild? I like your thinking! It's smart enough to rebuild on the next page load. But that's really the topic of the next section.

ファイルを更新してキャッシュを再構築する必要がある場合はどうなるのだろうと思っているかもしれません。私はあなたの考えが好きです!次のページロードで再構築するのに十分スマートです。しかし、それは実際には次のセクションのトピックです。

Development Versus Production: Environments

One of a framework's main jobs is to make debugging easy! And our app is full of great tools for this: the web debug toolbar displays at the bottom of the page, errors are big, beautiful & explicit, and any configuration cache is automatically rebuilt whenever needed.

フレームワークの主な仕事の 1 つは、デバッグを容易にすることです。そして、私たちのアプリには、このための優れたツールがたくさんあります。ウェブ デバッグ ツールバーはページの下部に表示され、エラーは大きく、美しく明確であり、構成キャッシュは必要に応じて自動的に再構築されます。

But what about when you deploy to production? We will need to hide those tools and optimize for speed!

しかし、本番環境にデプロイする場合はどうでしょうか?これらのツールを非表示にして、速度を最適化する必要があります。

This is solved by Symfony's environment system and there are three: dev, prod and test. Based on the environment, Symfony loads different files in the config/ directory:

これは Symfony の環境システムによって解決され、dev、prod、test の 3 つがあります。環境に基づいて、Symfony は config/directory にさまざまなファイルをロードします。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
config/
├─ services.yaml
├─ ...
└─ packages/
    ├─ framework.yaml
    ├─ ...
    ├─ **dev/**
        ├─ monolog.yaml
        └─ ...
    ├─ **prod/**
        └─ monolog.yaml
    └─ **test/**
        ├─ framework.yaml
        └─ ...
└─ routes/
    ├─ annotations.yaml
    └─ **dev/**
        ├─ twig.yaml
        └─ web_profiler.yaml

This is a powerful idea: by changing one piece of configuration (the environment), your app is transformed from a debugging-friendly experience to one that's optimized for speed.

これは強力なアイデアです。構成の一部 (環境) を変更することで、アプリはデバッグしやすいエクスペリエンスから、速度が最適化されたエクスペリエンスに変わります。

Oh, how do you change the environment? Change the APP_ENV environment variable from dev to prod:

ああ、どうやって環境を変えるの? APP_ENV 環境変数を dev から prod に変更します。
1
2
3
# .env
- APP_ENV=dev
+ APP_ENV=prod

But I want to talk more about environment variables next. Change the value back to dev: debugging tools are great when you're working locally.

しかし、次は環境変数についてもっと話したいと思います。値を dev に戻します。デバッグ ツールは、ローカルで作業している場合に最適です。

Environment Variables

Every app contains configuration that's different on each server - like database connection information or passwords. How should these be stored? In files? Or another way?

すべてのアプリには、データベース接続情報やパスワードなど、サーバーごとに異なる構成が含まれています。これらはどのように保管すればよいですか?ファイルで?それとも別の方法ですか?

Symfony follows the industry best practice by storing server-based configuration as environment variables. This means that Symfony works perfectly with Platform as a Service (PaaS) deployment systems as well as Docker.

symfony は、サーバーベースの構成を環境変数として保存することで、業界のベスト プラクティスに従います。これは、Symfony がプラットフォームとしてのサービス (PaaS) 展開システムや Docker と完全に連携することを意味します。

But setting environment variables while developing can be a pain. That's why your app automatically loads a .env file. The keys in this file then become environment variables and are read by your app:

しかし、開発中に環境変数を設定するのは面倒です。そのため、yourapp は自動的に .env ファイルをロードします。このファイルのキーは環境変数になり、アプリによって読み取られます。
1
2
3
4
5
# .env
###> symfony/framework-bundle ###
APP_ENV=dev
APP_SECRET=cc86c7ca937636d5ddf1b754beb22a10
###< symfony/framework-bundle ###

At first, the file doesn't contain much. But as your app grows, you'll add more configuration as you need it. But, actually, it gets much more interesting! Suppose your app needs a database ORM. Let's install the Doctrine ORM:

最初は、ファイルにはあま​​り含まれていません。ただし、アプリが成長するにつれて、必要に応じて構成を追加します。しかし、実際には、もっと面白くなります!アプリにデータベース ORM が必要だとします。 Doctrine ORM をインストールしましょう:
1
$ composer require doctrine

Thanks to a new recipe installed by Flex, look at the .env file again:

Flex によってインストールされた新しいレシピのおかげで、.env ファイルをもう一度見てください。
1
2
3
4
5
6
7
8
9
###> symfony/framework-bundle ###
  APP_ENV=dev
  APP_SECRET=cc86c7ca937636d5ddf1b754beb22a10
  ###< symfony/framework-bundle ###

+ ###> doctrine/doctrine-bundle ###
+ # ...
+ DATABASE_URL=mysql://db_user:db_password@127.0.0.1:3306/db_name
+ ###< doctrine/doctrine-bundle ###

The new DATABASE_URL environment variable was added automatically and is already referenced by the new doctrine.yaml configuration file. By combining environment variables and Flex, you're using industry best practices without any extra effort.

新しい DATABASE_URL 環境変数が自動的に追加され、新しい doctrine.yaml 構成ファイルによって既に参照されています。環境変数と Flex を組み合わせることで、余計な労力をかけずに業界のベスト プラクティスを使用できます。

Keep Going!

Call me crazy, but after reading this part, you should be comfortable with the most important parts of Symfony. Everything in Symfony is designed to get out of your way so you can keep coding and adding features, all with the speed and quality you demand.

頭がおかしいと言うかもしれませんが、この部分を読んだ後は、Symfony の最も重要な部分に慣れているはずです。 Symfony のすべてが邪魔にならないように設計されているため、必要な速度と品質でコーディングを続けたり、機能を追加したりできます。

That's all for the quick tour. From authentication, to forms, to caching, there is so much more to discover. Ready to dig into these topics now? Look no further - go to the official Symfony Documentation and pick any guide you want.

クイック ツアーは以上です。認証からフォーム、キャッシングまで、発見すべきことがたくさんあります。これらのトピックを掘り下げる準備はできましたか?もう探す必要はありません。Symfony の公式ドキュメントにアクセスして、必要なガイドを選択してください。