Symfony versus Flat PHP

Why is Symfony better than just opening up a file and writing flat PHP?

ファイルを開いてフラットな PHP を書くよりも Symfony の方が優れているのはなぜですか?

If you've never used a PHP framework, aren't familiar with the Model-View-Controller (MVC) philosophy, or just wonder what all the hype is around Symfony, this article is for you. Instead of telling you that Symfony allows you to develop faster and better software than with flat PHP, you'll see for yourself.

PHP フレームワークを使用したことがない場合、Model-View-Controller (MVC) の哲学に慣れていない場合、または単に Symfony をめぐる誇大広告について疑問に思っている場合、この記事はあなたのためのものです。 Symfony を使用すると、フラットな PHP よりも高速で優れたソフトウェアを開発できると説明する代わりに、自分の目で確かめてください。

In this article, you'll write a basic application in flat PHP, and then refactor it to be more organized. You'll travel through time, seeing the decisions behind why web development has evolved over the past several years to where it is now.

この記事では、フラットな PHP で基本的なアプリケーションを作成し、それをリファクタリングしてより整理します。過去数年間で Web 開発が進化し、現在の状況に至った理由の背後にある決定を見て、時間を旅します。

By the end, you'll see how Symfony can rescue you from mundane tasks and let you take back control of your code.

最終的には、Symfony がどのようにありふれたタスクからあなたを救出し、コードの制御を取り戻すことができるかがわかります。

A Basic Blog in Flat PHP

In this article, you'll build the token blog application using only flat PHP. To begin, create a single page that displays blog entries that have been persisted to the database. Writing in flat PHP is quick and dirty:

この記事では、フラット PHP のみを使用してトークン ブログ アプリケーションを作成します。まず、データベースに保持されているブログ エントリを表示する単一のページを作成します。フラットな PHP で書くのは手っ取り早くて汚い:
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
<?php
// index.php
$connection = new PDO("mysql:host=localhost;dbname=blog_db", 'myuser', 'mypassword');

$result = $connection->query('SELECT id, title FROM post');
?>

<!DOCTYPE html>
<html>
    <head>
        <title>List of Posts</title>
    </head>
    <body>
        <h1>List of Posts</h1>
        <ul>
            <?php while ($row = $result->fetch(PDO::FETCH_ASSOC)): ?>
            <li>
                <a href="/show.php?id=<?= $row['id'] ?>">
                    <?= $row['title'] ?>
                </a>
            </li>
            <?php endwhile ?>
        </ul>
    </body>
</html>

<?php
$connection = null;
?>

That's quick to write, fast to deploy and run, and, as your app grows, impossible to maintain. There are several problems that need to be addressed:

これは、作成が速く、デプロイと実行が速く、アプリが成長するにつれて保守が不可能になります。対処する必要があるいくつかの問題があります。
  • No error-checking: What if the connection to the database fails?
    エラーチェックなし: データベースへの接続が失敗した場合はどうなりますか?
  • Poor organization: If the application grows, this single file will become increasingly unmaintainable. Where should you put code to handle a form submission? How can you validate data? Where should code go for sending emails?
    貧弱な編成: アプリケーションが大きくなると、この単一のファイルはますます維持できなくなります。フォーム送信を処理するコードはどこに置くべきですか?どのようにデータを検証できますか?電子メールを送信するためのコードはどこに行くべきですか?
  • Difficult to reuse code: Since everything is in one file, there's no way to reuse any part of the application for other "pages" of the blog.
    コードの再利用が難しい: すべてが 1 つのファイルにあるため、アプリケーションのどの部分もブログの他の「ページ」に再利用することはできません。

Note

ノート

Another problem not mentioned here is the fact that the database is tied to MySQL. Though not covered here, Symfony fully integrates Doctrine, a library dedicated to database abstraction and mapping.

ここで言及されていないもう 1 つの問題は、データベースが MySQL に関連付けられているという事実です。ここでは説明しませんが、Symfony はデータベースの抽象化とマッピング専用のライブラリである Doctrine を完全に統合しています。

Isolating the Presentation

The code can immediately gain from separating the application "logic" from the code that prepares the HTML "presentation":

