ステップ 6: コントローラーを作成する

5.0 version
Maintained

コントローラーを作成する

ちょっとごまかしがありますが、私たちのゲストブックのプロジェクトは、本番サーバーで実際に動くようになりました。まだプロジェクトはページが一つもありません。ホームページは 404 エラーページとなっていますので、直してみましょう。

ホームページへ(http://localhost:8000/)のような、HTTP リクエストが来ると、 Symfony は リクエストされたパス (ここでは /) にマッチする ルート を探そうとします。 ルート は、リクエストのパスと対応する HTTP レスポンス を作成する関数の PHP の実行可能コード をリンクします。

これらの実行可能なコードを "コントローラー" と呼びます。 Symfony では、ほとんどのコントローラーは PHP のクラスで実装します。クラスは手動で作成することが可能ですが、もっと早くするため Symfony がやってくれることを見てみましょう。

Maker Bundle で楽をする

少ない努力でコントローラーを生成するのに symfony/maker-bundle パッケージを使用することができます:

1
$ symfony composer req maker --dev

Maker Bundle は開発時のみで便利なバンドルで、本番では有効にしたくないので、 --dev フラグをつけるのを忘れないでください。

Maker Bundle はたくさんのクラスを生成してくれます。この書籍では、常に使うことになります。各 "ジェネレーター" は、コマンドに定義されており、全てのコマンドは、 make コマンドのネームスペースにあります。

Symfony Console の list コマンドは、指定のネームスペース以下の全てのコマンドを一覧で表示します; Maker Bundle で使用可能なすべてのジェネレーターを調べてみてください:

1
$ symfony console list make

設定のフォーマットを選ぶ

プロジェクトの最初のコントローラーを作成する前に、使用したい設定のフォーマットを決める必要があります。Symfony は YAML, XML, PHP, アノテーションを最初からサポートしています。

関連するパッケージの設定 では、 YAML がベストな選択です。YAML フォーマットは、 config/ ディレクトリ内で使用されています。多くの場合、新しいパッケージをインストールすると、パッケージのレシピは .yaml という拡張子の新規ファイルをこのディレクトリに追加します。

PHP コードに関連する設定 では、コードに隣接して定義することができる アノテーション がベターな選択です。例で説明しましょう。リクエストが来ると、設定は Symfony にどのリクエストパスがどのコントローラー(PHPクラス)によって処理するか伝える必要があります。YAML や XML や PHP フォーマットでは、2つのファイルを必要とします(設定ファイルと PHP のコントローラーファイル)。アノテーションを使用すれば、設定はコントローラークラスで直接設定可能です。

アノテーションを使用するために、依存を追加する必要があります:

1
$ symfony composer req annotations

インストールする必要のあるパッケージ名をどうやって判断するか疑問に思ったかもしれません。ほとんどの場合、知る必要はありません。Symfony はエラーメッセージ中にインストールが必要なパッケージを表示しています。 annotations パッケージのない状態で symfony make:controller コマンドを実行すると、正しいパッケージをインストールするヒントを含んだ例外を見ることができます。

コントローラーを生成する

make:controller コマンドで最初の コントローラー を作成しましょう:

1
$ symfony console make:controller ConferenceController

このコマンドは src/Controller ディレクトリ以下に ConferenceController クラスを作成します。生成されたクラスはちゃんと動くようなボイラープレートが既に入っています:

src/Controller/ConferenceController.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
namespace App\Controller;

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

class ConferenceController extends AbstractController
{
    /**
     * @Route("/conference", name="conference")
     */
    public function index()
    {
        return $this->render('conference/index.html.twig', [
            'controller_name' => 'ConferenceController',
        ]);
    }
}

@Route("/conference", name="conference") アノテーションは、コントローラーの index() メソッドを作成します(設定は、コードに隣接しています)。

/conference をブラウザで開くと、このコントローラが実行され、レスポンスが返されます。

ホームページにマッチするようにルートを微調整します:

patch_file
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
--- a/src/Controller/ConferenceController.php
+++ b/src/Controller/ConferenceController.php
@@ -8,7 +8,7 @@ use Symfony\Component\Routing\Annotation\Route;
 class ConferenceController extends AbstractController
 {
     /**
-     * @Route("/conference", name="conference")
+     * @Route("/", name="homepage")
      */
     public function index()
     {

コード内でホームページを参照したいときは、ルートの 名前 が便利です。 / パスをハードコードせずに、 ルート名を使いましょう。

デフォルトで表示されるページの代わりに、シンプルな HTML のページを返すようにしましょう:

patch_file
 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
--- a/src/Controller/ConferenceController.php
+++ b/src/Controller/ConferenceController.php
@@ -3,6 +3,7 @@
 namespace App\Controller;

 use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
+use Symfony\Component\HttpFoundation\Response;
 use Symfony\Component\Routing\Annotation\Route;

 class ConferenceController extends AbstractController
@@ -12,8 +13,13 @@ class ConferenceController extends AbstractController
      */
     public function index()
     {
-        return $this->render('conference/index.html.twig', [
-            'controller_name' => 'ConferenceController',
-        ]);
+        return new Response(<<<EOF
+<html>
+    <body>
+        <img src="/images/under-construction.gif" />
+    </body>
+</html>
+EOF
+        );
     }
 }

ブラウザを更新します:

コントローラーの主な責務は、リクエストに対応する HTTP レスポンス を返すことです。

イースターエッグを追加します

どうやってリクエストの情報からレスポンスが作られるかを見るために、 小さな Easter egg を追加してみましょう。ホームページに ?hello=Fabien のようなクエリー文字列が含まれていたら、挨拶ができるようにしてみましょう:

 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
--- a/src/Controller/ConferenceController.php
+++ b/src/Controller/ConferenceController.php
@@ -3,6 +3,7 @@
 namespace App\Controller;

 use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
+use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\HttpFoundation\Response;
 use Symfony\Component\Routing\Annotation\Route;

@@ -11,11 +12,17 @@ class ConferenceController extends AbstractController
     /**
      * @Route("/", name="homepage")
      */
-    public function index()
+    public function index(Request $request)
     {
+        $greet = '';
+        if ($name = $request->query->get('hello')) {
+            $greet = sprintf('<h1>Hello %s!</h1>', htmlspecialchars($name));
+        }
+
         return new Response(<<<EOF
 <html>
     <body>
+        $greet
         <img src="/images/under-construction.gif" />
     </body>
 </html>

Symfony は Request オブジェクトを通してリクエストされたデータを取得することができます。Symfony は、コントローラーの引数にこの型宣言があると、自動的に渡すことができます。 クエリー文字列にある name の値を取得して <h1> のタイトルに追加することができます。

ブラウザで、/ へアクセスして、それから /?hello=Fabien へ変えて、違いを見てみてください。

注釈

XSS の問題を避けるために htmlspecialchars() が呼ばれているのに気づきましたか。適切なテンプレートエンジンへスイッチすると、自動的にサニタイズされます。

また、URL の一部の name を指定することができます:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
--- a/src/Controller/ConferenceController.php
+++ b/src/Controller/ConferenceController.php
@@ -9,13 +9,19 @@ use Symfony\Component\Routing\Annotation\Route;
 class ConferenceController extends AbstractController
 {
     /**
-     * @Route("/", name="homepage")
+     * @Route("/hello/{name}", name="homepage")
      */
-    public function index()
+    public function index(string $name = '')
     {
+        $greet = '';
+        if ($name) {
+            $greet = sprintf('<h1>Hello %s!</h1>', htmlspecialchars($name));
+        }
+
         return new Response(<<<EOF
 <html>
     <body>
+        $greet
         <img src="/images/under-construction.gif" />
     </body>
 </html>

ルーティングの {name} の部分は、 ダイナミックな ルートパラメーター です。ワイルドーカードのようなものです。これでブラウザで /hello と開いてから hello/Fabien と変えても同じ結果が出すことができます。コントローラーに name と同じ引数($name)を指定することで、 {name} パラメーターの を取得することができます。


  • « Previous ステップ 5: トラブルシューティング
  • Next » ステップ 7: データベースをセットアップする

This work, including the code samples, is licensed under a Creative Commons BY-NC-SA 4.0 license.