From 9783fe66ff93bdce70edd170799ab56cdb5b0da3 Mon Sep 17 00:00:00 2001 From: Olivier PARPAILLON Date: Tue, 19 Nov 2024 10:34:34 +0100 Subject: [PATCH] registration form --- .idea/php.xml | 1 + .idea/sortir.iml | 1 + composer.json | 1 + composer.lock | 48 ++++++++++++- config/bundles.php | 1 + config/packages/security.yaml | 2 + src/Controller/RegistrationController.php | 42 ++++++++++++ src/Entity/Participant.php | 82 +++++++++++++++------- src/Form/RegistrationFormType.php | 83 +++++++++++++++++++++++ src/Repository/UserRepository.php | 60 ---------------- symfony.lock | 3 + templates/registration/register.html.twig | 27 ++++++++ 12 files changed, 264 insertions(+), 87 deletions(-) create mode 100644 src/Controller/RegistrationController.php create mode 100644 src/Form/RegistrationFormType.php delete mode 100644 src/Repository/UserRepository.php create mode 100644 templates/registration/register.html.twig diff --git a/.idea/php.xml b/.idea/php.xml index 2f80302..3bc3bf6 100644 --- a/.idea/php.xml +++ b/.idea/php.xml @@ -144,6 +144,7 @@ + diff --git a/.idea/sortir.iml b/.idea/sortir.iml index ac01b78..c0db0d2 100644 --- a/.idea/sortir.iml +++ b/.idea/sortir.iml @@ -136,6 +136,7 @@ + diff --git a/composer.json b/composer.json index 14da7ec..d81dbac 100644 --- a/composer.json +++ b/composer.json @@ -44,6 +44,7 @@ "symfony/web-link": "6.4.*", "symfony/webpack-encore-bundle": "^2.2", "symfony/yaml": "6.4.*", + "symfonycasts/verify-email-bundle": "^1.17", "twig/extra-bundle": "^2.12|^3.0", "twig/twig": "^2.12|^3.0" }, diff --git a/composer.lock b/composer.lock index f4fb62a..8ce70f1 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "33bcc2038360ba02bb2a0f01f9a1bf9a", + "content-hash": "12d1d380814a0606ceb716bdf895138d", "packages": [ { "name": "composer/semver", @@ -7509,6 +7509,52 @@ ], "time": "2024-09-25T14:18:03+00:00" }, + { + "name": "symfonycasts/verify-email-bundle", + "version": "v1.17.2", + "source": { + "type": "git", + "url": "https://github.com/SymfonyCasts/verify-email-bundle.git", + "reference": "05d47360e423cd8cb6cde639972abefcf7aac7f0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/SymfonyCasts/verify-email-bundle/zipball/05d47360e423cd8cb6cde639972abefcf7aac7f0", + "reference": "05d47360e423cd8cb6cde639972abefcf7aac7f0", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": ">=8.1", + "symfony/config": "^5.4 | ^6.0 | ^7.0", + "symfony/dependency-injection": "^5.4 | ^6.0 | ^7.0", + "symfony/deprecation-contracts": "^2.2 | ^3.0", + "symfony/http-kernel": "^5.4 | ^6.0 | ^7.0", + "symfony/routing": "^5.4 | ^6.0 | ^7.0" + }, + "require-dev": { + "doctrine/orm": "^2.7", + "doctrine/persistence": "^2.0", + "symfony/framework-bundle": "^5.4 | ^6.0 | ^7.0", + "symfony/phpunit-bridge": "^5.4 | ^6.0 | ^7.0" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "SymfonyCasts\\Bundle\\VerifyEmail\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Simple, stylish Email Verification for Symfony", + "support": { + "issues": "https://github.com/SymfonyCasts/verify-email-bundle/issues", + "source": "https://github.com/SymfonyCasts/verify-email-bundle/tree/v1.17.2" + }, + "time": "2024-10-22T11:14:17+00:00" + }, { "name": "twig/extra-bundle", "version": "v3.15.0", diff --git a/config/bundles.php b/config/bundles.php index ad50351..2476b22 100644 --- a/config/bundles.php +++ b/config/bundles.php @@ -13,4 +13,5 @@ return [ Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true], Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true], Symfony\WebpackEncoreBundle\WebpackEncoreBundle::class => ['all' => true], + SymfonyCasts\Bundle\VerifyEmail\SymfonyCastsVerifyEmailBundle::class => ['all' => true], ]; diff --git a/config/packages/security.yaml b/config/packages/security.yaml index fbfb8ed..8b052ba 100644 --- a/config/packages/security.yaml +++ b/config/packages/security.yaml @@ -9,6 +9,8 @@ security: entity: class: App\Entity\User property: email + # used to reload user from session & other features (e.g. switch_user) + # used to reload user from session & other features (e.g. switch_user) firewalls: dev: pattern: ^/(_(profiler|wdt)|css|images|js)/ diff --git a/src/Controller/RegistrationController.php b/src/Controller/RegistrationController.php new file mode 100644 index 0000000..3b24f86 --- /dev/null +++ b/src/Controller/RegistrationController.php @@ -0,0 +1,42 @@ +createForm(RegistrationFormType::class, $user); + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + /** @var string $plainPassword */ + $plainPassword = $form->get('plainPassword')->getData(); + + // encode the plain password + $user->setPassword($userPasswordHasher->hashPassword($user, $plainPassword)); + + $entityManager->persist($user); + $entityManager->flush(); + + // do anything else you need here, like send an email + + return $this->redirectToRoute('home'); + } + + return $this->render('registration/register.html.twig', [ + 'registrationForm' => $form, + ]); + } +} diff --git a/src/Entity/Participant.php b/src/Entity/Participant.php index 5218db9..f5e8b7e 100644 --- a/src/Entity/Participant.php +++ b/src/Entity/Participant.php @@ -6,10 +6,13 @@ use App\Repository\ParticipantRepository; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; +use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface; +use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Uid\Uuid; #[ORM\Entity(repositoryClass: ParticipantRepository::class)] -class Participant +#[ORM\UniqueConstraint(name: 'UNIQ_IDENTIFIER_EMAIL', fields: ['email'])] +class Participant implements UserInterface, PasswordAuthenticatedUserInterface { #[ORM\Id] #[ORM\Column(type: 'uuid', unique: true)] @@ -26,8 +29,8 @@ class Participant #[ORM\Column(length: 255, nullable: true)] private ?string $telephone = null; - #[ORM\Column(length: 255, nullable: true)] - private ?string $mail = null; + #[ORM\Column(length: 255)] + private ?string $email = null; #[ORM\Column] private ?bool $administrateur = null; @@ -42,7 +45,7 @@ class Participant private ?string $password = null; #[ORM\ManyToOne(targetEntity: Site::class, inversedBy: 'participants')] - #[ORM\JoinColumn(name: 'site_id', referencedColumnName: 'idSite', nullable: false)] + #[ORM\JoinColumn(name: 'site_id', referencedColumnName: 'idSite', nullable: true)] private ?Site $site = null; /** @@ -98,14 +101,48 @@ class Participant return $this; } - public function getMail(): ?string + public function getEmail(): ?string { - return $this->mail; + return $this->email; } - public function setMail(?string $mail): self + public function setEmail(string $email): static { - $this->mail = $mail; + $this->email = $email; + + return $this; + } + + /** + * A visual identifier that represents this user. + * + * @see UserInterface + */ + public function getUserIdentifier(): string + { + return (string) $this->email; + } + + /** + * @see UserInterface + * + * @return list + */ + public function getRoles(): array + { + $roles = $this->roles; + // guarantee every user at least has ROLE_USER + $roles[] = 'ROLE_USER'; + + return array_unique($roles); + } + + /** + * @param list $roles + */ + public function setRoles(array $roles): static + { + $this->roles = $roles; return $this; } @@ -134,37 +171,30 @@ class Participant return $this; } - public function getRoles(): array - { - $roles = $this->roles; - // Garantit que chaque utilisateur a au moins le rôle ROLE_USER - $roles[] = 'ROLE_USER'; - - return array_unique($roles); - } - /** - * @param list $roles + * @see PasswordAuthenticatedUserInterface */ - public function setRoles(array $roles): self - { - $this->roles = $roles; - - return $this; - } - public function getPassword(): ?string { return $this->password; } - public function setPassword(string $password): self + public function setPassword(string $password): static { $this->password = $password; return $this; } + /** + * @see UserInterface + */ + public function eraseCredentials(): void + { + // If you store any temporary, sensitive data on the user, clear it here + // $this->plainPassword = null; + } + public function getSite(): ?Site { return $this->site; diff --git a/src/Form/RegistrationFormType.php b/src/Form/RegistrationFormType.php new file mode 100644 index 0000000..6c92c0b --- /dev/null +++ b/src/Form/RegistrationFormType.php @@ -0,0 +1,83 @@ +add('email', EmailType::class, [ + 'label' => 'Email', + 'label_attr' => ['class' => 'text-gray-700 font-bold'], + 'attr' => [ + 'class' => 'w-full mb-4 px-4 py-2 border-2 border-gray-300 rounded-lg focus:outline-none focus:border-blue-500', + 'placeholder' => 'Adresse e-mail', + ], + 'constraints' => [ + new NotBlank([ + 'message' => 'Please enter a password', + ]), + ], + ]) +// ->add('username', TextType::class, [ +// 'label' => 'Nom d\'utilisateur', +// 'label_attr' => ['class' => 'text-gray-700 font-bold'], +// 'attr' => [ +// 'class' => 'w-full mb-4 px-4 py-2 border-2 border-gray-300 rounded-lg focus:outline-none focus:border-blue-500', +// 'placeholder' => 'Nom d\'utilisateur', +// ], +// ]) +// ->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, + 'label' => 'Mot de passe', + 'label_attr' => ['class' => 'text-gray-700 font-bold'], + 'attr' => [ + 'autocomplete' => 'new-password', + 'class' => 'w-full mb-4 px-4 py-2 border-2 border-gray-300 rounded-lg focus:outline-none focus:border-blue-500', + 'placeholder' => 'Mot de passe', + ], + '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' => Participant::class, + ]); + } +} \ No newline at end of file diff --git a/src/Repository/UserRepository.php b/src/Repository/UserRepository.php deleted file mode 100644 index 4f2804e..0000000 --- a/src/Repository/UserRepository.php +++ /dev/null @@ -1,60 +0,0 @@ - - */ -class UserRepository extends ServiceEntityRepository implements PasswordUpgraderInterface -{ - public function __construct(ManagerRegistry $registry) - { - parent::__construct($registry, User::class); - } - - /** - * Used to upgrade (rehash) the user's password automatically over time. - */ - public function upgradePassword(PasswordAuthenticatedUserInterface $user, string $newHashedPassword): void - { - if (!$user instanceof User) { - throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', $user::class)); - } - - $user->setPassword($newHashedPassword); - $this->getEntityManager()->persist($user); - $this->getEntityManager()->flush(); - } - - // /** - // * @return User[] Returns an array of User objects - // */ - // public function findByExampleField($value): array - // { - // return $this->createQueryBuilder('u') - // ->andWhere('u.exampleField = :val') - // ->setParameter('val', $value) - // ->orderBy('u.id', 'ASC') - // ->setMaxResults(10) - // ->getQuery() - // ->getResult() - // ; - // } - - // public function findOneBySomeField($value): ?User - // { - // return $this->createQueryBuilder('u') - // ->andWhere('u.exampleField = :val') - // ->setParameter('val', $value) - // ->getQuery() - // ->getOneOrNullResult() - // ; - // } -} diff --git a/symfony.lock b/symfony.lock index ef67e85..8310ae4 100644 --- a/symfony.lock +++ b/symfony.lock @@ -301,6 +301,9 @@ "./webpack.config.js" ] }, + "symfonycasts/verify-email-bundle": { + "version": "v1.17.2" + }, "twig/extra-bundle": { "version": "v3.15.0" } diff --git a/templates/registration/register.html.twig b/templates/registration/register.html.twig new file mode 100644 index 0000000..5cd77ec --- /dev/null +++ b/templates/registration/register.html.twig @@ -0,0 +1,27 @@ +{% extends 'main/base.html.twig' %} +{% block head %} + + + Sortie + {% block stylesheets %} + {{ encore_entry_link_tags('app') }} + {% endblock %} + +{% endblock %} + +{% block content %} +
+
+

Sortir !

+

Bienvenue sur notre application web référencant tout type d'évènements à travers le monde. N'hésitez pas à vous inscrire sur notre plateforme et y invitez vos amis afins de participer à des évènements simplement et qui vous conviennent !

+
+
+

S'inscrire

+ {{ form_start(registrationForm) }} + {{ form_row(registrationForm.email) }} + {{ form_row(registrationForm.plainPassword) }} + + {{ form_end(registrationForm) }} +
+
+{% endblock %} \ No newline at end of file