このコードは、アプリケーションの「ロジック」を HTML の「プレゼンテーション」を準備するコードから分離することですぐに得られます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// index.php
$connection = new PDO("mysql:host=localhost;dbname=blog_db", 'myuser', 'mypassword');

$result = $connection->query('SELECT id, title FROM post');

$posts = [];
while ($row = $result->fetch(PDO::FETCH_ASSOC)) {
    $posts[] = $row;
}

$connection = null;

// include the HTML presentation code
require 'templates/list.php';

The HTML code is now stored in a separate file templates/list.php, which is primarily an HTML file that uses a template-like PHP syntax:

HTML コードは、別のファイル templates/list.php に保存されます。これは主に、テンプレートのような PHP 構文を使用する HTML ファイルです。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!-- templates/list.php -->
<!DOCTYPE html>
<html>
    <head>
        <title>List of Posts</title>
    </head>
    <body>
        <h1>List of Posts</h1>
        <ul>
            <?php foreach ($posts as $post): ?>
            <li>
                <a href="/show.php?id=<?= $post['id'] ?>">
                    <?= $post['title'] ?>
                </a>
            </li>
            <?php endforeach ?>
        </ul>
    </body>
</html>

By convention, the file that contains all the application logic - index.php - is known as a "controller". The term controller is a word you'll hear a lot, regardless of the language or framework you use. It refers to the area of your code that processes user input and prepares the response.

慣例により、すべてのアプリケーション ロジックを含むファイル (index.php) は「コントローラー」と呼ばれます。コントローラーという用語は、使用する言語やフレームワークに関係なく、よく耳にする言葉です。ユーザー入力を処理して応答を準備するコードの領域を指します。

In this case, the controller prepares data from the database and then includes a template to present that data. With the controller isolated, you could change just the template file if you needed to render the blog entries in some other format (e.g. list.json.php for JSON format).

この場合、コントローラはデータベースからデータを準備し、そのデータを表示するためのテンプレートを組み込みます。コントローラーを分離すると、ブログエントリを他の形式 (JSON 形式の場合は list.json.php など) でレンダリングする必要がある場合は、テンプレート ファイルだけを変更できます。

Isolating the Application (Domain) Logic

So far the application contains only one page. But what if a second page needed to use the same database connection, or even the same array of blog posts? Refactor the code so that the core behavior and data-access functions of the application are isolated in a new file called model.php:

これまでのところ、アプリケーションには 1 ページしか含まれていません。しかし、2 番目のページが同じデータベース接続を使用する必要がある場合、またはブログ投稿の同じ配列を使用する必要がある場合はどうすればよいでしょうか?アプリケーションのコア動作とデータ アクセス関数が model.php という新しいファイルに分離されるように、コードをリファクタリングします。
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
// model.php
function open_database_connection()
{
    $connection = new PDO("mysql:host=localhost;dbname=blog_db", 'myuser', 'mypassword');

    return $connection;
}

function close_database_connection(&$connection)
{
    $connection = null;
}

function get_all_posts()
{
    $connection = open_database_connection();

    $result = $connection->query('SELECT id, title FROM post');

    $posts = [];
    while ($row = $result->fetch(PDO::FETCH_ASSOC)) {
        $posts[] = $row;
    }
    close_database_connection($connection);

    return $posts;
}

Tip

ヒント

The filename model.php is used because the logic and data access of an application is traditionally known as the "model" layer. In a well-organized application, the majority of the code representing your "business logic" should live in the model (as opposed to living in a controller). And unlike in this example, only a portion (or none) of the model is actually concerned with accessing a database.

ファイル名 model.php が使用されるのは、アプリケーションのロジックおよびデータ アクセスが伝統的に「モデル」層として知られているためです。適切に編成されたアプリケーションでは、「ビジネス ロジック」を表すコードの大部分が (コントローラー内ではなく) モデル内に存在する必要があります。また、この例とは異なり、モデルの一部 (またはまったく) のみが実際にデータベースへのアクセスに関係しています。

The controller (index.php) is now only a few lines of code:

コントローラー (index.php) は、数行のコードだけになりました。
1
2
3
4
5
6
// index.php
require_once 'model.php';

