Chapter 09

ユーザー削除画面を実装

たつきち
たつきち
2022.07.30に更新

この章に対応するコミット

デモアプリは日本語と英語に対応するためすべての文字列リテラルを翻訳しているので、コミットの内容は本文の解説と若干異なります。

ユーザー削除画面を実装

現状、ユーザー削除の動線は、ユーザー編集画面で 削除... ボタンをクリックしてJavaScriptのconfirmをOKするだけという実装になっていますが、間違って削除してしまうことがないようもう少し堅くしておきたいところです。

また、ほとんどの場合、ユーザーの削除と同時にそのユーザーに紐づいていたすべてのデータがcascadeで削除されてしまうという仕様は許されないと思いますが、ユーザーを削除する前に関連データの所有ユーザーを手動で変更して回るという作業を利用者に課すのも酷すぎて現実的ではありません。

なので、一般的なエンティティのCRUDに加えて、ユーザーの場合のみ「ユーザー削除画面」を設けて、その画面で「振替先ユーザー」を選択した上でユーザーを削除できるようにします。

FormType

まず、ユーザー削除用のFormTypeを作成します。

class UserDeleteType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $self = $options['self'];

        $builder
            ->add('alternateUser', EntityType::class, [
                'class' => User::class,
                'label' => '振替先ユーザー',
                'placeholder' => '',
                'attr' => [
                    'data-placeholder' => '選択してください',
                    'data-allow-clear' => true,
                    'class' => 'w-100',
                ],
                'query_builder' => function(UserRepository $repository) use ($self) {
                    return $repository->createQueryBuilder('u')
                        ->where('u != :self')
                        ->setParameter('self', $self)
                    ;
                },
            ])
        ;
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver
            ->setDefaults([
                'method' => 'DELETE',
            ])
            ->setRequired('self')
            ->setAllowedTypes('self', [User::class])
        ;
    }
}

削除対象のユーザー自身を振替先ユーザーに指定することはできないようにしたいので、EntityTypeのquery_builderオプション を使って自分自身を選択肢から除外できるようにしてあります。

この手法については以下の過去記事で詳しく説明していますので、ご参照ください✋

[Symfony] 循環参照しているエンティティのフォームで自分自身を選択できないようにする

コントローラ

次に、コントローラの delete アクションを以下のような内容に変更します。

/**
 * @Route("/delete/{id}", name="delete", methods={"GET", "DELETE"})
 * @IsGranted("ROLE_ALLOWED_TO_EDIT_USER")
 */
public function delete(Request $request, User $user)
{
    $form = $this->createForm(UserDeleteType::class, null, [
        'self' => $user,
    ]);
    $form->handleRequest($request);

    if ($form->isSubmitted() && $form->isValid()) {

        /** @var User $alternateUser */
        $alternateUser = ($alternateUserId = $form->get('alternateUser')->getData())
            ? $this->repository->find($alternateUserId)
            : null
        ;

        if (!$alternateUser) {
            throw new \RuntimeException();
        }

        // 各種関連エンティティの所有ユーザーを$laternateUserに変更する(現状は何もなし)

        $this->em->remove($user);
        $this->em->flush();

        $this->addFlash('success', 'ユーザーの削除が完了しました。');

        return $this->redirectToRouteOrReturn('user_index');
    }

    return $this->render('user/delete.html.twig', [
        'user' => $user,
        'form' => $form->createView(),
    ];
}

'self' => $user, で削除対象ユーザーをFormTypeの self オプションに渡しています。

フォームで送信された振替先ユーザーのIDからユーザーエンティティを取得し、各種関連エンティティの所有ユーザーを変更した上で、ユーザーの削除を実行する流れを想定しています。

が、現状は何も関連エンティティがないのでとりあえず処理は空です✋

ビュー

あとは、

完了です👍

動作確認

これで、下図のようなユーザー削除画面ができました🙌

見た目はダサいですが、絶対に間違えて実行してほしくない操作なので、これぐらい過激な色でいいと思います。