Symfony4.4 ログイン中のアカウントのパスワードの再チェックフォームの実装

# 課題

パスワードの変更やクレジットカードの削除など、システム上、重要な変更をする場合は、ログインをしている状態でも、本人確認のために、再度、パスワードを確認したい。

バリデーションを眺めていたら、目的に合致する機能があったので、使ってみました。

# TL;DR

こちらも、ズバリ、バリデーションとして、[UserPassword](https://symfony.com/doc/4.4/reference/constraints/UserPassword.html)が用意されている。

こちらを使うと、現在ログイン済みのアカウントのパスワードとチェックをしてくれるというもの。

フォームクラスとして、以下のように定義して使います。
コントローラとTwigテンプレも掲載します。

```php:App/Form/PasswordChangeType.php
<?php

namespace App\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Security\Core\Validator\Constraints\UserPassword;
use Symfony\Component\Validator\Constraints\Length;
use Symfony\Component\Validator\Constraints\NotBlank;

class PasswordChangeType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('oldPassword', PasswordType::class, [
                'constraints' => [
                    new UserPassword([
                        'message' => '正しいパスワードを設定してください。'
                    ])
                ]
            ])
            ->add('newPassword', RepeatedType::class, [
                'type' => PasswordType::class,
                'required' => true,
                'invalid_message' => '再入力されたパスワードと一致しません。',
                'constraints' => [
                    new NotBlank([
                        'message' => 'パスワードを設定指定ください。',
                    ]),
                    new Length([
                        'min' => 6,
                        'minMessage' => 'パスワードは、{{ limit }}文字以上で設定してください。',
                        // max length allowed by Symfony for security reasons
                        'max' => 100,
                        'maxMessage' => 'パスワードは、{{limit}}文字以内で設定してください。'
                    ]),
                ],
            ])
        ;
    }
}

```

```php:App/Controller/changePasswordController.php
   /**
     * @Route("/password/change", name="password_change")
     * @param Request $request
     * @param UserPasswordEncoderInterface $passwordEncoder
     * @param Security $security
     * @return \Symfony\Component\HttpFoundation\Response
     */
    public function changePassword(int $id, Request $request, UserPasswordEncoderInterface $passwordEncoder, Security $security)
    {
        $email = $security->getUser()->getUsername();
        /** @var User $user */
        $user = $this->getDoctrine()->getRepository(User::class)->findOneBy(['email' => $email]);
        $form = $this->createForm(UserPasswordType::class);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $user->setPassword(
                $passwordEncoder->encodePassword(
                    $user,
                    $form->get('newPassword')->getData()
                )
            );

            $this->getDoctrine()->getManager()->flush();

            $this->addFlash('success', 'パスワードを変更しました。');
        }

        return $this->render('changePassword/password.html.twig', [
           'passwordForm' => $form->createView()
        ]);
    }
```

```twig:templates/changePassword/password.html.twig
    <div class="container">
        <div class="row justify-content-center">
            <div class="col-4">
                {{ form_start(passwordForm) }}
                {{ form_row(passwordForm.oldPassword, {label:'現在のパスワード'}) }}
                {{ form_row(passwordForm.newPassword.first, {label:'新しいパスワード'}) }}
                {{ form_row(passwordForm.newPassword.second, {label:'新しいパスワード再入力'}) }}
                <button class="btn btn-primary" name="confirm" type="submit"><i class="fas fa-check fa-fw mr-2"></i>変更する</button>
                {{ form_end(passwordForm) }}
            </div>
        </div>
    </div>
```

以下が実際の動作

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133291/afbde078-f0c0-187d-f458-332f70a5ce1b.png)