$posts = get_all_posts();

require 'templates/list.php';

Now, the sole task of the controller is to get data from the model layer of the application (the model) and to call a template to render that data. This is a very concise example of the model-view-controller pattern.

ここで、コントローラーの唯一のタスクは、アプリケーションのモデル レイヤー (モデル) からデータを取得し、テンプレートを呼び出してそのデータをレンダリングすることです。これは、モデル-ビュー-コントローラー パターンの非常に簡潔な例です。

Isolating the Layout

At this point, the application has been refactored into three distinct pieces offering various advantages and the opportunity to reuse almost everything on different pages.

この時点で、アプリケーションは 3 つの異なる部分にリファクタリングされており、さまざまな利点と、異なるページでほとんどすべてを再利用する機会を提供しています。

The only part of the code that can't be reused is the page layout. Fix that by creating a new templates/layout.php file:

再利用できないコードの部分は、ページ レイアウトだけです。新しい templates/layout.php ファイルを作成して修正します。
1
2
3
4
5
6
7
8
9
10
<!-- templates/layout.php -->
<!DOCTYPE html>
<html>
    <head>
        <title><?= $title ?></title>
    </head>
    <body>
        <?= $content ?>
    </body>
</html>

The template templates/list.php can now be simplified to "extend" the templates/layout.php:

テンプレート templates/list.php を単純化して、templates/layout.php を「拡張」できるようになりました。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!-- templates/list.php -->
<?php $title = 'List of Posts' ?>

<?php ob_start() ?>
    <h1>List of Posts</h1>
    <ul>
        <?php foreach ($posts as $post): ?>
        <li>
            <a href="/show.php?id=<?= $post['id'] ?>">
                <?= $post['title'] ?>
            </a>
        </li>
        <?php endforeach ?>
    </ul>
<?php $content = ob_get_clean() ?>

<?php include 'layout.php' ?>

You now have a setup that will allow you to reuse the layout. Unfortunately, to accomplish this, you're forced to use a few ugly PHP functions (ob_start(), ob_get_clean()) in the template. Symfony solves this using a Templating component. You'll see it in action shortly.

これで、レイアウトを再利用できるセットアップができました。残念ながら、これを実現するには、テンプレートでいくつかの醜い PHP 関数 (ob_start()、ob_get_clean()) を使用する必要があります。 symfony は、Templating コンポーネントを使用してこれを解決します。すぐに実際の動作を確認できます。

Adding a Blog "show" Page

The blog "list" page has now been refactored so that the code is better-organized and reusable. To prove it, add a blog "show" page, which displays an individual blog post identified by an id query parameter.

ブログの「リスト」ページがリファクタリングされ、コードがより整理され、再利用できるようになりました。それを証明するために、id クエリ パラメータで識別される個々のブログ投稿を表示するブログ「表示」ページを追加します。

To begin, create a new function in the model.php file that retrieves an individual blog result based on a given id:

まず、与えられた ID に基づいて個々のブログの結果を取得する model.php ファイルに新しい関数を作成します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// model.php
function get_post_by_id($id)
{
    $connection = open_database_connection();

    $query = 'SELECT created_at, title, body FROM post WHERE id=:id';
    $statement = $connection->prepare($query);
    $statement->bindValue(':id', $id, PDO::PARAM_INT);
    $statement->execute();

    $row = $statement->fetch(PDO::FETCH_ASSOC);

    close_database_connection($connection);

    return $row;
}

Next, create a new file called show.php - the controller for this new page:

次に、この新しいページのコントローラーである show.php という名前の新しいファイルを作成します。
1
2
3
4
5
6
// show.php
require_once 'model.php';

$post = get_post_by_id($_GET['id']);

require 'templates/show.php';

Finally, create the new template file - templates/show.php - to render the individual blog post:

最後に、新しいテンプレート ファイル - templates/show.php - を作成して、個々のブログ投稿をレンダリングします。
1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- templates/show.php -->
<?php $title = $post['title'] ?>

