<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use App\Entity\ShopPanier;
use App\Entity\User;
use App\Event\StripeEvent;
use App\Repository\ShopOrderRepository;
use Stripe\Event as StripeEventApi;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
class StripeController extends AbstractController
{
protected $dispatcher;
public function __construct(
private \Doctrine\ORM\EntityManagerInterface $entityManager,
private \Psr\Log\LoggerInterface $lifecycleLogger,
\App\EventSubscriber\StripeSubscriber $eventSubscriber
){
$config = new \App\Entity\Configuration;
\Stripe\Stripe::setApiKey($config->getStripeSecretKey());
$this->dispatcher = new \Symfony\Component\EventDispatcher\EventDispatcher();
$this->dispatcher->addSubscriber($eventSubscriber);
}
/**
* @Route("/stripe", name="stripe")
*/
public function index(): Response
{
return $this->render('stripe/index.html.twig', [
'controller_name' => 'StripeController',
]);
}
/**
* @Route("/stripe/success", name="stripe_success")
*/
public function success(ShopOrderRepository $shopOrderRepository, Request $request): Response
{
$index_date_premiere = __FUNCTION__.'-start';
/** @var \App\Entity\ShopOrder */
$LastOrder = $shopOrderRepository->findOneBy(
['user'=>$this->getUser()],
['updatedAt'=>'DESC']
);
if($LastOrder->getStatus()->getCode() !== 'success'){
$date_premiere = $request->getSession()->get($index_date_premiere, new \DateTime('NOW'));
$now = new \DateTime();
$interval = $now->format('U') - $date_premiere->format('U');
if($interval < 120){
$request->getSession()->set($index_date_premiere, $date_premiere);
sleep(10);
return $this->redirectToRoute('stripe_success');
}
$this->addFlash(
'error',
'Une erreur est survenue lors du traitement de votre paiement.<br/>'.
'Merci de nous contacter concernant la commande '.$LastOrder->getReference().' afin de la régulariser.'
);
}
else {
$this->addFlash(
'success',
'Votre paiement a bien été pris en compte.<br/>'.
'Les forfaits ont été ajoutés aux crédits correspondants.'
);
}
$request->getSession()->remove($index_date_premiere);
return $this->redirectToRoute('eleve_forfaits');
}
/**
* @Route("/stripe/cancel", name="stripe_cancel")
*/
public function cancel(): Response
{
$this->addFlash(
'error',
'Votre paiement n\'a pu être validé.<br/>'.
'Vos articles ont été conservés dans votre panier.'
);
return $this->redirectToRoute('eleve_paiement');
}
/**
* 4242424242424242 Réussite de la transaction et traitement immédiat du paiement.
* 4000000000003220 Pour que le paiement réussisse, une authentification 3D Secure 2 est nécessaire.
* 4000000000009995 Échoue toujours avec le code de refus de paiement insufficient_funds.
* https://stripe.com/docs/testing
* @Route("/stripe/webhook", name="stripe_webhook")
*/
public function webHook(Request $request)
{
$requestData = json_decode($request->getContent());
if (!isset($requestData->id) || !isset($requestData->object)) {
throw new BadRequestHttpException('Invalid webhook request data');
}
if ($requestData->object !== 'event') {
throw new \Exception('Unknown stripe object type in webhook');
}
$cache = new FilesystemAdapter();
$cached = $cache->getItem('stripe_event_'.$requestData->id);
if ($cached->isHit()) {
throw new \Exception('L\'évènement '.$requestData->id.' est déjà en cours de traitement.');
}
$stripeEventApi = new StripeEventApi();
if (!$stripeEventObject = $stripeEventApi->retrieve($requestData->id)) {
$this->lifecycleLogger->Error(sprintf('Event does not exists, id %s', $requestData->id), [
'requestData' => $requestData
]);
throw new \Exception(
sprintf('Event does not exists, id %s', $requestData->id)
);
}
$cached->set($stripeEventObject);
$cache->save($cached);
// Log the event
$this->lifecycleLogger->info('StripeEventDispatched : "'.'stripe.' . $stripeEventObject->type.'"', [
'stripeEventObject' => $stripeEventObject
]);
$event = new StripeEvent($stripeEventObject);
$this
->dispatcher
->dispatch($event, 'stripe.' . $stripeEventObject->type);
$response = new Response();
$response->headers->set('Content-Type', 'text/plain');
$response->setStatusCode(Response::HTTP_OK);
$cache->deleteItem($cached->getKey());
return $response;
}
/**
* @Route("/stripe/checkout/{reference}", name="stripe_checkout")
*/
public function checkout($reference): Response
{
// on crée un sessionCheckout à partir du panier
$entityManager = $this->entityManager;
$panier = $entityManager->getRepository(ShopPanier::class)->findBy(['reference'=>$reference]);
$ShopPanier = $panier[0];
$session_parameters = [
'line_items' => [],
'client_reference_id' =>$ShopPanier->getReference(),
'mode' => 'payment',
'mode' => 'payment',
'success_url' => $this->generateUrl('stripe_success', [], UrlGeneratorInterface::ABSOLUTE_URL),
'cancel_url' => $this->generateUrl('stripe_cancel', [], UrlGeneratorInterface::ABSOLUTE_URL),
];
// si le User correspond à un customer dans Stripe, on l'ajoute
if ($ShopPanier->getUser()->getReference()) {
$session_parameters['customer'] = $ShopPanier->getUser()->getReference();
}
if (!$ShopPanier->getUser()->getReference()) {
$session_parameters['customer_email'] = $ShopPanier->getUser()->getEmail();
}
$default_item = [
'price_data' => [
'currency' => 'eur',
'product_data' => [
'name' => '',
'metadata' =>[
'id_product'=>'-1',
'points'=>'0'
],
],
'unit_amount' => '-1',
],
'quantity' => '1',
];
foreach ($panier as $ShopPanier) {
$item = $default_item;
$item['quantity'] = (string)$ShopPanier->getUnit();
$item['price_data']['unit_amount'] = (string)$ShopPanier->getProduit()->getPrice()*100;
$item['price_data']['product_data']['name'] = $ShopPanier->getProduit()->getIntitule();
$item['price_data']['product_data']['metadata']['id_product'] = (string)$ShopPanier->getProduit()->getId();
$item['price_data']['product_data']['metadata']['categorie'] = (string)$ShopPanier->getProduit()->getCategorie()->getIntitule();
$item['price_data']['product_data']['metadata']['points'] = (string)$ShopPanier->getProduit()->getPoints();
$session_parameters['line_items'][] = $item;
}
try {
$session = \Stripe\Checkout\Session::create($session_parameters);
//code...
} catch (\Stripe\Exception\InvalidRequestException $th) {
//throw $th;
unset($session_parameters['customer']);
$ShopPanier->getUser()->setReference(null);
$entityManager->persist($ShopPanier->getUser());
$entityManager->flush();
$session = \Stripe\Checkout\Session::create($session_parameters);
}
return $this->redirect($session->url, 303);
}
}