src/Controller/InscriptionController.php line 39

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use App\Entity\Card;
  4. use App\Entity\PlanityRewardCode;
  5. use App\Entity\User;
  6. use App\Service\EmailService;
  7. use App\Service\QrcodeService;
  8. use Doctrine\ORM\EntityManagerInterface;
  9. use Psr\Log\LoggerInterface;
  10. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  11. use Symfony\Component\HttpFoundation\JsonResponse;
  12. use Symfony\Component\HttpFoundation\Request;
  13. use Symfony\Component\HttpFoundation\Response;
  14. use Symfony\Component\HttpFoundation\Session\SessionInterface;
  15. use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
  16. use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
  17. use Symfony\Component\Routing\Annotation\Route;
  18. use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
  19. use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
  20. use Symfony\Component\Validator\Context\ExecutionContextInterface;
  21. use Symfony\Component\Validator\Validator\ValidatorInterface;
  22. use Symfony\Component\Validator\Constraints as Assert;
  23. class InscriptionController extends AbstractController
  24. {
  25.     public function __construct(
  26.         private readonly EntityManagerInterface $entityManager,
  27.         private readonly QrcodeService $qrcodeService,
  28.         private readonly EmailService $emailService,
  29.         private readonly TokenStorageInterface $tokenStorage,
  30.         private readonly ValidatorInterface $validator,
  31.         private readonly LoggerInterface $logger
  32.     ) {
  33.     }
  34.     #[Route('/inscription'name'inscription')]
  35.     public function index(): Response
  36.     {
  37.         return $this->render('inscription/inscription.html.twig', [
  38.             'controller_name' => 'InscriptionController',
  39.         ]);
  40.     }
  41.     #[Route(path'/api/inscription'name'api_register'options: ["expose" => true], methods: ["POST"])]
  42.     public function apiInscription(Request $requestUserPasswordHasherInterface $passwordEncoder)
  43.     {
  44.         try {
  45.             $submittedToken $request->request->get('_csrf_token');
  46.             if (!$this->isCsrfTokenValid('register'$submittedToken)) {
  47.                 return new JsonResponse(['message' => 'Token CSRF invalide'], Response::HTTP_FORBIDDEN);
  48.             }
  49.             $data $request->request->all();
  50.             // Validation améliorée
  51.             $constraints = new Assert\Collection(
  52.                 [
  53.                     'fields' => [
  54.                         '_csrf_token' => new Assert\NotBlank(),
  55.                         'email' => [
  56.                             new Assert\NotBlank(['message' => 'L\'email est obligatoire']),
  57.                             new Assert\Email(['message' => 'L\'email n\'est pas valide']),
  58.                             new Assert\Length(['max' => 180])
  59.                         ],
  60.                         'password' => [
  61.                             new Assert\NotBlank(['message' => 'Le mot de passe est obligatoire']),
  62.                             new Assert\Length([
  63.                                 'min' => 8,
  64.                                 'minMessage' => 'Le mot de passe doit contenir au moins {{ limit }} caractères'
  65.                             ])
  66.                         ],
  67.                         'confirm_password' => [
  68.                             new Assert\NotBlank(),
  69.                             new Assert\EqualTo([
  70.                                 'propertyPath' => 'password',
  71.                                 'message' => 'Les mots de passe ne correspondent pas'
  72.                             ])
  73.                         ],
  74.                         'prenom' => [
  75.                             new Assert\NotBlank(['message' => 'Le prénom est obligatoire']),
  76.                             new Assert\Length(['min' => 2'max' => 50])
  77.                         ],
  78.                         'nom' => [
  79.                             new Assert\NotBlank(['message' => 'Le nom est obligatoire']),
  80.                             new Assert\Length(['min' => 2'max' => 50])
  81.                         ],
  82.                         'telephone' => [
  83.                             new Assert\NotBlank(['message' => 'Le téléphone est obligatoire']),
  84.                             new Assert\Regex([
  85.                                 'pattern' => '/^0[1-9][0-9]{8}$/',
  86.                                 'message' => 'Le numéro de téléphone doit commencer par 0 et contenir 10 chiffres'
  87.                             ])
  88.                         ],
  89.                         'birthdate' => [
  90.                             new Assert\NotBlank(['message' => 'La date de naissance est obligatoire']),
  91.                             new Assert\Date(['message' => 'Date de naissance invalide'])
  92.                         ],
  93.                         'promo_code' => new Assert\Optional([
  94.                             new Assert\Type(['type' => 'string'])
  95.                         ])
  96.                     ],
  97.                     'allowExtraFields' => true,
  98.                     'groups' => ['Default']
  99.                 ]
  100.             );
  101.             $violations $this->validator->validate($data$constraints);
  102.             if (count($violations) > 0) {
  103.                 $errors = [];
  104.                 foreach ($violations as $violation) {
  105.                     $errors[$violation->getPropertyPath()] = $violation->getMessage();
  106.                 }
  107.                 return new JsonResponse([
  108.                     'message' => 'Erreurs de validation',
  109.                     'errors' => $errors
  110.                 ], Response::HTTP_BAD_REQUEST);
  111.             }
  112.             // Vérification email unique
  113.             $existingUser $this->entityManager->getRepository(User::class)->findOneBy(['email' => $data['email']]);
  114.             if ($existingUser) {
  115.                 return new JsonResponse(['message' => "Cette adresse email est déjà utilisée"], Response::HTTP_CONFLICT);
  116.             }
  117.             // Création de l'utilisateur
  118.             $user = new User();
  119.             $user->setEmail(strtolower(trim($data['email'])));
  120.             $user->setPhone($data['telephone']);
  121.             $user->setFirstname(ucfirst(strtolower(trim($data['prenom']))));
  122.             $user->setLastname(ucfirst(strtolower(trim($data['nom']))));
  123.             $user->setBirthdate(new \DateTime($data['birthdate']));
  124.             $user->setSlug(uniqid());
  125.             $user->setRoles(['ROLE_USER']);
  126.             // Points de base
  127.             $points 20;
  128.             // Vérification du code promo s'il existe
  129.             if (!empty($data['promo_code'])) {
  130.                 $rewardCode $this->entityManager->getRepository(PlanityRewardCode::class)
  131.                     ->findOneBy([
  132.                         'code' => $data['promo_code'],
  133.                         'planityEmail' => $user->getEmail(),
  134.                         'isUsed' => false
  135.                     ]);
  136.                 if ($rewardCode && $rewardCode->isValid()) {
  137.                     $points += $rewardCode->getValue();
  138.                     $rewardCode->setIsUsed(true);
  139.                     $this->entityManager->persist($rewardCode);
  140.                 }
  141.             }
  142.             // Hashage du mot de passe
  143.             $encodedPassword $passwordEncoder->hashPassword($user$data['password']);
  144.             $user->setPassword($encodedPassword);
  145.             $this->entityManager->persist($user);
  146.             $this->entityManager->flush();
  147.             // Création de la carte de fidélité
  148.             $QrCode $this->qrcodeService->generateQrCode($user);
  149.             $card = new Card();
  150.             $card->setUser($user);
  151.             $card->setQrCodeImage($QrCode);
  152.             $card->setPoints($points);
  153.             $this->entityManager->persist($card);
  154.             $this->entityManager->flush();
  155.             // Email et connexion
  156.             $this->emailService->sendBienvenueEmail($user->getFirstname() . ', Bienvenue chez IMMY BEAUTY !'$user);
  157.             $token = new UsernamePasswordToken($user'main'$user->getRoles());
  158.             $this->tokenStorage->setToken($token);
  159.             $request->getSession()->set('_security_main'serialize($token));
  160.             return new JsonResponse([
  161.                 'success' => true,
  162.                 'message' => 'Inscription réussie ! Vous êtes maintenant connecté.',
  163.                 'redirect' => $this->generateUrl('app_fidelite')
  164.             ], Response::HTTP_CREATED);
  165.         } catch (\Exception $e) {
  166.             $this->logger->error('Erreur inscription : ' $e->getMessage());
  167.             return new JsonResponse([
  168.                 'success' => false,
  169.                 'message' => 'Une erreur est survenue lors de l\'inscription. Veuillez réessayer.',
  170.                 'debug' => $e->getMessage() // À retirer en production
  171.             ], Response::HTTP_INTERNAL_SERVER_ERROR);
  172.         }
  173.     }
  174.     #[Route('/verify-promo-code'name'verify_promo_code'methods: ['POST'])]
  175.     public function verifyCode(Request $request): JsonResponse
  176.     {
  177.         // Validation CSRF
  178.         if (!$this->isCsrfTokenValid('promo_verify'$request->request->get('_token'))) {
  179.             return $this->json([
  180.                 'valid' => false,
  181.                 'message' => 'Une erreur est survenue'
  182.             ], 403);
  183.         }
  184.         $code trim($request->request->get('code'));
  185.         $email trim(strtolower($request->request->get('email')));
  186.         // Validation basique
  187.         if (!$code || !$email || !filter_var($emailFILTER_VALIDATE_EMAIL)) {
  188.             return $this->json([
  189.                 'valid' => false,
  190.                 'message' => 'Veuillez entrer un email valide et un code'
  191.             ], 400);
  192.         }
  193.         // Vérification du code
  194.         $rewardCode $this->entityManager->getRepository(PlanityRewardCode::class)
  195.             ->findOneBy([
  196.                 'code' => $code,
  197.                 'planityEmail' => $email,
  198.                 'isUsed' => false
  199.             ]);
  200.         if (!$rewardCode) {
  201.             return $this->json([
  202.                 'valid' => false,
  203.                 'message' => 'Code invalide ou expiré'
  204.             ], 400);
  205.         }
  206.         if (!$rewardCode->isValid()) {
  207.             return $this->json([
  208.                 'valid' => false,
  209.                 'message' => 'Code invalide ou expiré'
  210.             ], 400);
  211.         }
  212.         return $this->json([
  213.             'valid' => true,
  214.             'points' => $rewardCode->getValue(),
  215.             'message' => sprintf('Code valide ! %d points seront crédités à la création de votre compte'$rewardCode->getValue())
  216.         ]);
  217.     }
  218. }