<?php ob_start() ?>
    <h1><?= $post['title'] ?></h1>

    <div class="date"><?= $post['created_at'] ?></div>
    <div class="body">
        <?= $post['body'] ?>
    </div>
<?php $content = ob_get_clean() ?>

<?php include 'layout.php' ?>

Creating the second page now requires very little work and no code is duplicated. Still, this page introduces even more lingering problems that a framework can solve for you. For example, a missing or invalid id query parameter will cause the page to crash. It would be better if this caused a 404 page to be rendered, but this can't really be done yet.

2 番目のページの作成に必要な作業は非常に少なくなり、コードが重複することもありません。それでも、このページでは、フレームワークが解決できるさらに長引く問題を紹介します。たとえば、id クエリ パラメータが欠落しているか無効であると、ページがクラッシュします。これにより 404 ページが表示されるようになればよいのですが、実際にはまだできません。

Another major problem is that each individual controller file must include the model.php file. What if each controller file suddenly needed to include an additional file or perform some other global task (e.g. enforce security)? As it stands now, that code would need to be added to every controller file. If you forget to include something in one file, hopefully it doesn't relate to security...

もう 1 つの大きな問題は、個々のコントローラー ファイルに model.php ファイルを含める必要があることです。各コントローラ ファイルに突然、追加のファイルをインクルードしたり、他のグローバル タスクを実行する必要が生じたりした場合はどうすればよいでしょうか (たとえば、セキュリティの実施など)?現状では、そのコードをすべてのコントローラ ファイルに追加する必要があります。うまくいけば、それはセキュリティに関係しません...

A "Front Controller" to the Rescue

The solution is to use a front controller: a single PHP file through which all requests are processed. With a front controller, the URIs for the application change slightly, but start to become more flexible:

解決策は、フロント コントローラーを使用することです。つまり、すべての要求が処理される単一の PHP ファイルです。フロント コントローラーを使用すると、アプリケーションの URI がわずかに変わりますが、より柔軟になり始めます。
1
2
3
4
5
6
7
Without a front controller
/index.php          => Blog post list page (index.php executed)
/show.php           => Blog post show page (show.php executed)

With index.php as the front controller
/index.php          => Blog post list page (index.php executed)
/index.php/show     => Blog post show page (index.php executed)

Tip

ヒント

By using rewrite rules in your web server configuration, the index.php won't be needed and you will have beautiful, clean URLs (e.g. /show).

Web サーバー構成で書き換えルールを使用することにより、index.php が不要になり、きれいでクリーンな URL (例: /show) が得られます。

When using a front controller, a single PHP file (index.php in this case) renders every request. For the blog post show page, /index.php/show will actually execute the index.php file, which is now responsible for routing requests internally based on the full URI. As you'll see, a front controller is a very powerful tool.

フロント コントローラーを使用する場合、単一の PHP ファイル (この場合は index.php) がすべての要求をレンダリングします。ブログ投稿の表示ページの場合、/index.php/show は実際に index.php ファイルを実行します。このファイルは、完全な URI に基づいて内部的にリクエストをルーティングする役割を果たします。ご覧のとおり、フロント コントローラーは非常に強力なツールです。

Creating the Front Controller

You're about to take a big step with the application. With one file handling all requests, you can centralize things such as security handling, configuration loading, and routing. In this application, index.php must now be smart enough to render the blog post list page or the blog post show page based on the requested URI:

あなたはアプリケーションで大きな一歩を踏み出そうとしています。すべての要求を 1 つのファイルで処理することで、セキュリティ処理、構成の読み込み、ルーティングなどを一元化できます。このアプリケーションでは、index.php は、要求された URI に基づいてブログ投稿リスト ページまたはブログ投稿表示ページをレンダリングするのに十分なほどスマートである必要があります。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// index.php

// load and initialize any global libraries
require_once 'model.php';
require_once 'controllers.php';

// route the request internally
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
if ('/index.php' === $uri) {
    list_action();
} elseif ('/index.php/show' === $uri && isset($_GET['id'])) {
    show_action($_GET['id']);
} else {
    header('HTTP/1.1 404 Not Found');
    echo '<html><body><h1>Page Not Found</h1></body></html>';
}

