Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Symfony 4 - Good practice to remove your own user account while connected

I would like my users to be able to delete their own user account. I made a SecurityController where there is my 3 functions login, logout and deleteUser. When I delete the current user in database this error appears :

You cannot refresh a user from the EntityUserProvider that does not contain an identifier. The user object has to be serialized with its own identifier mapped by Doctrine.

When I delete another user, it works correctly because he's not connected. Do I have to serialize the User and pass it through a Service, logout the user then remove it in a Service? Or can I clear the PHP session in the controller but I don't know how to do it with symfony4 I think it changed since version 4.

<?php

namespace App\Controller;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Security\Core\Authorization\AuthorizationChecker;

use App\Entity\User;
use App\Form\UserType;

class SecurityController extends Controller
{
  /**
   * @Route("/createAdmin", name="create_admin")
   */
    public function createAdminUser(Request $request, UserPasswordEncoderInterface $passwordEncoder)
    {
      $usersRepo = $this->getDoctrine()->getRepository(User::class);
      $uCount = $usersRepo->countAllUsers();

      if ($uCount == 0)
      {
        $user = new User();
        $form = $this->createForm(UserType::class, $user, array(
          'is_fresh_install' => true,
        ));

        $form->handleRequest($request);
        if ($form->isSubmitted() && $form->isValid()) {

            // Encode the password
            $password = $passwordEncoder->encodePassword($user, $user->getPlainPassword());
            $user->setPassword($password);

            // save the User
            $em = $this->getDoctrine()->getManager();
            $em->persist($user);
            $em->flush();

            // Do what you want here before redirecting the user

            return $this->redirectToRoute('login');
        }

        return $this->render('security/register_admin_user.html.twig', array(
          'form' => $form->createView(),
        ));
      } else {
        if ($this->getUser())
        {
          return $this->redirectToRoute('user_account');
        } else {
          return $this->redirectToRoute('login');
        }
      }
    }

    /**
     * @Route("/login", name="login")
     */
    public function login(Request $request, AuthenticationUtils $authUtils)
    {
      $usersRepo = $this->getDoctrine()->getRepository(User::class);
      $uCount = $usersRepo->countAllUsers();

      if ($uCount == 0)
      {
        return $this->redirectToRoute('create_admin');
      } else {
        $error = $authUtils->getLastAuthenticationError();
        $lastUsername = $authUtils->getLastUsername();

        return $this->render('security/login.html.twig', array(
         'last_username' => $lastUsername,
         'error'         => $error,
        ));
      }
    }

    /**
     * @Route("/logout", name="logout")
     */
    public function logout()
    {

    }

    /**
     * @Route("/delete_user/{id}", name="delete_user")
     */
    public function deleteUser($id)
    {
      $em = $this->getDoctrine()->getManager();
      $usrRepo = $em->getRepository(User::class);

      $user = $usrRepo->find($id);
      $em->remove($user);
      $em->flush();

      return $this->redirectToRoute('user_registration');

    }

}
like image 387
blakyris Avatar asked Mar 21 '18 08:03

blakyris


2 Answers

SOLUTION :

You have to clear the Session before deleting user entry in DB with this method:

<?php

use Symfony\Component\HttpFoundation\Session\Session;

// In your deleteUser function...

      $currentUserId = $this->getUser()->getId();
      if ($currentUserId == $id)
      {
        $session = $this->get('session');
        $session = new Session();
        $session->invalidate();
      }

I don't know why $this->get('session')->invalidate(); doesn't work directly... if someone knows :)

like image 200
blakyris Avatar answered Nov 19 '22 20:11

blakyris


I find it also a good solution to do this what is an accepted answer but you can also simply redirect the user to the logout route. This has worked for me without any problem in Symfony 4.4

like image 1
Martin Fasani Avatar answered Nov 19 '22 20:11

Martin Fasani