<?php
namespace App\Controller;
use App\Entity\User;
use App\Form\RegistrationFormType;
use App\Security\EmailVerifier;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Mime\Address;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Symfony\Component\Routing\Annotation\Route;
use SymfonyCasts\Bundle\VerifyEmail\Exception\VerifyEmailExceptionInterface;
use App\Entity\Prescriber;
use App\Form\PrescriberRegistrationType;
use App\Service\PrescriberCodeGeneratorService;
use App\Service\RPPSValidatorService;
use App\Service\SIRENValidatorService;
use Symfony\Component\Form\FormError;
use App\Service\PrescriberService;
use App\Service\EmailService;
use App\Repository\PrescriberActivityStatusRepository;
use App\Repository\BillingCenterRepository;
use Symfony\Component\Mailer\MailerInterface;
class RegistrationController extends AbstractController
{
private const DEFAULT_BILLING_SLUG = 'BIONOPS-SA';
private EmailVerifier $emailVerifier;
public function __construct(
EmailVerifier $emailVerifier,
private readonly PrescriberCodeGeneratorService $prescriberCodeGenerator,
private readonly PrescriberService $prescriberService,
private readonly RPPSValidatorService $rppsValidator,
private readonly SIRENValidatorService $sirenValidator,
private readonly UserPasswordHasherInterface $userPasswordHasher,
private readonly EntityManagerInterface $entityManager,
private readonly PrescriberActivityStatusRepository $activityStatusRepository,
private readonly BillingCenterRepository $billingCenterRepository,
private readonly EmailService $emailService,
private readonly MailerInterface $mailer
) {
$this->emailVerifier = $emailVerifier;
}
/**
* Action pour l'inscription complète multi-étapes (Originale)
*/
#[Route('/registration/prescriber', name: 'app_prescriber_register', methods: ['GET', 'POST'])]
public function registerPrescriber(Request $request): Response
{
$prescriber = new Prescriber();
// Définir le centre de profit par défaut
$billingCenter = $this->billingCenterRepository->findOneBy(['slug' => self::DEFAULT_BILLING_SLUG]);
if ($billingCenter) {
$prescriber->setBillingCenter($billingCenter);
}
$form = $this->createForm(PrescriberRegistrationType::class, $prescriber);
$form->handleRequest($request);
$activeTab = 'personal'; // Onglet par défaut
if ($form->isSubmitted()) {
if ($form->isValid()) {
// Vérifier SIREN/RPPS ici mais ne pas bloquer
$rppsNumberField = $form->get('rppsNumber');
$sirenNumberField = $form->get('sirenNumber');
$rppsNumber = $rppsNumberField->getData();
$sirenNumber = $sirenNumberField->getData();
// $hasServiceError = false; // Plus utile pour bloquer
if ($rppsNumber && !$this->rppsValidator->isValid($rppsNumber)) {
// Commenté : Ne pas ajouter d'erreur bloquante ici
// $rppsNumberField->addError(new FormError('Le numéro RPPS fourni n\'est pas valide.'));
// $hasServiceError = true;
$this->addFlash('warning', 'Le numéro RPPS fourni semble invalide mais l\'inscription peut continuer.'); // Optionnel
}
if ($sirenNumber && !$this->sirenValidator->isValid($sirenNumber)) {
// Commenté : Ne pas ajouter d'erreur bloquante ici
// $sirenNumberField->addError(new FormError('Le numéro SIREN fourni n\'est pas valide.'));
// $hasServiceError = true;
$this->addFlash('warning', 'Le numéro SIREN fourni semble invalide mais l\'inscription peut continuer.'); // Optionnel
}
// On continue la création même si $hasServiceError serait true
// if (!$hasServiceError) { // Condition retirée
// ... (logique de création de compte inchangée)
$baseUsername = strtolower($prescriber->getFirstname() . '.' . $prescriber->getLastname());
$username = $baseUsername;
if ($this->entityManager->getRepository(Prescriber::class)->findOneBy(['username' => $username])) {
do {
$randomNumber = str_pad(random_int(0, 999), 3, '0', STR_PAD_LEFT);
$username = $baseUsername . '.' . $randomNumber;
} while ($this->entityManager->getRepository(Prescriber::class)->findOneBy(['username' => $username]));
}
$prescriber->setUsername($username);
$prescriber->setPassword($this->userPasswordHasher->hashPassword($prescriber, $form->get('plainPassword')->getData()));
$prescriber->setApproved(false);
$prescriber->setPointCoefficient(0.15);
$prescriberCode = $this->prescriberCodeGenerator->generatePrescriberCode($prescriber);
$prescriber->setPrescriberCode($prescriberCode);
// Définir la date de création
$prescriber->setCreatedAt(new \DateTimeImmutable());
// Récupérer et définir le statut d'activité 'new'
$newStatus = $this->activityStatusRepository->findOneBy(['slug' => 'new']);
if (!$newStatus) {
throw new \RuntimeException('Statut \'new\' introuvable pour PrescriberActivityStatus.');
}
$prescriber->setActivityStatus($newStatus);
// Utiliser PrescriberService pour générer l'extranetCode unique
$prescriber->setExtranetCode($this->prescriberService->getUniquePrescriberCode());
// Définir le créateur comme étant le prescripteur lui-même
$prescriber->setCreatedBy($prescriber);
$this->entityManager->persist($prescriber);
$this->entityManager->flush();
// Envoi email informant que la demande va être traitée
if ($this->emailService->isEmailSendingAllowedTo('app.allow_send_emails_prospect_new')) {
$data = [
'prescriber' => $prescriber,
];
$email = $this->emailService->sendEmail(
$this->emailService->getEmailSender(),
$prescriber->getEmail(),
'Demande d\'inscription reçue',
'emails/prescriber_registration_received.html.twig',
$data,
);
if ($email) {
$this->mailer->send($email);
}
}
$this->addFlash('success', 'Votre demande d\'inscription a été enregistrée avec succès. Un email de confirmation vous a été envoyé.');
return $this->redirectToRoute('app_login');
// } else { // Partie else retirée
// Erreur service détectée après form->isValid(), définir l'onglet actif sur pro
// $activeTab = 'professional'; // Plus nécessaire de changer d'onglet ici
// }
} else {
// Le formulaire est invalide (contraintes Symfony), déterminer l'onglet
$activeTab = $this->determineActiveTabOnErrorMultiStep($form);
}
}
return $this->render('registration/prescriber_register.html.twig', [
'registrationForm' => $form->createView(),
'activeTab' => $activeTab,
]);
}
/**
* Helper pour déterminer l'onglet actif en cas d'erreur sur le formulaire multi-étapes
*/
private function determineActiveTabOnErrorMultiStep($form): string
{
// Ordre des onglets: personal -> professional -> address
// Vérifier erreurs étape 1 (personal)
if (!$form->get('firstname')->isValid() || !$form->get('lastname')->isValid() || !$form->get('email')->isValid() || !$form->get('phone')->isValid() || !$form->get('plainPassword')->isValid()) {
return 'personal';
}
// Vérifier erreurs étape 2 (professional)
if (!$form->get('rppsNumber')->isValid() || !$form->get('sirenNumber')->isValid() || !$form->get('mainSpeciality')->isValid()) {
return 'professional';
}
// Vérifier erreurs étape 3 (address)
if (!$form->get('address')->isValid() || !$form->get('postalCode')->isValid() || !$form->get('city')->isValid() || !$form->get('country')->isValid() || ($form->has('agreeTerms') && !$form->get('agreeTerms')->isValid())) {
return 'address';
}
// Défaut
return 'personal';
}
#[Route('/verify/email', name: 'app_verify_email')]
public function verifyUserEmail(Request $request): Response
{
$this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY');
// validate email confirmation link, sets User::isVerified=true and persists
try {
$this->emailVerifier->handleEmailConfirmation($request, $this->getUser());
} catch (VerifyEmailExceptionInterface $exception) {
$this->addFlash('verify_email_error', $exception->getReason());
return $this->redirectToRoute('app_register');
}
// @TODO Change the redirect on success and handle or remove the flash message in your templates
$this->addFlash('success', 'Your email address has been verified.');
return $this->redirectToRoute('app_register');
}
}