Symfony Formを利用したフォームの作成について解説

[Symfony Advent Calendar 2022](https://qiita.com/advent-calendar/2022/symfony) 13日目の記事です✨
昨日は @77web@github さんの「Symfony World 2022 Winter day2参加レポ」でした！

今回は前回書いた記事「[Symfony Formを利用したフォームの作成について解説](https://qiita.com/mako5656/items/85b18f8e8fb8cb622f2b)」のフォーム箇所に絞って詳しく解説していきます！

## 前回の振り返り

①プロジェクトの作成

``` zsh
$ composer create-project symfony/website-skeleton hello-symfony6
```

②フォームに必要な3つのファイル作成

- src ＞ Controller ＞ HelloController.php
- template ＞ hello ＞ index.html.twig
- src ＞ Entity ＞ Person.php

## 3つのファイルそれぞれの解説

### 1. src ＞ Controller ＞ HelloController.php

``` php
<?php

declare(strict_types=1);

namespace App\Controller;

use App\Entity\Person;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

class HelloController extends AbstractController
{
    #[Route('/hello', name:'hello')]
    public function index(Request $request): Response
    {
        $person = new Person();

        $form = $this->createFormBuilder($person)
            ->add('name', TextType::class)
            ->add('mail', EmailType::class)
            ->add('save', SubmitType::class, ['label' => 'Click'])
            ->getForm();

        if ($request->getMethod() == 'POST'){
            $form->handleRequest($request);
            $obj = $form->getData();
            $message = '名前は' . $obj->getName() . 'で、' . 'メールアドレスは ' . $obj->getMail() . 'です。';
        } else {
            $message = 'こんにちは！<br>あなたの名前とメールアドレスを教えて下さい！';
        }

        return $this->render('hello/index.html.twig', [
            'title' => 'Hello World!',
            'message' => $message,
            'form' => $form->createView(),
        ]);
    }
}

```

### 1.1 ルート設定

``` php
#[Route('/hello', name:'hello')]
```
単なるルーティング設定です
/hello にアクセスするとその下にあるメソッドが呼べます。

- /hello
→URLのパスを指定する。

- name='hello'
→ルーティング名symfony内でURLを呼び出す際に使用する。

### 1.2 FormInterfaceの作成

``` php
$form = $this->createFormBuilder($person)
             ->add('name', TextType::class)
             ->add('mail', EmailType::class)
             ->add('save', SubmitType::class, ['label' => 'Click'])
             ->getForm();
```

createFormBuilderの引数に先程のPsersonクラス入れることでデータを持ったままFormInterfaceの作成ができます。

今回、テキスト用のフィールド→TextType,メール用のフィールド→EmailTypeと指定しましたが、
数字用のフィールド→IntegerType,金額用のフィールド→MoneyType,日付用のフィールドDateTypeなど色々とあります。※1

項目を増やしたい場合ここにフィールドを1つ追加することで増やせるのは便利です。

### 1.3 POST送信時の処理

``` php
if ($request->getMethod() == 'POST'){
    $form->handleRequest($request);
    $obj = $form->getData();
    $message = '名前は' . $obj->getName() . 'で、' . 'メールアドレスは ' . $obj->getMail() . 'です。';
} else {
    $message = 'こんにちは！<br>あなたの名前とメールアドレスを教えて下さい！';
}
```

`if ($request->getMethod() == 'POST')` でフォームが送られたかどうかが判断し、
送られているなら
`$form->handleRequest($request);` で引数の`$request(送信された情報)`をフィールドに設定する働きをしています。※2

あとは、`$form`から情報を取り出して`$message`に格納してます。

### 1.4 Twigファイルに情報を渡す

``` php
return $this->render('hello/index.html.twig', [
         'title' => 'Hello World!',
         'message' => $message,
         'form' => $form->createView(),
       ]);
```
ここでは単に`render()`で変数の配列をTwigに渡すことをおこないます。

## 2. template ＞ hello ＞ index.html.twig

ここではFormViewによるフォームの表示を行っています。

``` twig
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>{{title}}</title>
</head>
<body>
<h1>{{title}}</h1>
<p>{{message | raw}}</p>
{{ form_start(form) }}
{{ form_widget(form) }}
{{ form_end(form) }}
</body>
</html>
```

formについてそれぞの行の意味としては、

- `{{ form_start(form) }}`：フォームの開始を表すもの(<form>タグ)
- `{{ form_widget(form) }}`：フォームの内容全てを表すもの(<input>タグ全て)
- `{{ form_end(form) }}` ：フォームの終了を表す(</form>タグ)

です。

## 3. src ＞ Entity ＞ Person.php

Personに関するデータ管理用のクラスです。

``` php
<?php

declare(strict_types=1);

namespace App\Entity;

class Person
{
    private ?string $name = null;
    private ?string $mail = null;

    public function getName(): ?string
    {
        return $this->name;
    }

    public function setName(string $name): static
    {
        $this->name = $name;

        return $this;
    }

    public function getMail(): ?string
    {
        return $this->mail;
    }

    public function setMail(string $mail): static
    {
        $this->mail = $mail;

        return $this;
    }
}
```

`$name` と`$mail` のプロパティとgeter/setterがあり、
Personに関する名前とメールアドレスを管理するためのクラスです。

役割としては、Formから入力された値を管理し、逆に利用したい場合に取り出したりしています。

## まとめ

今回、前回書いた記事「[Symfony Formを利用したフォームの作成について解説](https://qiita.com/mako5656/items/85b18f8e8fb8cb622f2b)」のフォーム箇所に絞って紹介しました。

まだまだSymfonyのドキュメントとにらめっこする日が続くと思うので頑張っていこうと思います。

[Symfony Advent Calendar 2022](https://qiita.com/advent-calendar/2022/symfony)、明日は @ippey_s さんです！


## 参考
※1 Symfony公式ドキュメントFormTypeについて

https://symfony.com/doc/current/reference/forms/types.html

※2 Symfony公式ドキュメントhandleRequestについて

https://symfony.com/doc/current/components/form.html#request-handling