<?php
namespace App\Controller\Auth\App;
use App\Entity\App\User;
use App\Event\Auth\UserCreatedEvent;
use App\Event\Auth\UserResetEvent;
use App\Form\App\Security\RegistrationFormType;
use App\Service\Auth\UserResetNotifier;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
use Symfony\Component\Form\FormError;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Constraints\Email;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
* Class RegistrationController
*
* @package App\Controller
*
* @Route("/")
*/
class AccountManagementController extends AbstractController
{
/**
* @Route("/register", name="register")
* @Route("/{_locale}/register", name="register", requirements={"_locale": "\w{2}"}, methods={"GET", "POST"})
*/
public function register(
Request $request,
EventDispatcherInterface $dispatcher,
UserResetNotifier $notifier
): Response
{
if (!$request->attributes->get('_locale')) {
return $this->redirectToRoute('register', ['_locale' => $request->getDefaultLocale()]);
}
$user = new User();
$form = $this->createForm(RegistrationFormType::class, $user)->handleRequest($request);
if (!$form->isSubmitted() || !$form->isValid()) {
return $this->render('Auth/Registration/register.html.twig', [
'form' => $form->createView(),
]);
}
$dispatcher->dispatch(new UserCreatedEvent($user, $notifier));
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($user);
$entityManager->flush();
return $this->redirectToRoute('login');
}
/**
* @Route("/{_locale}/verify_email/{token}", name="verify_email", requirements={"_locale": "\w{2}"}, methods={"GET"})
*/
public function verifyEmail(string $token, TranslatorInterface $translator): Response
{
$user = $this->getDoctrine()->getRepository(User::class)->findByToken($token);
if (!$user) {
$this->addFlash('error', $translator->trans(
'registration.invalid_token',
[],
'Auth'
));
return $this->redirectToRoute('login');
}
$user->setEnabled(true)->setConfirmationToken();
$em = $this->getDoctrine()->getManager();
$em->persist($user);
$em->flush();
$this->addFlash('success', $translator->trans(
'registration.confirmed',
['%username%' => $user->getFullName()],
'Auth'
));
return $this->redirectToRoute('login');
}
/**
*
* @Route("/reset_password", name="reset_password")
* @Route("/{_locale}/reset_password", name="reset_password", requirements={"_locale": "\w{2}"}, methods={"GET", "POST"})
*/
public function resetPassword(
Request $request,
EventDispatcherInterface $dispatcher,
TranslatorInterface $translator,
UserResetNotifier $notifier
): Response {
if (!$request->attributes->get('_locale')) {
return $this->redirectToRoute('reset_password', ['_locale' => $request->getDefaultLocale()]);
}
$form = $this->createResetPasswordForm($request)->handleRequest($request);
$tokenLifetime = $this->getParameter('tokenLifetime');
if ($form->isSubmitted() && $form->isValid()) {
$user = $this->getDoctrine()->getRepository(User::class)->findByEmail($form->getData()['email']);
if (!$user instanceof User){
$form->addError(new FormError($translator->trans('resetting.reset.error', [], 'Auth')));
} elseif ($user->isPasswordRequestNonExpired($tokenLifetime * 3600)) {
$form->addError(
new FormError(
$translator->trans(
'resetting.reset.not_expired_error',
['%tokenLifetime%' => $tokenLifetime],
'Auth'
)
)
);
} else {
$dispatcher->dispatch(new UserResetEvent($user, $notifier));
$em = $this->getDoctrine()->getManager();
$em->persist($user);
$em->flush();
}
}
return $this->render(
'Auth/Resetting/reset.html.twig',
[
'tokenLifetime' => $tokenLifetime,
'user' => $user ?? null,
'form' => $form->createView(),
]
);
}
/**
* Create Reset Password Form
*
* @param Request $request
*
* @return FormInterface
*/
protected function createResetPasswordForm(Request $request): FormInterface
{
return $this->createFormBuilder(
['email' => ''],
[
'method' => 'POST',
'action' => $this->generateUrl('reset_password', ['_locale' => $request->getLocale()])
]
)
->add('email', EmailType::class, [
'constraints' => [
new NotBlank(),
new Email()
]
])
->getForm();
}
/**
* @Route("/reset_password/{token}", name="reset_password_submit")
* @Route("/{_locale}/reset_password/{token}", name="reset_password_submit", requirements={"_locale": "\w{2}"}, methods={"GET", "POST"})
*/
public function newPassword(
Request $request,
TranslatorInterface $translator,
string $token
): Response {
if (!$request->attributes->get('_locale')) {
return $this->redirectToRoute('reset_password', ['_locale' => $request->getDefaultLocale()]);
}
$form = $this->createNewPasswordForm($request)->handleRequest($request);
$tokenLifetime = $this->getParameter('tokenLifetime');
if ($form->isSubmitted() && $form->isValid()) {
$user = $this->getDoctrine()->getRepository(User::class)->findByToken($token);
if (!$user instanceof User) {
$form->addError(new FormError($translator->trans('resetting.reset.error', [], 'Auth')));
} elseif (!$user->isPasswordRequestNonExpired($tokenLifetime * 3600)) {
$form->addError(new FormError($translator->trans('resetting.reset.expired_error', [], 'Auth')));
} else {
$user->setConfirmationToken()->setPasswordRequestedAt();
$em = $this->getDoctrine()->getManager();
$em->persist($user);
$em->flush();
$this->addFlash('success', $translator->trans('resetting.flash.success', [], 'Auth'));
return $this->redirectToRoute('login', ['_locale' => $request->getLocale()]);
}
}
return new Response(
$this->renderView(
'Auth/Resetting/reset.html.twig',
[
'tokenLifetime' => $tokenLifetime,
'form' => $form->createView(),
]
),
$form->getErrors()->count() < 1 ? Response::HTTP_OK : Response::HTTP_BAD_REQUEST
);
}
/**
* Create Reset Password Form
*
* @param Request $request
*
* @return FormInterface
*/
protected function createNewPasswordForm(Request $request): FormInterface
{
return $this->createFormBuilder(
['password' => ''],
[
'method' => 'POST',
'action' => $this->generateUrl(
'reset_password_submit',
[
'_locale' => $request->getLocale(),
'token' => $request->get('token'),
]
)
]
)
->add('password', RepeatedType::class, [
'type' => PasswordType::class,
'constraints' => [
new NotBlank(),
]
])
->getForm();
}
}