src/Controller/AccountController.php line 58

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use App\Entity\User;
  4. use App\Entity\Subscription as Sub;
  5. use App\Form\ProfileFormType;
  6. use Doctrine\ORM\EntityManagerInterface;
  7. use Psr\Log\LoggerInterface;
  8. use Stripe\Checkout\Session;
  9. use Stripe\Customer;
  10. use Stripe\Event;
  11. use Stripe\Exception\ApiErrorException;
  12. use Stripe\Exception\SignatureVerificationException;
  13. use Stripe\Exception\UnexpectedValueException;
  14. use Stripe\Stripe;
  15. use Stripe\Subscription;
  16. use Stripe\Webhook;
  17. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  18. use Symfony\Component\HttpFoundation\Request;
  19. use Symfony\Component\HttpFoundation\Response;
  20. use Symfony\Component\Routing\Annotation\Route;
  21. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  22. use Symfony\Component\Security\Core\Security;
  23. final class AccountController extends AbstractController
  24. {
  25.     public function __construct(
  26.         private EntityManagerInterface $em,
  27.         private LoggerInterface $logger,
  28.         private string $monthlyPrice,
  29.         private string $yearlyPrice
  30.     ) {
  31.     }
  32.     #[Route('/app/profile'name'profile')]
  33.     public function profile(Request $requestSecurity $securityEntityManagerInterface $em): Response
  34.     {
  35.         $user $security->getUser();
  36.         $form $this->createForm(ProfileFormType::class, $user);
  37.         $form->handleRequest($request);
  38.         if ($form->isSubmitted() && $form->isValid()) {
  39.             $this->addFlash('info''Vos données sont mise à jour avec suucès');
  40.             $em->persist($user);
  41.             $em->flush();
  42.             return $this->redirectToRoute('profile');
  43.         }
  44.         return $this->render('app/profile.html.twig', ['form' => $form->createView()]);
  45.     }
  46.     #[Route('/app/order'name'order')]
  47.     public function order(): Response
  48.     {
  49.         return $this->render('app/order.html.twig');
  50.     }
  51.     #[Route('/app/checkout'name'checkout')]
  52.     public function checkout(Request $requestUrlGeneratorInterface $urlGeneratorSecurity $securitystring $stripeSK): Response
  53.     {
  54.         $qte $request->request->get('qte'1);
  55.         $plan $request->request->get('plan''monthly');
  56.         Stripe::setApiKey($stripeSK);
  57.         $session Session::create([
  58.             'line_items' => [[
  59.                 'price' => $plan == 'monthly' $this->monthlyPrice $this->yearlyPrice,
  60.                 'quantity' => $qte,
  61.             ]],
  62.             'mode' => 'subscription',
  63.             'success_url' => $urlGenerator->generate('checkout_success', [], UrlGeneratorInterface::ABSOLUTE_URL),
  64.             'cancel_url' => $urlGenerator->generate('checkout_cancel', [], UrlGeneratorInterface::ABSOLUTE_URL),
  65.             'automatic_tax' => [
  66.                 'enabled' => true,
  67.             ],
  68.             'customer_email' => $security->getUser()->getEmail(),
  69.         ]);
  70.         return $this->redirect($session->url303);
  71.     }
  72.     #[Route('/app/checkout-success'name'checkout_success')]
  73.     public function success(): Response
  74.     {
  75.         return $this->render('app/payment_success.html.twig');
  76.     }
  77.     #[Route('/app/checkout-cancel'name'checkout_cancel')]
  78.     public function cancel(): Response
  79.     {
  80.         return $this->render('app/payment_cancel.html.twig');
  81.     }
  82.     #[Route('/stripe-webhook'name'stripe_webhook')]
  83.     public function webhook(Request $requeststring $stripeSKstring $stripeWebhookSecret): Response
  84.     {
  85.         $payload $request->getContent();
  86.         try {
  87.             $event Event::constructFrom(
  88.                 json_decode($payloadtrue)
  89.             );
  90.         } catch(UnexpectedValueException $e) {
  91.             // Invalid payload
  92.             $this->logger->error('⚠️  Webhook error while parsing basic request.');
  93.             return $this->json([], Response::HTTP_BAD_REQUEST);
  94.         }
  95.         if ($stripeWebhookSecret) {
  96.             $sigHeader $request->headers->get('stripe-signature');
  97.             try {
  98.                 $event Webhook::constructEvent(
  99.                     $payload$sigHeader$stripeWebhookSecret
  100.                 );
  101.             } catch(SignatureVerificationException $e) {
  102.                 $this->logger->error('⚠️  Webhook error while validating signature.');
  103.                 return $this->json([], Response::HTTP_BAD_REQUEST);
  104.             }
  105.         }
  106.         // Handle the event
  107.         switch ($event->type) {
  108.             case 'customer.subscription.created':
  109.             case 'customer.subscription.updated':
  110.             case 'customer.subscription.deleted':
  111.                 $object $event->data->object;
  112.                 $this->logger->error(get_class($object));
  113.                 $this->handlePaymentIntentSucceeded($object$stripeSK);
  114.                 break;
  115.             default:
  116.                 // Unexpected event type
  117.                 $this->logger->error('Received unknown event type');
  118.         }
  119.         return $this->json([]);
  120.     }
  121.     private function handlePaymentIntentSucceeded(Subscription $subscriptionObjectstring $stripeSK): void
  122.     {
  123.         Stripe::setApiKey($stripeSK);
  124.         $customer Customer::retrieve($subscriptionObject->customer);
  125.         $user $this->em->getRepository(User::class)->findOneBy(['email' => $customer->email]);
  126.         $subscription $this->em->getRepository(Sub::class)->findOneBy(['stripeSubId' => $subscriptionObject->id]) ?? new Sub();
  127.         $subscription->setStripeSubId($subscriptionObject->id);
  128.         $subscription->setStartAt((new \DateTimeImmutable())->setTimestamp($subscriptionObject->current_period_start));
  129.         $subscription->setEndAt((new \DateTimeImmutable())->setTimestamp($subscriptionObject->current_period_end));
  130.         $subscription->setAutoRenew(!$subscriptionObject->cancel_at_period_end);
  131.         $subscription->setPrice($subscriptionObject->plan->amount_decimal);
  132.         $subscription->setPlan($subscriptionObject->plan->interval);
  133.         $subscription->setQte($subscriptionObject->quantity);
  134.         $subscription->setCustomer($user);
  135.         $subscription->setStatus($subscriptionObject->status);
  136.         $this->em->persist($subscription);
  137.         $this->em->flush();
  138.     }
  139.     #[Route('/app/unsubscribe/{sub}'name'unsubscribe')]
  140.     public function unsubscribe(Security $securitySub $substring $stripeSK): Response
  141.     {
  142.         try {
  143.             if ($security->getUser() !== $sub->getCustomer()) {
  144.                 return $this->redirectToRoute('app_index');
  145.             }
  146.             Stripe::setApiKey($stripeSK);
  147.             Subscription::update($sub->getStripeSubId(), ['cancel_at_period_end' => true]);
  148.             $sub->setAutoRenew(false);
  149.             $this->em->persist($sub);
  150.             $this->em->flush();
  151.             $this->addFlash('info''Souscription mise à jour avec succès');
  152.         } catch (ApiErrorException $exception) {
  153.             $this->addFlash('error'$exception->getMessage());
  154.             return $this->redirectToRoute('app_index');
  155.         }
  156.         return $this->redirectToRoute('app_index');
  157.     }
  158.     #[Route('/app/resume/{sub}'name'resume')]
  159.     public function resume(Security $securitySub $substring $stripeSK): Response
  160.     {
  161.         try {
  162.             if ($security->getUser() !== $sub->getCustomer()) {
  163.                 return $this->redirectToRoute('app_index');
  164.             }
  165.             Stripe::setApiKey($stripeSK);
  166.             Subscription::update($sub->getStripeSubId(), ['cancel_at_period_end' => false]);
  167.             $sub->setAutoRenew(true);
  168.             $this->em->persist($sub);
  169.             $this->em->flush();
  170.             $this->addFlash('info''Souscription mise à jour avec succès');
  171.         } catch (ApiErrorException $exception) {
  172.             $this->addFlash('error'$exception->getMessage());
  173.             return $this->redirectToRoute('app_index');
  174.         }
  175.         return $this->redirectToRoute('app_index');
  176.     }
  177. }