PaymentController
extends AbstractController
in package
Contrôleur du panier, du tunnel de commande et du paiement des cartes physiques vendues à l'unité.
Le panier est stocké en session sous la clé cart, indexé par identifiant de produit Card ;
il ne contient que des données scalaires (identifiant, quantité, police, couleur, design,
fichier de design, options de couleur et d'impression) et est réhydraté depuis la base à chaque
affichage. Le tunnel accepte les visiteurs non authentifiés : un compte ROLE_USER est créé à
la volée avec un jeton de réinitialisation de mot de passe, et un e-mail d'accès lui est envoyé
une fois la commande confirmée. Deux méthodes de paiement sont prévues — le paiement en ligne
via la passerelle Djomy (Orange Money, MTN MoMo, carte bancaire sur la page Djomy) et le
paiement à la livraison. Une commande payée en ligne n'est confirmée que par
PaymentFulfillmentService (retour Djomy vérifié ou webhook) ; la page de succès
ne fait qu'afficher. Les montants sont exprimés en francs guinéens et arrondis à l'entier pour Djomy.
Aucun préfixe de route ni contrôle d'accès au niveau de la classe : les pages sont accessibles
sans authentification, la propriété d'une commande étant vérifiée soit par l'utilisateur
connecté, soit par l'identifiant checkout_order_id conservé en session pour les invités.
Table of Contents
Properties
- $djomyCheckoutService : DjomyCheckoutService
- $logger : LoggerInterface
Methods
- __construct() : mixed
- addCart() : Response
- Ajoute un produit au panier, avec ses options de personnalisation et un éventuel fichier de design.
- cart() : Response
- Affiche le contenu du panier.
- continueToPayment() : Response
- Allows a user to continue with a previously initiated payment.
- miniCart() : JsonResponse
- Retourne en JSON un résumé du panier destiné au mini-panier de l'en-tête.
- paymentCancel() : Response
- Handles the cancellation of a payment, redirecting the user to the homepage.
- paymentSuccess() : Response
- Affiche la page de confirmation d'une commande payée, sans jamais valider un paiement en ligne.
- procedeToPayment() : Response
- Handles the entire checkout process.
- removeCart() : Response
- Retire une ligne du panier.
- resumeOrderPayment() : Response
- Propose à un utilisateur connecté de choisir un mode de règlement pour reprendre une commande en attente de paiement.
- showOrder() : Response
- Displays the success page after a successful payment and clears the user's cart.
- updateCart() : Response
- Met à jour les quantités des lignes du panier.
- generatePassword() : string
- Generates a random password for new user accounts.
- handlePaymentException() : string
- Handles various exceptions that can occur during the payment process.
- hydrateCartForView() : array<int|string, array<string, mixed>>
- Recharge les entités `Card` d'un panier normalisé pour l'affichage.
- normalizeCart() : array<int|string, array<string, mixed>>
- Normalise un panier de session pour n'y conserver que des données scalaires.
- parseMoney() : float
- Convertit un montant stocké sous forme de chaîne en flottant.
- processCashOnDeliveryPayment() : Response
- Processes cash on delivery payments.
- sendWelcomeEmail() : void
- Sends a welcome email to a new user with their credentials.
Properties
$djomyCheckoutService
private
DjomyCheckoutService
$djomyCheckoutService
$logger
private
LoggerInterface
$logger
Methods
__construct()
public
__construct(LoggerInterface $logger, DjomyCheckoutService $djomyCheckoutService) : mixed
Parameters
- $logger : LoggerInterface
-
Journalise les échecs d'upload, d'envoi d'e-mail, de démarrage du paiement et de traitement de commande.
- $djomyCheckoutService : DjomyCheckoutService
-
Démarre le paiement en ligne Djomy.
addCart()
Ajoute un produit au panier, avec ses options de personnalisation et un éventuel fichier de design.
public
addCart(Card $card, Request $request, SessionInterface $session, UploaderService $uploaderService) : Response
La quantité est ramenée à un minimum de 1 ; la police vaut Arial et le design classic
par défaut. Si un fichier design_file est fourni, il subit trois contrôles successifs,
chacun se soldant en cas d'échec par un message flash et un retour vers la fiche produit :
validité de l'upload, taille inférieure au paramètre design_file_max_bytes, et type
accepté (MIME image/png, image/jpeg, image/jpg, application/pdf ou extension png,
jpg, jpeg, pdf). Le répertoire design_directory est créé s'il n'existe pas, puis le
fichier est déposé via UploaderService::uploadFile() ; une FileException est
journalisée et signalée à l'utilisateur. L'entrée est indexée par l'identifiant du produit,
ce qui écrase toute personnalisation antérieure du même produit au lieu de cumuler les
quantités.
Route : /panier/ajouter/{id} (POST), nom app_add_cart. Accès public.
Parameters
- $card : Card
-
Produit à ajouter, résolu depuis le paramètre de route
id. - $request : Request
-
Requête HTTP contenant les options et le fichier
design_file. - $session : SessionInterface
-
Session dans laquelle le panier est enregistré.
- $uploaderService : UploaderService
-
Service d'upload du fichier de design.
Attributes
- #[Route]
- '/panier/ajouter/{id}'
- $name: 'app_add_cart'
- $methods: ['POST']
Return values
Response —Redirection vers app_cart en cas de succès, ou vers app_product_retail (avec l'identifiant du produit) si le fichier de design est refusé.
cart()
Affiche le contenu du panier.
public
cart(SessionInterface $session, EntityManagerInterface $entityManager) : Response
Lit le panier en session en le remplaçant par un tableau vide s'il n'est pas un tableau, le
normalise via PaymentController::normalizeCart(), réécrit la version normalisée en
session (ce qui purge les anciennes entrées contenant des entités sérialisées), puis
l'enrichit des entités Card avec PaymentController::hydrateCartForView().
Route : /panier (GET), nom app_cart. Accès public.
Parameters
- $session : SessionInterface
-
Session contenant la clé
cart. - $entityManager : EntityManagerInterface
-
Utilisé pour recharger les produits du panier.
Attributes
- #[Route]
- '/panier'
- $name: 'app_cart'
- $methods: ['GET']
Return values
Response —Page HTML home/cart.html.twig avec la variable cart (array<int|string, array<string, mixed>>).
continueToPayment()
Allows a user to continue with a previously initiated payment.
public
continueToPayment(Request $request, EntityManagerInterface $entityManager, SessionInterface $session) : Response
Reprend le paiement d'une commande en attente. L'identifiant de commande est lu dans le paramètre de
requête order, avec repli sur checkout_order_id en session ; à défaut, ou si la commande
est introuvable, l'utilisateur est renvoyé au panier. Le contrôle d'accès est identique à
celui de PaymentController::showOrder(). Une commande déjà en Order::EN_TRAITEMENT
redirige vers payment_success. Une commande en Order::EN_ATTENTE_PAIEMENT d'un utilisateur
connecté est renvoyée vers PaymentController::resumeOrderPayment(), qui ouvre une nouvelle
transaction Djomy ; toute autre commande est déclarée non reprenable. Aucune transaction n'est
créée ici.
Route : /continue-to-paiement (toutes méthodes), nom app_continue_payment. Accès public sous réserve du contrôle de propriété.
Parameters
- $request : Request
-
Requête HTTP contenant éventuellement le paramètre
order. - $entityManager : EntityManagerInterface
-
Charge la commande.
- $session : SessionInterface
-
Session contenant
checkout_order_id.
Attributes
- #[Route]
- '/continue-to-paiement'
- $name: 'app_continue_payment'
Return values
Response —Redirection vers app_resume_order_payment, vers payment_success si la commande est déjà traitée, vers app_cart si aucune commande n'est exploitable, vers app_home en cas d'accès refusé, ou vers procede_to_payment si la reprise est impossible.
miniCart()
Retourne en JSON un résumé du panier destiné au mini-panier de l'en-tête.
public
miniCart(SessionInterface $session, EntityManagerInterface $entityManager) : JsonResponse
Normalise et réenregistre le panier en session, puis le réhydrate. Les lignes de quantité nulle ou négative sont ignorées. Les options de couleur et d'impression ne sont prises en compte que si elles existent, sont actives et appartiennent bien au produit de la ligne : cette validation évite qu'une option d'un autre produit gonfle le prix. Le prix unitaire additionne le prix du produit et celui des options retenues ; le total et les montants sont arrondis à l'entier. L'illustration est la première image du produit, à défaut une image par défaut.
Route : /panier/mini (GET), nom app_cart_mini. Accès public.
Parameters
- $session : SessionInterface
-
Session contenant le panier.
- $entityManager : EntityManagerInterface
-
Charge les produits et les options.
Attributes
- #[Route]
- '/panier/mini'
- $name: 'app_cart_mini'
- $methods: ['GET']
Return values
JsonResponse —array{count: int, subtotal: int, currency: string, items: list<array{cardId: int, name: string, quantity: int, unitPrice: int, lineTotal: int, imageUrl: string}>} (HTTP 200).
paymentCancel()
Handles the cancellation of a payment, redirecting the user to the homepage.
public
paymentCancel() : Response
Page d'annulation neutre (Djomy ne s'en sert pas : son retour passe par djomy_payment_return).
Aucune donnée n'est modifiée : ni la commande ni le paiement ne changent de statut, et le panier
est conservé pour permettre une nouvelle tentative. Un simple message flash d'erreur est ajouté.
Route : /payment-cancel (toutes méthodes), nom payment_cancel. Accès public.
Attributes
- #[Route]
- '/payment-cancel'
- $name: 'payment_cancel'
Return values
Response —Redirection vers app_home.
paymentSuccess()
Affiche la page de confirmation d'une commande payée, sans jamais valider un paiement en ligne.
public
paymentSuccess(Order $order, SessionInterface $session, MailerService $mailerService, EntityManagerInterface $entityManager) : Response
Applique le même contrôle d'accès que PaymentController::showOrder() : propriétaire
connecté ou identifiant de commande présent en session pour un invité. Une commande déjà en
Order::EN_TRAITEMENT voit son panier et son identifiant de session nettoyés (ce qui dépend de la
session et reste donc ici) puis la page de confirmation est rendue. Pour un paiement en ligne, la
commande n'est confirmée que par PaymentFulfillmentService (retour Djomy vérifié
ou webhook) : tant qu'elle n'est pas EN_TRAITEMENT, cette page ne modifie rien et renvoie vers le
détail de la commande. Seul le paiement à la livraison est encore finalisé ici, dans une
transaction DBAL : la commande passe en Order::EN_TRAITEMENT, puis l'e-mail de confirmation est
envoyé, suivi le cas échéant de l'e-mail d'accès du compte créé pour un invité ; un échec d'envoi est
journalisé sans bloquer. Enfin le panier et checkout_order_id sont supprimés de la session.
Route : /payment-success/{order} (toutes méthodes), nom payment_success. Accès public sous réserve du contrôle de propriété.
Parameters
- $order : Order
-
Commande concernée, résolue depuis le paramètre de route
order. - $session : SessionInterface
-
Session contenant le panier et les indicateurs de tunnel.
- $mailerService : MailerService
-
Envoi des e-mails de confirmation et d'accès.
- $entityManager : EntityManagerInterface
-
Persistance et gestion de la transaction.
Attributes
- #[Route]
- '/payment-success/{order}'
- $name: 'payment_success'
Return values
Response —Page HTML payment/confirmation.html.twig, redirection vers app_my_order_show si le paiement en ligne n'est pas encore confirmé, ou vers app_home en cas d'accès refusé ou d'erreur inattendue.
procedeToPayment()
Handles the entire checkout process.
public
procedeToPayment(Request $request, SessionInterface $session, UserPasswordHasherInterface $userPasswordHasher, MailerService $mailerService, EntityManagerInterface $entityManager) : Response
It manages the checkout form, creates a new user if one does not exist, and delegates to the appropriate payment processing method based on user selection.
Traite l'intégralité du tunnel de commande. Le panier est normalisé puis réhydraté ; s'il est
vide, l'utilisateur est renvoyé à l'accueil. Lorsqu'un utilisateur est connecté, le
formulaire CheckoutType est prérempli avec son nom (découpé en prénom/nom sur le
premier espace), son e-mail et son téléphone. À la soumission valide, l'e-mail, le prénom et
le nom sont exigés, puis le total est recalculé côté serveur à partir des prix en base : une
ligne sans produit valide ou de quantité nulle interrompt le processus. Les options de
couleur et d'impression ne sont retenues que si elles sont actives et rattachées au produit.
Si aucun utilisateur n'est connecté, un compte existant portant le même e-mail est réutilisé,
sinon un compte ROLE_USER est créé avec un mot de passe aléatoire et un jeton de
réinitialisation, les indicateurs checkout_new_user et checkout_new_user_email étant
placés en session. Les OrderItem sont ensuite construits (le fichier de design prime sur le
design textuel) et un Payment en PENDING_STATUS est rattaché à la commande. Seules les
méthodes djomy et cash_on_delivery sont acceptées ; pour djomy, le téléphone du formulaire
est utilisé comme numéro du payeur et validé avant toute écriture. La persistance
a lieu dans une transaction DBAL explicite : cash_on_delivery valide la transaction, envoie
l'e-mail de commande puis vide le panier, et djomy place la commande en attente de paiement,
ouvre la transaction Djomy via DjomyCheckoutService::start() et redirige vers sa page de
paiement ; le panier de session est vidé dès que la transaction est ouverte et la commande enregistrée,
checkout_order_id étant conservé. Toute
exception provoque un rollBack(), un message flash adapté (e-mail déjà utilisé, paiement
indisponible, ou erreur générique, sans détail technique) et une journalisation ; un try/catch
externe rattrape les erreurs restantes et redirige vers l'accueil.
Route : /paiement (toutes méthodes), nom procede_to_payment. Accès public (les invités sont pris en charge).
Parameters
- $request : Request
-
Requête HTTP courante (formulaire).
- $session : SessionInterface
-
Session contenant le panier et les indicateurs de tunnel.
- $userPasswordHasher : UserPasswordHasherInterface
-
Hache le mot de passe aléatoire du compte créé pour un invité.
- $mailerService : MailerService
-
Envoi des e-mails de commande et d'accès au compte.
- $entityManager : EntityManagerInterface
-
Persistance et gestion de la transaction.
Attributes
- #[Route]
- '/paiement'
- $name: 'procede_to_payment'
Return values
Response —Page HTML payment/index.html.twig, redirection vers Djomy, vers payment_success en paiement à la livraison, ou vers app_home si le panier est vide, invalide ou en cas d'erreur inattendue.
removeCart()
Retire une ligne du panier.
public
removeCart(int $id, SessionInterface $session) : Response
Supprime l'entrée dont la clé correspond à l'identifiant fourni, sans vérifier son existence : une clé inconnue n'a aucun effet et ne produit aucun message.
Route : /panier/supprimer/{id} (POST, GET), nom app_remove_cart. Accès public.
Parameters
- $id : int
-
Clé de la ligne à retirer, c'est-à-dire l'identifiant du produit.
- $session : SessionInterface
-
Session contenant le panier.
Attributes
- #[Route]
- '/panier/supprimer/{id}'
- $name: 'app_remove_cart'
- $methods: ['POST', 'GET']
Return values
Response —Redirection vers app_cart.
resumeOrderPayment()
Propose à un utilisateur connecté de choisir un mode de règlement pour reprendre une commande en attente de paiement.
public
resumeOrderPayment(Order $order, Request $request, EntityManagerInterface $entityManager) : Response
L'accès exige un utilisateur connecté propriétaire de la commande. Une commande déjà en
Order::EN_TRAITEMENT redirige vers son détail, et toute commande dont le statut n'est pas
Order::EN_ATTENTE_PAIEMENT est refusée. Un formulaire construit à la volée, protégé par un
jeton CSRF propre à la commande, propose le paiement en ligne Djomy (choix par défaut, avec le
téléphone du payeur prérempli) et le paiement à la livraison. Le montant
est recalculé depuis le total de la commande via PaymentController::parseMoney() :
s'il est nul ou négatif, la commande est directement confirmée en Order::EN_TRAITEMENT. Un
paiement en attente existant est réutilisé, sinon un nouveau Payment est créé et rattaché.
En paiement à la livraison, la méthode est enregistrée et l'utilisateur est renvoyé vers
payment_success qui se charge de la suite (statut, e-mails) ; en paiement en ligne, le
téléphone du payeur est validé, puis DjomyCheckoutService::start() ouvre une transaction
Djomy (description « Commande BCard #
Route : /paiement/reprendre/{order} (GET, POST), nom app_resume_order_payment. Utilisateur connecté et propriétaire de la commande.
Parameters
- $order : Order
-
Commande à reprendre, résolue depuis le paramètre de route
order. - $request : Request
-
Requête HTTP courante (soumission du formulaire).
- $entityManager : EntityManagerInterface
-
Persistance des paiements et de la commande.
Attributes
- #[Route]
- '/paiement/reprendre/{order}'
- $name: 'app_resume_order_payment'
- $methods: ['GET', 'POST']
Return values
Response —Page HTML payment/resume_order.html.twig, redirection vers Djomy, vers payment_success, vers app_my_order_show si la commande est déjà traitée, vers physical_card_my_orders si elle n'est pas en attente de paiement ou si le montant est nul, ou vers app_home en cas d'accès refusé.
showOrder()
Displays the success page after a successful payment and clears the user's cart.
public
showOrder(Order $order, SessionInterface $session) : Response
Affiche le détail d'une commande. Contrairement à ce que suggère la description historique
ci-dessus, aucune donnée n'est modifiée et le panier n'est pas vidé. Le contrôle d'accès est
double : un utilisateur connecté doit être le propriétaire de la commande, tandis qu'un
visiteur non authentifié n'y accède que si l'identifiant checkout_order_id conservé en
session correspond à la commande demandée. Tout écart provoque un message flash d'erreur et
un retour à l'accueil.
Route : /my-order/{order} (toutes méthodes), nom app_my_order_show. Accès public sous réserve du contrôle décrit ci-dessus.
Parameters
- $order : Order
-
Commande à afficher, résolue depuis le paramètre de route
order. - $session : SessionInterface
-
Session contenant
checkout_order_idpour les invités.
Attributes
- #[Route]
- '/my-order/{order}'
- $name: 'app_my_order_show'
Return values
Response —Page HTML payment/confirmation.html.twig, ou redirection vers app_home si l'accès est refusé.
updateCart()
Met à jour les quantités des lignes du panier.
public
updateCart(Request $request, SessionInterface $session) : Response
Les nouvelles quantités sont lues dans le tableau de requête quantity, indexé par la clé
de la ligne du panier. Les lignes absentes de ce tableau sont laissées inchangées, et chaque
quantité est ramenée à un minimum de 1. Aucune suppression n'est effectuée : mettre 0 revient
à mettre 1.
Route : /panier/mettre-a-jour (POST), nom app_update_cart. Accès public.
Parameters
- $request : Request
-
Requête HTTP contenant le tableau
quantity. - $session : SessionInterface
-
Session contenant le panier.
Attributes
- #[Route]
- '/panier/mettre-a-jour'
- $name: 'app_update_cart'
- $methods: ['POST']
Return values
Response —Redirection vers app_cart.
generatePassword()
Generates a random password for new user accounts.
private
generatePassword([int $length = 12 ]) : string
Tire aléatoirement des caractères, via random_int(), dans un alphabet composé de chiffres,
de lettres minuscules et majuscules et de symboles. Si random_int() échoue, un repli non
aléatoire est utilisé : la chaîne Password suivie d'un uniqid() et de !@. Méthode
utilitaire actuellement non appelée, le tunnel de commande générant lui-même un mot de passe
via bin2hex(random_bytes(16)).
Parameters
- $length : int = 12
-
Longueur du mot de passe à générer (12 par défaut).
Return values
string —Mot de passe généré.
handlePaymentException()
Handles various exceptions that can occur during the payment process.
private
handlePaymentException(Throwable $e) : string
Traduit une exception en message destiné à l'utilisateur : erreur d'envoi d'e-mail pour une
TransportExceptionInterface, adresse e-mail déjà associée à un compte pour une
UniqueConstraintViolationException, et sinon un message générique auquel le message
d'origine de l'exception est concaténé. Méthode utilitaire actuellement non appelée, la
gestion d'erreurs étant inline dans PaymentController::procedeToPayment().
Parameters
- $e : Throwable
-
Exception survenue pendant le traitement du paiement.
Return values
string —Message d'erreur en français à afficher à l'utilisateur.
hydrateCartForView()
Recharge les entités `Card` d'un panier normalisé pour l'affichage.
private
hydrateCartForView(array<int|string, array<string, mixed>> $cart, EntityManagerInterface $entityManager) : array<int|string, array<string, mixed>>
Collecte les identifiants présents, effectue une unique requête findBy sur les
identifiants dédoublonnés, puis construit une table de correspondance. Chaque ligne se voit
ajouter une clé card ; les lignes dont le produit n'existe plus en base sont
silencieusement écartées du résultat, sans être supprimées de la session.
Parameters
- $cart : array<int|string, array<string, mixed>>
-
Panier normalisé.
- $entityManager : EntityManagerInterface
-
Utilisé pour charger les produits.
Return values
array<int|string, array<string, mixed>> —Panier enrichi d'une clé card contenant l'entité Card.
normalizeCart()
Normalise un panier de session pour n'y conserver que des données scalaires.
private
normalizeCart(array<int|string, mixed> $rawCart) : array<int|string, array<string, mixed>>
Ignore les entrées qui ne sont pas des tableaux. L'identifiant de produit est repris de la
clé cardId ou, pour les paniers issus d'un ancien format, extrait de l'entité Card
stockée sous la clé card ; cette entité est ensuite retirée afin d'éviter de sérialiser un
objet Doctrine en session. Les entrées sans identifiant exploitable sont écartées, les clés
d'origine étant préservées pour les autres.
Parameters
- $rawCart : array<int|string, mixed>
-
Panier brut lu en session.
Return values
array<int|string, array<string, mixed>> —Panier normalisé, chaque ligne comportant une clé cardId entière.
parseMoney()
Convertit un montant stocké sous forme de chaîne en flottant.
private
parseMoney(string|null $value) : float
Retourne 0.0 si la valeur est nulle. Sinon les espaces sont supprimés et les virgules
converties en points avant le transtypage, ce qui permet d'accepter des prix saisis au
format français (25 000,50).
Parameters
- $value : string|null
-
Montant textuel provenant d'une entité (produit, option, commande).
Return values
float —Montant numérique, 0.0 si la valeur est nulle ou non numérique.
processCashOnDeliveryPayment()
Processes cash on delivery payments.
private
processCashOnDeliveryPayment(Order $order, Payment $payment, SessionInterface $session, MailerService $mailerService, string $email) : Response
Ancienne implémentation du paiement à la livraison, remplacée par la branche
cash_on_delivery de PaymentController::procedeToPayment() et non appelée. La
commande passe en Order::EN_TRAITEMENT avec la méthode Payment::DELIVERY_CASH, le
paiement reste en PENDING_STATUS, l'identifiant de commande est mémorisé en session et
l'e-mail de confirmation est envoyé. Si un compte a été créé pour un invité
(checkout_new_user) et que l'e-mail correspond à celui de la commande, l'e-mail d'accès est
envoyé et les indicateurs de session sont nettoyés ; un échec d'envoi est journalisé sans
bloquer. Le panier est ensuite vidé. Aucun flush() n'est réalisé ici : la persistance
incombe à l'appelant.
Parameters
- $order : Order
-
Commande à confirmer.
- $payment : Payment
-
Paiement associé à la commande.
- $session : SessionInterface
-
Session contenant le panier et les indicateurs de tunnel.
- $mailerService : MailerService
-
Envoi des e-mails de confirmation et d'accès.
- $email : string
-
Adresse e-mail destinataire de l'e-mail de confirmation.
Tags
Return values
Response —Redirection vers payment_success avec l'identifiant de la commande.
sendWelcomeEmail()
Sends a welcome email to a new user with their credentials.
private
sendWelcomeEmail(MailerService $mailerService, string $email, string $password, string $firstName) : void
Envoie un e-mail de bienvenue reprenant le template create_credential, auquel sont
transmis l'adresse e-mail, le mot de passe en clair et le prénom du destinataire. Méthode
utilitaire actuellement non appelée : le tunnel de commande envoie désormais un e-mail de
réinitialisation de mot de passe plutôt que des identifiants en clair.
Parameters
- $mailerService : MailerService
-
Service d'envoi d'e-mails.
- $email : string
-
Adresse e-mail du nouvel utilisateur.
- $password : string
-
Mot de passe en clair communiqué à l'utilisateur.
- $firstName : string
-
Prénom utilisé dans le corps de l'e-mail.