あれこれをSymfony2.4でやる Form確認入力編

フレームワークのバージョンを上げた時、実装したあの機能は新しいバージョンでどーやるんだ？
よく遭遇する疑問なのでメモって同じ疑問にぶつかった人に共有しておこう。
別にバージョンアップじゃなくて初めてSymfony2.4触る人にも共有できるな。


今回はあの機能。入力フォームで同じ項目を２個用意して入力値の比較でバリデーションを行うあれ。
パスワード登録とかメールアドレス登録とかでよく見かけるよね。
二つの入力値が一致しない場合はバリデーションエラーになってしまう入力フォームだ！！

## エンティティにバリデーションメソッド追加

んでは。早速Symfony2.4で実装する。
バリデーションを行いたいEntityにプロパティとメソッドを追加する。
User::emailプロパティを比較するためのUser::emailConfirmってプロパティを追加。
それのセッターゲッターと比較を行うメソッドを追加する。

```php:User.php
// src/Acme/YourBundle/Entity/User.php

namespace Acme\YourBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @PRM\Table
 * @ORM\Entity
 */
class User
{
  /**
   * @ORM¥Column(type="string", lenght="128")
   */
  private $mail;

  /**
   * @var string
   */
  private $mailConfirm;

  /**
   * Set Email
   * @param string $email
   * @return User
   */
  public function setEmail($email)
  {
    $this->email = $email;

    return $this;
  }

  /**
   * Get Email
   * @return string
   */
  public function getEmail()
  {
    return $this->email;
  }

  /**
   * Set Email confirm
   * @param string $emailConfirm
   * @return User
   */
  public function setEmailConfirm($emailConfirm)
  {
    $this->email = $emailConfirm;

    return $this;
  }

  /**
   * Get Email confirm
   * @return string
   */
  public function getEmailConfirm()
  {
    return $this->emailConfirm;
  }

  /**
   * 二つの入力値を比較するバリデーションメソッド
   * @return boolean
   */
  public function isEqualEmailConfirm()
  {
    // 二つの入力値を比較して一致すればTrueを返すようにする
    return $this->getEmail() && $this->getEmailConfirm();
  }
}
```

## Typeクラスに確認用入力フォームを追加

まぁ、詳細は以下のコードが示してる。

```php:UserType.php
// src/Acme/YourBundle/From/UserType.php
namespace Acme\YourBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;

class UserType extends AbstractType
{
  /**
   * @param FormBuidlerInterface $builder
   * @param array $options
   */
  public function buildForm(FormBuilderInterface $builder, array $options)
  {
    // ここで確認用のフォームフィールドを登録する
    $builder
      ->add('email', null, array('label' => 'メールアドレス'))
      ->add('emailConfirm', 'email', array('label' => 'メールアドレス(確認用)'));
  }

  /**
   * @param OptionsResolverInterface $resolver
   */
  public function setDefaultOptions(OptionsResolverInterface $resolver)
  {
    // Userエンティティを使用するように設定
    $resolver->setDefaults(array(
      'data_class' => 'Acme\YourBundle\Entity\User',
    ));
  }

  /**
   * @return string
   */
  public function getName()
  {
    return 'acme_yourbundle_user';
  }
}
```

## YAMLファイルに登録

んで、このバリデーションメソッドをSymfonyに教えてあ・げ・る。

```yaml:validate.yml
# src/Acme/YourBundle/Resource/config/validation.yml
Acme\YourBundle\Entity\User:
  getters:
    equalEmailConfirm:
      - "True" : { message: 入力したメールアドレスが確認用メールアドレスと一致しません。 }
```

isやgetを省略したメソッド名をYAMLのgettersに登録する。
(この辺の仕様はSymfonyのドキュメントのどこかに書いてあったがどこだったか・・・)
今回は二つを比較して一致すればTrueを返すメソッドなので上記の様な設定になる。(Trueを(ダブル)クォーテーションで囲まないとエラー出っぞ)
合わせてmessage項目でバリデーションエラーの文言も登録しておくといいね。

## コントローラで処理を実行

後はコントローラから呼び出せばおkさ。
そうそう、日本Symfonyユーザ会が翻訳してくれているフォーム処理関連のドキュメントが古いらしく
2.4ではbindRequestメソッドが使えない、つまりエラーになってしまう。
原文では最新になっており、handleRequestメソッドに変更されているので要注意。

```php:UserController.php
// src/Acme/YourBundle/Controller/UserController.php
namespace Acme\YourBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Acme\YourBundle\Form\UserType;
use Acme\YourBundle\Entity\User;

class UserController extends Controller
{
  public function newAction(Request $request)
  {
    $user = new User();
    $form = $this->createForm(new UserType);
    $form->setData($user);

    if ($request->getMethod() == 'POST') {
      // handleRequestメソッドでないと2.4はエラーになる
      $form->handleRequest($request);

      if ($form->isValid()) {
        // バリデーションOKであれば保存
        $manager = $this->getDoctrine()->getManager();
        $manager->persist($user);
        $manager->flush();

        // 二重POST防ぐ為に登録完了ページへリダイレクト
        return $this->redirect($this->generateUrl('...'));
      }
    }

    return $this->render('AcmeYourBundle:User:new.html.twig', array('form', $form->createView()));
  }
}
```

テンプレートファイルは自分で用意して（サンプル書くのめんどくさくなった）

これで大丈夫なはずだが、一つだけ問題がある。
実際に動いているコードから公開用に作り直したコードをアップしたのだけど・・・これはテストしてないのだ！
一番ダメなパターン (>ω<｡人) 許して～