BCard - Documentation technique

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

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 # ») et l'utilisateur y est redirigé. Un échec est journalisé et ramène sur cette même page avec un message générique.

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_id pour 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
throws
TransportExceptionInterface
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.

Tags
throws
TransportExceptionInterface

        
On this page

Search results