For organization, both controllers (formerly /index.php and /index.php/show) are now PHP functions and each has been moved into a separate file named controllers.php:

整理のために、両方のコントローラー (以前の /index.php および /index.php/show) は PHP 関数になり、それぞれが controllers.php という名前の別のファイルに移動されました。
1
2
3
4
5
6
7
8
9
10
11
12
// controllers.php
function list_action()
{
    $posts = get_all_posts();
    require 'templates/list.php';
}

function show_action($id)
{
    $post = get_post_by_id($id);
    require 'templates/show.php';
}

As a front controller, index.php has taken on an entirely new role, one that includes loading the core libraries and routing the application so that one of the two controllers (the list_action() and show_action() functions) is called. In reality, the front controller is beginning to look and act a lot like how Symfony handles and routes requests.

フロント コントローラーとして、index.php はまったく新しい役割を担っています。これには、コア ライブラリのロードと、2 つのコントローラー (list_action() および show_action() 関数) のいずれかが呼び出されるようにアプリケーションをルーティングすることが含まれます。実際には、フロント コントローラーは、Symfony がリクエストを処理およびルーティングする方法とよく似た外観と動作をし始めています。

But be careful not to confuse the terms front controller and controller. Your app will usually have only one front controller, which boots your code. You will have many controller functions: one for each page.

ただし、フロントコントローラーとコントローラーという用語を混同しないように注意してください。アプリには通常、コードを起動するフロント コントローラーが 1 つだけあります。各ページに 1 つずつ、多くのコントローラー関数があります。

Tip

ヒント

Another advantage of a front controller is flexible URLs. Notice that the URL to the blog post show page could be changed from /show to /read by changing code in only one location. Before, an entire file needed to be renamed. In Symfony, URLs are even more flexible.

フロント コントローラーのもう 1 つの利点は、柔軟な URL です。 1 か所のコードを変更するだけで、ブログ投稿の表示ページへの URL を /show から /read に変更できることに注意してください。以前は、ファイル全体の名前を変更する必要がありました。 Symfony では、URL はさらに柔軟です。

By now, the application has evolved from a single PHP file into a structure that is organized and allows for code reuse. You should be happier, but far from being satisfied. For example, the routing system is fickle, and wouldn't recognize that the list page - /index.php - should be accessible also via / (if Apache rewrite rules were added). Also, instead of developing the blog, a lot of time is being spent working on the "architecture" of the code (e.g. routing, calling controllers, templates, etc.). More time will need to be spent to handle form submissions, input validation, logging and security. Why should you have to reinvent solutions to all these routine problems?

今では、アプリケーションは単一の PHP ファイルから、コードを再利用できるように編成された構造へと進化しています。あなたはもっと幸せになるべきですが、満足には程遠いです。たとえば、ルーティング システムは気まぐれで、リスト ページ (/index.php) が /(Apache 書き換えルールが追加されている場合) 経由でもアクセスできる必要があることを認識しません。また、ブログを開発する代わりに、コードの「アーキテクチャ」(ルーティング、コントローラーの呼び出し、テンプレートなど) の作業に多くの時間が費やされています。フォームの送信、入力の検証、ログ記録、およびセキュリティを処理するには、さらに多くの時間を費やす必要があります。これらすべての日常的な問題に対するソリューションを再発明する必要があるのはなぜですか?

Add a Touch of Symfony

Symfony to the rescue. Before actually using Symfony, you need to download it. This can be done by using Composer, which takes care of downloading the correct version and all its dependencies and provides an autoloader. An autoloader is a tool that makes it possible to start using PHP classes without explicitly including the file containing the class.

救助へのsymfony。 Symfony を実際に使用する前に、ダウンロードする必要があります。これは、正しいバージョンとそのすべての依存関係をダウンロードし、オートローダーを提供する Composer を使用して行うことができます。オートローダーは、クラスを含むファイルを明示的にインクルードしなくても、PHP クラスの使用を開始できるようにするツールです。

In your root directory, create a composer.json file with the following content:

ルート ディレクトリで、次の内容を含む composer.json ファイルを作成します。
1
2
3
4
5
6
7
8
{
    "require": {
        "symfony/http-foundation": "^4.0"
    },
    "autoload": {
        "files": ["model.php","controllers.php"]
    }
}

