<?php
namespace App\EventListener;
use App\Entity\Subscription;
use App\Entity\SubscriptionType;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Authorization\AuthorizationChecker;
use App\Model\User;
use App\Helper\Tools;
use App\Repository\UserRepository;
use DateInterval;
use DateTime;
use DateTimeImmutable;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Component\Routing\RouterInterface;
class UserRequestListener
{
/**
* @var AuthorizationChecker
*/
protected $authChecker;
/**
* @var TokenStorageInterface
*/
protected $tokenStorage;
/**
* @var SessionInterface
*/
protected $session;
/**
* @var UserRepository
*/
protected $userRepository;
/**
* @var KernelInterface
*/
protected $kernel;
/**
* @var RouterInterface
*/
protected $router;
public function __construct(
AuthorizationChecker $authChecker,
TokenStorageInterface $tokenStorage,
SessionInterface $session,
UserRepository $userRepository,
KernelInterface $kernel,
RouterInterface $router
) {
$this->authChecker = $authChecker;
$this->tokenStorage = $tokenStorage;
$this->authChecker = $authChecker;
$this->session = $session;
$this->userRepository = $userRepository;
$this->kernel = $kernel;
$this->router = $router;
}
/**
* @return Kernel
*/
public function getKernel()
{
return $this->kernel;
}
public function endingDate($subscriptionType)
{
$dateNow = new DateTime();
$endingDate = $dateNow;
if ('annuel' === $subscriptionType->getPeriod()) {
$endingDate = $dateNow->add(new DateInterval('P1Y'));
} else {
$endingDate = $dateNow->add(new DateInterval('P1M'));
}
return DateTimeImmutable::createFromMutable($endingDate);
}
public function checkSubscription($user)
{
$stripe = new \Stripe\StripeClient($this->getKernel()->getContainer()->getParameter('STRIPE_SECRET_KEY_LIVE'));
$em = $this->getKernel()->getContainer()->get('doctrine.orm.default_entity_manager');
if (!is_string($user)) {
if ($user->getStripeId()) {
$customer = $stripe->customers->retrieve(
$user->getStripeId(),
['expand' => ['subscriptions']]
);
if ($customer->subscriptions) {
if ($customer->subscriptions->data) {
$subscription = $customer->subscriptions->data;
$annuelOrMensuel = 'year' === $subscription[0]->plan->interval ? Tools::YEAR : Tools::MONTH;
//add subscription in DB if there is a subscription on stripe
if (0 !== count($subscription) && 'active' === $customer->subscriptions->data[0]->status) {
if (null === $user->getSubscription()) {
$newSubscription = new Subscription();
$subscriptionType = $em->getRepository(SubscriptionType::class)->findOneBy(['name' => $annuelOrMensuel]);
$newSubscription->setSubscriptionType($subscriptionType);
$newSubscription->setEndingAt($this->endingDate($subscriptionType));
$user->setSubscription($newSubscription);
$em->persist($user);
$em->persist($newSubscription);
$em->flush();
} else {
//set new subscription endingDate if endingDate before now
if ($user->getSubscription()->getEndingAt() < new DateTime()) {
$user->getSubscription()->setEndingAt($this->endingDate($user->getSubscription()->getSubscriptionType()));
$em->persist($user);
$em->flush();
}
//need to release subscription schedule if exists for later edit or cancel subscription
if ($subscription[0]->schedule) {
$stripe->subscriptionSchedules->release(
$customer->subscriptions->data[0]->schedule,
[]
);
}
//during change of subscription to pass from annuel to mensuel or revert
if ($annuelOrMensuel !== $user->getSubscription()->getSubscriptionType()->getPeriod()) {
$subscriptionType = $em->getRepository(SubscriptionType::class)->findOneBy(['name' => $annuelOrMensuel]);
$subscriptionToEdit = $em->getRepository(Subscription::class)->findOneBy(['id' => $user->getSubscription()->getId()]);
$subscriptionToEdit->setSubscriptionType($subscriptionType);
$subscriptionToEdit->setCreatedAt(new DateTime());
$subscriptionToEdit->setEndingAt($this->endingDate($subscriptionType));
$em->persist($subscriptionToEdit);
$em->flush();
}
}
} else {
//remove subscription if no subscription on stripe
if ($user->getSubscription()) {
$user->setSubscription(null);
$em->persist($user);
$em->flush();
}
}
} else {
//remove subscription if no subscription on stripe
if ($user->getSubscription()) {
$user->setSubscription(null);
$em->persist($user);
$em->flush();
}
}
}
} else {
//add stripe id in bdd if preset in stripe for current user
$customer = $stripe->customers->search([
'query' => 'email:\''.$user->getEmail().'\'',
]);
if ($customer && 'ROLE_CLIENT' === $user->getRoles()[0]) {
$user->setStripeId($customer->data[0]->id);
$em->persist($user);
$em->flush();
}
}
}
}
public function onKernelRequest(RequestEvent $event)
{
if (!$event->isMainRequest()) {
// don't do anything if it's not the main request
return;
}
$accessToken = $this->tokenStorage->getToken();
$currentRoute = $event->getRequest()->get('_route');
if (!$accessToken) {
return;
}
// When logging the current user to the admin, we don't need to make all the checks underneath
if ('admin_dashboard' === $currentRoute) {
return;
}
/** @var User $user */
$user = $accessToken->getUser();
if ('object' == gettype($user)) {
if ($this->session->get('sessionSecret') !== $user->getSessionSecret()) {
// Logging user out.
$this->tokenStorage->setToken(null);
// Invalidating the session.
$this->session->invalidate();
}
}
$this->checkSubscription($user);
$routesToIgnore = ['app_api_payment_getstripeinfos', 'app_my_account', 'app_api_payment_newsubscription', 'app_api_payment_updatecard',
'app_api_payment_subscriptiontype', 'app_api_payment_payments', ];
if ('anon.' !== $user) {
if (!$user->getSubscription() && 'ROLE_CLIENT' === $user->getRoles()[0]) {
if (!in_array($currentRoute, $routesToIgnore)) {
$response = new RedirectResponse($this->router->generate('app_my_account'));
$event->setResponse($response);
}
}
}
}
}