diff --git a/src/Controller/RegistrationController.php b/src/Controller/RegistrationController.php new file mode 100644 index 0000000..84c4b0d --- /dev/null +++ b/src/Controller/RegistrationController.php @@ -0,0 +1,49 @@ +createForm(RegistrationFormType::class, $user); + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + // encode the plain password + $user->setPassword( + $userPasswordHasher->hashPassword( + $user, + $form->get('plainPassword')->getData() + ) + ); + + $entityManager->persist($user); + $entityManager->flush(); + // do anything else you need here, like send an email + + return $userAuthenticator->authenticateUser( + $user, + $authenticator, + $request + ); + } + + return $this->render('registration/register.html.twig', [ + 'registrationForm' => $form->createView(), + ]); + } +} diff --git a/src/Entity/User.php b/src/Entity/User.php index 197abcc..52342f1 100644 --- a/src/Entity/User.php +++ b/src/Entity/User.php @@ -4,10 +4,12 @@ namespace App\Entity; use App\Repository\UserRepository; use Doctrine\ORM\Mapping as ORM; +use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface; use Symfony\Component\Security\Core\User\UserInterface; #[ORM\Entity(repositoryClass: UserRepository::class)] +#[UniqueEntity(fields: ['username'], message: 'There is already an account with this username')] class User implements UserInterface, PasswordAuthenticatedUserInterface { #[ORM\Id] diff --git a/src/Form/RegistrationFormType.php b/src/Form/RegistrationFormType.php new file mode 100644 index 0000000..223e07f --- /dev/null +++ b/src/Form/RegistrationFormType.php @@ -0,0 +1,55 @@ +add('username') + ->add('agreeTerms', CheckboxType::class, [ + 'mapped' => false, + 'constraints' => [ + new IsTrue([ + 'message' => 'You should agree to our terms.', + ]), + ], + ]) + ->add('plainPassword', PasswordType::class, [ + // instead of being set onto the object directly, + // this is read and encoded in the controller + 'mapped' => false, + 'attr' => ['autocomplete' => 'new-password'], + 'constraints' => [ + new NotBlank([ + 'message' => 'Please enter a password', + ]), + new Length([ + 'min' => 6, + 'minMessage' => 'Your password should be at least {{ limit }} characters', + // max length allowed by Symfony for security reasons + 'max' => 4096, + ]), + ], + ]) + ; + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults([ + 'data_class' => User::class, + ]); + } +} diff --git a/src/Security/Authenticator.php b/src/Security/Authenticator.php index f284f09..bfe37e2 100644 --- a/src/Security/Authenticator.php +++ b/src/Security/Authenticator.php @@ -49,8 +49,7 @@ class Authenticator extends AbstractLoginFormAuthenticator } // For example: - // return new RedirectResponse($this->urlGenerator->generate('some_route')); - throw new \Exception('TODO: provide a valid redirect inside '.__FILE__); + return new RedirectResponse($this->urlGenerator->generate('index')); } protected function getLoginUrl(Request $request): string diff --git a/templates/registration/register.html.twig b/templates/registration/register.html.twig new file mode 100644 index 0000000..c5283d7 --- /dev/null +++ b/templates/registration/register.html.twig @@ -0,0 +1,19 @@ +{% extends 'base.html.twig' %} + +{% block title %}Register{% endblock %} + +{% block body %} +

Register

+ + {{ form_errors(registrationForm) }} + + {{ form_start(registrationForm) }} + {{ form_row(registrationForm.username) }} + {{ form_row(registrationForm.plainPassword, { + label: 'Password' + }) }} + {{ form_row(registrationForm.agreeTerms) }} + + + {{ form_end(registrationForm) }} +{% endblock %}