Next, download Composer and then run the following command, which will download Symfony into a vendor/ directory:

次に、Composer をダウンロードして、次のコマンドを実行します。これにより、Symfony が vendor/ ディレクトリにダウンロードされます。
1
$ composer install

Beside downloading your dependencies, Composer generates a vendor/autoload.php file, which takes care of autoloading for all the files in the Symfony Framework as well as the files mentioned in the autoload section of your composer.json.

依存関係をダウンロードするだけでなく、Composer は vendor/autoload.php ファイルを生成します。このファイルは、Symfony Framework 内のすべてのファイルと composer.json の autoload セクションに記載されているファイルの自動ロードを処理します。

Core to Symfony's philosophy is the idea that an application's main job is to interpret each request and return a response. To this end, Symfony provides both a Request and a Response class. These classes are object-oriented representations of the raw HTTP request being processed and the HTTP response being returned. Use them to improve the blog:

Symfony の哲学の核となるのは、アプリケーションの主な仕事は各リクエストを解釈してレスポンスを返すことであるという考えです。この目的のために、Symfony は Request クラスと Response クラスの両方を提供します。これらのクラスは、処理される生の HTTP 要求と返される HTTP 応答のオブジェクト指向表現です。それらを使用してブログを改善します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// index.php
require_once 'vendor/autoload.php';

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

$request = Request::createFromGlobals();

$uri = $request->getPathInfo();
if ('/' === $uri) {
    $response = list_action();
} elseif ('/show' === $uri && $request->query->has('id')) {
    $response = show_action($request->query->get('id'));
} else {
    $html = '<html><body><h1>Page Not Found</h1></body></html>';
    $response = new Response($html, Response::HTTP_NOT_FOUND);
}

// echo the headers and send the response
$response->send();

The controllers are now responsible for returning a Response object. To make this easier, you can add a new render_template() function, which, incidentally, acts quite a bit like the Symfony templating engine:

コントローラーは、Response オブジェクトを返す責任を負うようになりました。これを簡単にするために、新しい render_template() 関数を追加できます。これは、偶然にも、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
// controllers.php
use Symfony\Component\HttpFoundation\Response;

function list_action()
{
    $posts = get_all_posts();
    $html = render_template('templates/list.php', ['posts' => $posts]);

    return new Response($html);
}

function show_action($id)
{
    $post = get_post_by_id($id);
    $html = render_template('templates/show.php', ['post' => $post]);

    return new Response($html);
}

// helper function to render templates
function render_template($path, array $args)
{
    extract($args);
    ob_start();
    require $path;
    $html = ob_get_clean();

    return $html;
}

By bringing in a small part of Symfony, the application is more flexible and reliable. The Request provides a dependable way to access information about the HTTP request. Specifically, the getPathInfo() method returns a cleaned URI (always returning /show and never /index.php/show). So, even if the user goes to /index.php/show, the application is intelligent enough to route the request through show_action().

Symfony の一部を取り入れることで、アプリケーションはより柔軟で信頼性が高くなります。 Request は、HTTP 要求に関する情報にアクセスするための信頼できる方法を提供します。具体的には、getPathInfo() メソッドはクリーンな URI を返します (常に /show を返し、/index.php/show は返しません)。したがって、ユーザーが /index.php/show にアクセスした場合でも、アプリケーションは show_action( を介してリクエストをルーティングするのに十分インテリジェントです。 )。

The Response object gives flexibility when constructing the HTTP response, allowing HTTP headers and content to be added via an object-oriented interface. And while the responses in this application are simple, this flexibility will pay dividends as your application grows.

Response オブジェクトは、HTTP 応答を構築する際に柔軟性を提供し、HTTP ヘッダーとコンテンツをオブジェクト指向インターフェースを介して追加できるようにします。このアプリケーションの応答は単純ですが、この柔軟性は、アプリケーションが成長するにつれて利益をもたらします。

The Sample Application in Symfony

