Symfonyのコレクションフォームをバリデーションする方法を完全ガイド!初心者でもわかる入力チェックの基本
生徒
「Symfonyで、複数のフォームをまとめて扱う方法ってありますか?」
先生
「ありますよ。それが『コレクションフォーム』という機能です。複数の入力欄をひとつにまとめて管理できます。」
生徒
「でも、その場合ってバリデーション(入力チェック)はどうすればいいんですか?」
先生
「いいところに気づきましたね。コレクションフォームでも、しっかりとバリデーションができますよ。やり方を詳しく見ていきましょう!」
1. Symfonyのコレクションフォームとは?
コレクションフォームとは、Symfonyで使えるフォーム機能のひとつで、同じ種類の入力フィールドを「複数まとめて」扱える便利な仕組みです。
たとえば、「1人のユーザーが複数の電話番号を持っている」というようなケースで、電話番号入力欄をいくつも表示したいときに使います。
このように、「配列のように繰り返しの入力をまとめて扱う」ときに、CollectionType(コレクションタイプ)を使います。
2. コレクションフォームにバリデーションをかけるとは?
「バリデーション」とは、フォームに入力された内容が正しいかどうかをチェックする仕組みです。たとえば、空欄禁止や、文字数の制限などがあります。
コレクションフォームでは、1つ1つの「子要素」に対して、それぞれバリデーションを適用します。たとえば、「各電話番号は10桁以上でなければいけない」といった制限をつけることができます。
3. エンティティとバリデーションアノテーションの準備
まずは、バリデーションを使うために、@Assertというアノテーションを使ってルールを指定しておきます。エンティティというのは、データの型や構造を表すPHPクラスのことです。
namespace App\Entity;
use Symfony\Component\Validator\Constraints as Assert;
class PhoneNumber
{
#[Assert\NotBlank(message: "電話番号を入力してください。")]
#[Assert\Length(min: 10, minMessage: "電話番号は10桁以上で入力してください。")]
private string $number;
public function getNumber(): string
{
return $this->number;
}
public function setNumber(string $number): void
{
$this->number = $number;
}
}
4. コレクションフォームのFormTypeクラスを作成
Symfonyでは、フォームの構成をFormTypeというクラスで定義します。今回は、電話番号を複数入力できるフォームを作ります。
namespace App\Form;
use App\Entity\PhoneNumber;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class PhoneNumberType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder->add('number', TextType::class);
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => PhoneNumber::class,
]);
}
}
5. 親フォームにCollectionTypeを設定する
次に、コレクションフォームの親となるフォームを作ります。ここで、CollectionTypeを使って、PhoneNumberTypeを繰り返し入力できるようにします。
namespace App\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use App\Entity\User;
use App\Form\PhoneNumberType;
class UserType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder->add('phoneNumbers', CollectionType::class, [
'entry_type' => PhoneNumberType::class,
'allow_add' => true,
'by_reference' => false,
]);
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => User::class,
]);
}
}
6. コントローラでフォームとバリデーションを連携させる
最後に、フォームとエンティティを結びつけて、バリデーションを有効にする処理をコントローラに書きます。
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;
use App\Entity\User;
use App\Form\UserType;
class UserController extends AbstractController
{
#[Route('/user', name: 'user_form')]
public function form(Request $request): Response
{
$user = new User();
$form = $this->createForm(UserType::class, $user);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
// データの保存処理など
return new Response('保存しました!');
}
return $this->render('user/form.html.twig', [
'form' => $form->createView(),
]);
}
}
7. バリデーションエラーの表示も自動で行われる
Symfonyのフォームでは、Twigテンプレート側でフォームを正しくレンダリングすれば、バリデーションエラーも自動で表示されます。たとえば以下のように書くことで、エラーメッセージが表示されます。
{{ form_start(form) }}
{{ form_row(form.phoneNumbers) }}
<button type="submit">送信</button>
{{ form_end(form) }}
8. バリデーション対象が配列でも安心
通常のバリデーションと違って、コレクションフォームでは「それぞれの項目に対して同じバリデーションルールを適用する」ことが重要です。Symfonyはこれを標準でサポートしているので、開発者は安心して入力チェックを任せることができます。
しかも、Twigテンプレートでの表示も、ひとつずつ丁寧に繰り返して出力してくれるので、デザイン面でも柔軟に対応できます。