UserController
extends AbstractController
in package
Contrôleur du cycle de vie du compte utilisateur grand public.
Il couvre l'inscription protégée par reCAPTCHA v3, la vérification de l'adresse email (par code à saisir
ou par lien signé), la connexion via les fournisseurs OAuth Google et Facebook, la gestion du profil
(photo, informations, changement de mot de passe) et la suppression du compte. À l'inscription, un rôle
ROLE_USER et un abonnement gratuit sont attribués automatiquement, et les créations/modifications de
compte sont tracées via AuditLogger. Aucun préfixe de route ni contrôle d'accès n'est
déclaré au niveau de la classe : les restrictions sont posées méthode par méthode.
Table of Contents
Constants
- RECAPTCHA_THRESHOLD : mixed = 0.5
- Score minimal reCAPTCHA v3 exigé pour accepter une soumission d'inscription.
Properties
- $accountDeletionService : AccountDeletionService
- $auditLogger : AuditLogger
- $emailVerificationService : EmailVerificationService
- $emailVerifier : EmailVerifier
- $entityManager : EntityManagerInterface
- $logger : LoggerInterface
- $mailerService : MailerService
- $subscriptionService : SubscriptionService
Methods
- __construct() : mixed
- connectFacebook() : RedirectResponse
- Démarre le parcours d'authentification OAuth2 auprès de Facebook.
- connectGoogle() : RedirectResponse
- Démarre le parcours d'authentification OAuth2 auprès de Google.
- deleteAccount() : Response
- Supprime le compte de l'utilisateur connecté à sa demande.
- profileUser() : Response
- Affiche la page de profil et traite ses deux formulaires (informations et mot de passe).
- register() : Response
- Affiche le formulaire d'inscription et traite la création d'un compte.
- resendVerificationCode() : Response
- Renvoie un nouveau code de vérification à l'utilisateur en attente (point d'entrée AJAX).
- verifyCode() : Response
- Affiche le formulaire de saisie du code de vérification et traite sa validation.
- verifyUserEmail() : Response
- Valide l'adresse email de l'utilisateur connecté à partir d'un lien de confirmation signé.
- createUser() : void
- Create and persist new user
- handlePasswordChange() : Response
- Handle password change
- handleProfileUpdate() : Response
- Handle profile update
- sendConfirmationEmail() : void
- Send email confirmation
- validateRecaptcha() : array<string, mixed>
- Validate reCAPTCHA submission
Constants
RECAPTCHA_THRESHOLD
Score minimal reCAPTCHA v3 exigé pour accepter une soumission d'inscription.
private
mixed
RECAPTCHA_THRESHOLD
= 0.5
Properties
$accountDeletionService
private
AccountDeletionService
$accountDeletionService
$auditLogger
private
AuditLogger
$auditLogger
$emailVerificationService
private
EmailVerificationService
$emailVerificationService
$emailVerifier
private
EmailVerifier
$emailVerifier
$entityManager
private
EntityManagerInterface
$entityManager
$logger
private
LoggerInterface
$logger
$mailerService
private
MailerService
$mailerService
$subscriptionService
private
SubscriptionService
$subscriptionService
Methods
__construct()
public
__construct(EmailVerifier $emailVerifier, EmailVerificationService $emailVerificationService, EntityManagerInterface $entityManager, LoggerInterface $logger, SubscriptionService $subscriptionService, MailerService $mailerService, AuditLogger $auditLogger, AccountDeletionService $accountDeletionService) : mixed
Parameters
- $emailVerifier : EmailVerifier
-
Gère les liens signés de confirmation d'email (SymfonyCasts VerifyEmail).
- $emailVerificationService : EmailVerificationService
-
Génère, envoie et valide les codes de vérification à usage unique.
- $entityManager : EntityManagerInterface
-
Gestionnaire d'entités Doctrine (chargement et persistance des utilisateurs).
- $logger : LoggerInterface
-
Journalise les erreurs et incidents (inscription, reCAPTCHA, profil, mot de passe).
- $subscriptionService : SubscriptionService
-
Crée l'abonnement gratuit attribué à chaque nouvel inscrit.
- $mailerService : MailerService
-
Fournit l'expéditeur (adresse et nom) utilisé pour les emails transactionnels.
- $auditLogger : AuditLogger
-
Trace dans le journal d'audit les créations et modifications de compte.
- $accountDeletionService : AccountDeletionService
-
Réalise la suppression/anonymisation d'un compte et la déconnexion associée.
connectFacebook()
Démarre le parcours d'authentification OAuth2 auprès de Facebook.
public
connectFacebook(ClientRegistry $clientRegistry) : RedirectResponse
Contrairement à UserController::connectGoogle(), le scope email est explicitement demandé afin
de pouvoir rattacher ou créer le compte local à partir de l'adresse email du profil Facebook.
Route : /connect/facebook (GET), nom connect_facebook_start.
Parameters
- $clientRegistry : ClientRegistry
-
Registre des clients OAuth2 (bundle KnpU).
Attributes
- #[Route]
- '/connect/facebook'
- $name: 'connect_facebook_start'
Return values
RedirectResponse —Redirection vers l'écran d'autorisation Facebook.
connectGoogle()
Démarre le parcours d'authentification OAuth2 auprès de Google.
public
connectGoogle(ClientRegistry $clientRegistry) : RedirectResponse
Redirige vers la page de consentement Google sans demander de scope supplémentaire ; le retour est
traité par l'authenticator configuré pour le client google.
Route : /connect/google (GET), nom connect_google_start.
Parameters
- $clientRegistry : ClientRegistry
-
Registre des clients OAuth2 (bundle KnpU).
Attributes
- #[Route]
- '/connect/google'
- $name: 'connect_google_start'
Return values
RedirectResponse —Redirection vers l'écran d'autorisation Google.
deleteAccount()
Supprime le compte de l'utilisateur connecté à sa demande.
public
deleteAccount(Request $request) : Response
Contrôle d'abord le jeton CSRF delete_account_<id> ; en cas d'invalidité, la suppression est refusée
avec un message flash et un retour au profil. La suppression effective est déléguée à
AccountDeletionService::deleteAccount(), qui anonymise le compte, supprime les
cartes et contacts associés, anonymise les commandes, envoie les emails de confirmation, invalide le
jeton de sécurité (déconnexion) et refuse les comptes administratifs (ROLE_ADMIN, ROLE_SUPPORT,
ROLE_OPERATOR). Toute exception, y compris ce refus, est interceptée et présentée comme une erreur
générique — aucune distinction n'est faite entre un compte protégé et une panne technique.
Route : /delete-account (POST), nom app_user_delete_account. Authentification complète requise
(IS_AUTHENTICATED_FULLY).
Parameters
- $request : Request
-
Requête HTTP contenant le jeton CSRF
_token.
Attributes
- #[IsGranted]
- 'IS_AUTHENTICATED_FULLY'
- #[Route]
- '/delete-account'
- $name: 'app_user_delete_account'
- $methods: ['POST']
Return values
Response —Redirection vers app_home après suppression, vers app_profile si le jeton CSRF
est invalide ou si la suppression échoue.
profileUser()
Affiche la page de profil et traite ses deux formulaires (informations et mot de passe).
public
profileUser(Request $request, UploaderService $uploaderService, UserPasswordHasherInterface $userPasswordHasher) : Response
La page héberge simultanément le formulaire de profil (ProfilUserType) et celui de
changement de mot de passe (ChangePasswordType) ; les deux sont soumis à
handleRequest() et le traitement est aiguillé vers UserController::handleProfileUpdate() ou
UserController::handlePasswordChange() selon celui qui a été envoyé et validé. Le formulaire
de profil est primaire : s'il est soumis et valide, la méthode retourne immédiatement sans évaluer
le second.
Route : /profile-user (GET, POST), nom app_profile. Authentification complète requise
(IS_AUTHENTICATED_FULLY).
Parameters
- $request : Request
-
Requête HTTP courante (données des deux formulaires).
- $uploaderService : UploaderService
-
Gère l'upload de la nouvelle photo de profil.
- $userPasswordHasher : UserPasswordHasherInterface
-
Vérifie le mot de passe actuel et hache le nouveau.
Attributes
- #[IsGranted]
- 'IS_AUTHENTICATED_FULLY'
- #[Route]
- '/profile-user'
- $name: 'app_profile'
Return values
Response —Redirection vers app_dashboard après une mise à jour de profil ou de mot de passe
réussie, sinon la page de profil rendue (admin/user/profile.html.twig).
register()
Affiche le formulaire d'inscription et traite la création d'un compte.
public
register(Request $request, UserPasswordHasherInterface $userPasswordHasher, EntityManagerInterface $entityManager, Recaptcha3Validator $recaptcha3Validator, RecaptchaService $recaptchaService) : Response
À la soumission, le reCAPTCHA v3 est contrôlé en premier via UserController::validateRecaptcha() :
en cas d'échec (absence de réponse, score inférieur au seuil ou erreur), un message flash est ajouté et
l'utilisateur est redirigé vers le formulaire — la validation du formulaire n'est même pas évaluée.
Si le formulaire est valide, le compte est créé et persisté par UserController::createUser()
(hachage du mot de passe, rôle ROLE_USER, journal d'audit, abonnement gratuit), un code de
vérification est envoyé par email et l'identifiant utilisateur est stocké en session sous la clé
pending_verification_user_id avant redirection vers la saisie du code. Toute exception survenant
pendant cette phase est journalisée et convertie en message flash d'erreur avec retour au formulaire.
Route : /inscription (GET, POST), nom app_register.
Parameters
- $request : Request
-
Requête HTTP courante (données du formulaire, session).
- $userPasswordHasher : UserPasswordHasherInterface
-
Service de hachage du mot de passe en clair saisi.
- $entityManager : EntityManagerInterface
-
Gestionnaire d'entités utilisé pour persister le nouvel utilisateur.
- $recaptcha3Validator : Recaptcha3Validator
-
Donne accès à la dernière réponse reCAPTCHA et à son score.
- $recaptchaService : RecaptchaService
-
Fournit la clé publique reCAPTCHA injectée dans le template.
Attributes
- #[Route]
- '/inscription'
- $name: 'app_register'
Return values
Response —Redirection vers app_verify_code en cas de succès, vers app_register en cas
d'échec reCAPTCHA ou d'exception, sinon le formulaire rendu (home/register.html.twig).
resendVerificationCode()
Renvoie un nouveau code de vérification à l'utilisateur en attente (point d'entrée AJAX).
public
resendVerificationCode(Request $request) : Response
Répond toujours en JSON avec un statut HTTP 200 et une clé success booléenne. L'opération échoue
(success à false) si aucune vérification n'est en cours en session, si l'utilisateur est
introuvable ou déjà vérifié, ou si le délai anti-spam de
EmailVerificationService::canResendCode() n'est pas écoulé. Toute exception lors de
l'envoi est journalisée en erreur et renvoyée sous forme de message générique.
Route : /resend-verification-code (POST), nom app_resend_verification_code.
Parameters
- $request : Request
-
Requête HTTP courante, utilisée pour lire
pending_verification_user_iden session.
Attributes
- #[Route]
- '/resend-verification-code'
- $name: 'app_resend_verification_code'
- $methods: ['POST']
Return values
Response —Réponse JSON array{success: bool, message: string}, toujours en HTTP 200.
verifyCode()
Affiche le formulaire de saisie du code de vérification et traite sa validation.
public
verifyCode(Request $request) : Response
L'accès repose sur la clé de session pending_verification_user_id posée lors de l'inscription :
si elle est absente, l'utilisateur est renvoyé vers l'inscription avec un message d'erreur. Si
l'utilisateur référencé n'existe plus ou est déjà vérifié, la clé de session est purgée et une
redirection vers la connexion est effectuée. À la soumission d'un code valide, la clé de session est
supprimée et l'utilisateur est redirigé vers la connexion ; un code invalide ou expiré produit
seulement un message flash d'erreur et le formulaire est réaffiché (aucune limite de tentatives
n'est appliquée ici).
Route : /verify-code (GET, POST), nom app_verify_code. Accessible sans authentification.
Parameters
- $request : Request
-
Requête HTTP courante (session de vérification et code soumis).
Attributes
- #[Route]
- '/verify-code'
- $name: 'app_verify_code'
Return values
Response —Redirection vers app_register ou app_login selon l'état de la vérification,
sinon le formulaire rendu (home/verif_code.html.twig).
verifyUserEmail()
Valide l'adresse email de l'utilisateur connecté à partir d'un lien de confirmation signé.
public
verifyUserEmail(Request $request, TranslatorInterface $translator) : Response
Délègue à EmailVerifier::handleEmailConfirmation() la vérification de la signature et de la
péremption du lien, puis le marquage de l'utilisateur comme vérifié. En cas d'échec, la raison est
journalisée en avertissement, traduite dans le domaine VerifyEmailBundle et exposée via le message
flash verify_email_error, avec redirection vers le formulaire d'inscription.
Route : /verify/email (GET), nom app_verify_email. Authentification complète requise
(IS_AUTHENTICATED_FULLY).
Parameters
- $request : Request
-
Requête HTTP contenant les paramètres signés du lien de confirmation.
- $translator : TranslatorInterface
-
Traduit le motif d'échec renvoyé par le bundle de vérification.
Attributes
- #[IsGranted]
- 'IS_AUTHENTICATED_FULLY'
- #[Route]
- '/verify/email'
- $name: 'app_verify_email'
Return values
Response —Redirection vers app_dashboard en cas de succès, vers app_register en cas d'échec.
createUser()
Create and persist new user
private
createUser(User $user, UserPasswordHasherInterface $userPasswordHasher, FormInterface<string|int, User> $form, EntityManagerInterface $entityManager) : void
Finalise et enregistre un utilisateur nouvellement soumis via le formulaire d'inscription.
Hache le mot de passe en clair issu du champ plainPassword, force le rôle unique ROLE_USER
(les rôles éventuellement présents sur l'entité sont écrasés), persiste puis vide l'unité de travail.
Deux effets de bord suivent l'enregistrement : la création est tracée dans le journal d'audit avec
l'utilisateur lui-même comme acteur, et un abonnement gratuit lui est attribué via
SubscriptionService::createFreeSubscriptionForUser().
Parameters
- $user : User
-
Entité utilisateur hydratée par le formulaire, modifiée sur place.
- $userPasswordHasher : UserPasswordHasherInterface
-
Service de hachage du mot de passe.
- $form : FormInterface<string|int, User>
-
Formulaire d'inscription soumis, source du
plainPassword. - $entityManager : EntityManagerInterface
-
Gestionnaire d'entités utilisé pour la persistance.
handlePasswordChange()
Handle password change
private
handlePasswordChange(User $user, FormInterface<string|int, mixed> $changePasswordForm, UserPasswordHasherInterface $userPasswordHasher) : Response
Vérifie le mot de passe actuel puis applique le nouveau mot de passe.
Si le mot de passe actuel saisi ne correspond pas, un message flash d'avertissement et une erreur de
champ sont ajoutés, et la page de profil est réaffichée immédiatement (un formulaire de profil neuf
est alors recréé pour le rendu, ce qui écarte d'éventuelles saisies non enregistrées). Sinon, le
nouveau mot de passe est haché, l'indicateur mustChangePassword est remis à false — ce qui lève
l'obligation de changement imposée notamment aux comptes créés avec un mot de passe temporaire —,
la modification est persistée, tracée au journal d'audit et journalisée en information. Toute
exception est journalisée en erreur et signalée par un message flash.
Parameters
- $user : User
-
Utilisateur connecté dont le mot de passe est modifié.
- $changePasswordForm : FormInterface<string|int, mixed>
-
Formulaire de changement de mot de passe soumis et validé.
- $userPasswordHasher : UserPasswordHasherInterface
-
Vérifie le mot de passe actuel et hache le nouveau.
Return values
Response —Page de profil rendue (admin/user/profile.html.twig) si le mot de passe actuel est
incorrect, sinon redirection vers app_dashboard (succès comme erreur technique).
handleProfileUpdate()
Handle profile update
private
handleProfileUpdate(User $user, FormInterface<string|int, User> $formProfileUser, UploaderService $uploaderService) : Response
Enregistre les modifications du profil, y compris le remplacement de la photo.
Si une nouvelle image est fournie, elle est déposée dans le répertoire défini par le paramètre
applicatif profile_user_directory ; l'ancien fichier, s'il existe sur le disque, est supprimé avant
que le nouveau nom ne soit affecté à l'entité. Les autres champs ont déjà été hydratés par le
formulaire. La sauvegarde est suivie d'une entrée au journal d'audit et d'un message flash de succès.
Toute exception (upload, suppression du fichier, persistance) est journalisée en erreur et convertie
en message flash ; la redirection finale est identique en cas de succès comme d'échec.
Parameters
- $user : User
-
Utilisateur connecté, déjà hydraté par le formulaire.
- $formProfileUser : FormInterface<string|int, User>
-
Formulaire de profil soumis et validé.
- $uploaderService : UploaderService
-
Service d'upload de la photo de profil.
Return values
Response —Redirection vers app_dashboard, quel que soit le résultat.
sendConfirmationEmail()
Send email confirmation
private
sendConfirmationEmail(User $user) : void
Envoie l'email de bienvenue contenant le lien signé de confirmation d'adresse.
Construit un TemplatedEmail avec l'expéditeur configuré dans MailerService
(adresse et nom), le template email/confirmation_email.html.twig et l'utilisateur en contexte, puis
délègue à EmailVerifier::sendEmailConfirmation() qui y injecte le lien signé pointant vers la
route app_verify_email. Aucune exception n'est interceptée ici. À noter : cette méthode n'est
actuellement appelée nulle part dans le contrôleur, le parcours d'inscription utilisant le code de
vérification à saisir plutôt que le lien signé.
Parameters
- $user : User
-
Destinataire de l'email de confirmation.
validateRecaptcha()
Validate reCAPTCHA submission
private
validateRecaptcha(Recaptcha3Validator $recaptcha3Validator) : array<string, mixed>
Contrôle la dernière réponse reCAPTCHA v3 associée à la soumission en cours.
La vérification échoue dans trois cas, tous journalisés : aucune réponse reCAPTCHA disponible (avertissement), score strictement inférieur au seuil UserController::RECAPTCHA_THRESHOLD (avertissement, avec le score), ou exception levée pendant la récupération (erreur). La méthode ne lève jamais d'exception et n'ajoute aucun message flash : elle se contente de retourner le verdict, exploité par UserController::register().
Parameters
- $recaptcha3Validator : Recaptcha3Validator
-
Donne accès à la dernière réponse reCAPTCHA et à son score.
Return values
array<string, mixed> —['success' => true, 'score' => float] si la vérification passe,
sinon ['success' => false, 'message' => string] avec un message
destiné à l'utilisateur.