The blog has come a long way, but it still contains a lot of code for such a basic application. Along the way, you've made a basic routing system and a function using ob_start() and ob_get_clean() to render templates. If, for some reason, you needed to continue building this "framework" from scratch, you could at least use Symfony's standalone Routing component and Twig, which already solve these problems.

ブログは長い道のりを歩んできましたが、このような基本的なアプリケーションのコードがまだたくさん含まれています。その過程で、ob_start() と ob_get_clean() を使用して基本的なルーティング システムと関数を作成し、テンプレートをレンダリングしました。何らかの理由で、この「フレームワーク」をゼロから構築し続ける必要がある場合は、少なくとも Symfony のスタンドアロンを使用できます。これらの問題をすでに解決している Routingcomponent と Twig。

Instead of re-solving common problems, you can let Symfony take care of them for you. Here's the same sample application, now built in 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
// src/Controller/BlogController.php
namespace App\Controller;

use App\Entity\Post;
use Doctrine\Persistence\ManagerRegistry;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;

class BlogController extends AbstractController
{
    public function list(ManagerRegistry $doctrine)
    {
        $posts = $doctrine->getRepository(Post::class)->findAll();

        return $this->render('blog/list.html.twig', ['posts' => $posts]);
    }

    public function show(ManagerRegistry $doctrine, $id)
    {
        $post = $doctrine->getRepository(Post::class)->find($id);

        if (!$post) {
            // cause the 404 page not found to be displayed
            throw $this->createNotFoundException();
        }

        return $this->render('blog/show.html.twig', ['post' => $post]);
    }
}

Notice, both controller functions now live inside a "controller class". This is a nice way to group related pages. The controller functions are also sometimes called actions.

両方のコントローラー関数が「コントローラー クラス」内にあることに注意してください。これは、関連するページをグループ化するための良い方法です。コントローラー関数は、アクションと呼ばれることもあります。

The two controllers (or actions) are still lightweight. Each uses the Doctrine ORM library to retrieve objects from the database and the Templating component to render a template and return a Response object. The list.html.twig template is now quite a bit simpler, and uses Twig:

2 つのコントローラー (またはアクション) はまだ軽量です。それぞれが Doctrine ORM ライブラリを使用してデータベースからオブジェクトを取得し、Templating コンポーネントを使用してテンプレートをレンダリングし、Response オブジェクトを返します。 list.html.twig テンプレートはかなりシンプルになり、Twig を使用します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{# templates/blog/list.html.twig #}
{% extends 'base.html.twig' %}

{% block title %}List of Posts{% endblock %}

{% block body %}
<h1>List of Posts</h1>
<ul>
    {% for post in posts %}
    <li>
        <a href="{{ path('blog_show', { id: post.id }) }}">
            {{ post.title }}
        </a>
    </li>
    {% endfor %}
</ul>
{% endblock %}

The layout.php file is nearly identical:

layout.php ファイルはほぼ同じです。
1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- templates/base.html.twig -->
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>{% block title %}Welcome!{% endblock %}</title>
        {% block stylesheets %}{% endblock %}
        {% block javascripts %}{% endblock %}
    </head>
    <body>
        {% block body %}{% endblock %}
    </body>
</html>

Note

ノート

The show.html.twig template is left as an exercise: updating it should be really similar to updating the list.html.twig template.

show.html.twig テンプレートは演習として残しておきます: それを更新することは、list.html.twig テンプレートを更新することと非常に似ているはずです。

When Symfony's engine (called the Kernel) boots up, it needs a map so that it knows which controllers to call based on the request information. A routing configuration map - config/routes.yaml - provides this information in a readable format:

Symfony のエンジン (カーネルと呼ばれる) が起動するとき、リクエスト情報に基づいてどのコントローラーを呼び出すかを知るために、マップが必要です。ルーティング構成マップ - config/routes.yaml - は、この情報を読み取り可能な形式で提供します:
1
2
3
4
5
6
7
8
# config/routes.yaml
blog_list:
    path:     /blog
    controller: App\Controller\BlogController::list

blog_show:
    path:     /blog/show/{id}
    controller: App\Controller\BlogController::show

Now that Symfony is handling all the mundane tasks, the front controller public/index.php is reduced to bootstrapping. And since it does so little, you'll never have to touch it:

Symfony がすべてのありふれたタスクを処理するようになったので、フロント コントローラーpublic/index.php はブートストラップに縮小されます。そして、それはほとんど何もしないので、あなたはそれに触れる必要はありません:
1
2
3
4
5
6
7
8
// public/index.php
require_once __DIR__.'/../app/bootstrap.php';
require_once __DIR__.'/../src/Kernel.php';

use Symfony\Component\HttpFoundation\Request;

$kernel = new Kernel('prod', false);
$kernel->handle(Request::createFromGlobals())->send();

The front controller's only job is to initialize Symfony's engine (called the Kernel) and pass it a Request object to handle. The Symfony core asks the router to inspect the request. The router matches the incoming URL to a specific route and returns information about the route, including the controller that should be called. The correct controller from the matched route is called and your code inside the controller creates and returns the appropriate Response object. The HTTP headers and content of the Response object are sent back to the client.

フロントコントローラーの唯一の仕事は、Symfony のエンジン (theKernel と呼ばれる) を初期化し、処理する Request オブジェクトを渡すことです。 Symfony はルーターに要求を検査するように要求します。ルーターは、着信 URL を特定のルートと照合し、呼び出す必要のあるコントローラーなど、ルートに関する情報を返します。一致したルートから正しいコントローラーが呼び出され、コントローラー内のコードが適切な Response オブジェクトを作成して返します。 HTTP ヘッダーと Response オブジェクトのコンテンツがクライアントに送り返されます。

It's a beautiful thing.

それは美しいことです。

Where Symfony Delivers

In the rest of the documentation articles, you'll learn more about how each piece of Symfony works and how you can organize your project. For now, celebrate how migrating the blog from flat PHP to Symfony has improved your life:

ドキュメント記事の残りの部分では、Symfony の各部分がどのように機能し、プロジェクトをどのように編成できるかについて詳しく学びます。とりあえず、ブログをフラットな PHP から Symfony に移行したことで、あなたの生活がどのように改善されたかを祝いましょう:
  • Your application now has clear and consistently organized code (though Symfony doesn't force you into this). This promotes reusability and allows for new developers to be productive in your project more quickly;
    あなたのアプリケーションは、明確で一貫性のあるコードを持っています (ただし、Symfony はこれを強制しません)。これにより、再利用性が促進され、新しい開発者がプロ​​ジェクトでより迅速に生産的になることができます。
  • 100% of the code you write is for your application. You don't need to develop or maintain low-level utilities such as autoloading, routing, or rendering controllers;
    あなたが書くコードの 100% は、あなたのアプリケーションのためのものです。自動ロード、ルーティング、レンダリング コントローラーなどの低レベルのユーティリティを開発または維持する必要はありません。
  • Symfony gives you access to open source tools such as Doctrine and the Templating, Security, Form, Validator and Translation components (to name a few);
    Symfony では、Doctrine やテンプレート、セキュリティ、フォーム、バリデーター、翻訳コンポーネントなどのオープン ソース ツールにアクセスできます。
  • The application now enjoys fully-flexible URLs thanks to the Routing component;
    アプリケーションは、Routing コンポーネントのおかげで完全に柔軟な URL を利用できるようになりました。
  • Symfony's HTTP-centric architecture gives you access to powerful tools such as HTTP caching powered by Symfony's internal HTTP cache or more powerful tools such as Varnish. This is covered in another article all about caching.
    Symfony の HTTP 中心のアーキテクチャにより、Symfony の内部 HTTP キャッシュを利用した HTTP キャッシングや、Varnish などのより強力なツールなどの強力なツールにアクセスできます。これは、キャッシングに関する別の記事で説明されています。

And perhaps best of all, by using Symfony, you now have access to a whole set of high-quality open source tools developed by the Symfony community! A good selection of Symfony community tools can be found on GitHub.

そしておそらく何よりも、Symfony を使用することで、Symfony コミュニティによって開発された高品質のオープン ソース ツールのセット全体にアクセスできるようになりました!Symfony コミュニティ ツールの優れた選択は、GitHub で見つけることができます。