src/Social/CreditsBundle/Event/CreditConsumerEventSubscriber.php line 180

Open in your IDE?
  1. <?php
  2. namespace Social\CreditsBundle\Event;
  3. use Symfony\Component\Cache\CacheItem;
  4. use Sentry\ClientInterface as SentryClient;
  5. use Doctrine\ORM\EntityManagerInterface;
  6. use Social\CreditsBundle\Entity\CreditActionsEntity;
  7. use Symfony\Component\Cache\Adapter\FilesystemAdapter;
  8. use Social\CreditsBundle\Entity\CreditUserHistoryEntity;
  9. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  10. use Exception;
  11. use Psr\Cache\InvalidArgumentException;
  12. class CreditConsumerEventSubscriber implements EventSubscriberInterface
  13. {
  14.     const INTERNAL_CACHE_LOCATION 'social.credits.actions.definitions';
  15.     const CREDIT_CONSUMER_CHECK_ALLOWANCE       'credit_consumer.allowance';
  16.     const CREDIT_CONSUMER_CONSUME               'credit_consumer.consume';
  17.     const CREDIT_CONSUMER_RESTORE_LAST_CONSUMED 'credit_consumer.restore_last_consumed';
  18.     /**
  19.      * @var SentryClient $sentry
  20.      */
  21.     private $sentry;
  22.     /**
  23.      * Entity Manager
  24.      *
  25.      * @var EntityManagerInterface $entityManager
  26.      */
  27.     private $entityManager;
  28.     /**
  29.      * Package definitions
  30.      *
  31.      * @var array $packagesDefinitions
  32.      */
  33.     private $packagesDefinitions;
  34.     /**
  35.      * CreditConsumerEventSubscriber constructor.
  36.      *
  37.      * @param SentryClient           $sentry
  38.      * @param EntityManagerInterface $entityManager
  39.      *
  40.      * @throws InvalidArgumentException
  41.      */
  42.     public function __construct(
  43.         SentryClient $sentry,
  44.         EntityManagerInterface $entityManager
  45.     ) {
  46.         $this->sentry             $sentry;
  47.         $this->entityManager      $entityManager;
  48.         $cache                    = new FilesystemAdapter();
  49.         $creditActionsDefinitions = [];
  50.         if ($cache->hasItem(self::INTERNAL_CACHE_LOCATION)) {
  51.             /** @var CacheItem $cacheItem */
  52.             $cacheItem                $cache->getItem(self::INTERNAL_CACHE_LOCATION);
  53.             $creditActionsDefinitions json_decode($cacheItem->get(), true);
  54.         } else {
  55.             $credits $this->entityManager
  56.                 ->getRepository(CreditActionsEntity::class)
  57.                 ->findAll();
  58.             foreach ($credits as $individualCredit) {
  59.                 $creditActionsDefinitions[$individualCredit->getCode()] = [
  60.                     'active' => $individualCredit->isActive(),
  61.                     'name'   => $individualCredit->getName(),
  62.                     'code'   => $individualCredit->getCode(),
  63.                     'cost'   => $individualCredit->getCost(),
  64.                 ];
  65.             }
  66.             $newCache $cache->getItem(self::INTERNAL_CACHE_LOCATION);
  67.             $newCache->set(json_encode($creditActionsDefinitions));
  68.             $newCache->expiresAfter(36000);
  69.             $cache->save($newCache);
  70.         }
  71.         $this->packagesDefinitions $creditActionsDefinitions;
  72.     }
  73.     public static function getSubscribedEvents(): array
  74.     {
  75.         return [
  76.             self::CREDIT_CONSUMER_CHECK_ALLOWANCE       => 'checkAvailableCredits',
  77.             self::CREDIT_CONSUMER_CONSUME               => 'consumeCredits',
  78.             self::CREDIT_CONSUMER_RESTORE_LAST_CONSUMED => 'restoreLastActionConsumed',
  79.         ];
  80.     }
  81.     public function checkAvailableCredits(CreditConsumerEvent $event)
  82.     {
  83.         try {
  84.             $currentUser $event->getUser();
  85.             $this->entityManager->refresh($currentUser);
  86.             $currentAction $event->getAction();
  87.             // If the action exists then we will see if active
  88.             if (array_key_exists($currentAction$this->packagesDefinitions)) {
  89.                 // The action is active to be used - check cost and user balance
  90.                 if ($this->packagesDefinitions[$currentAction]['active'] == true) {
  91.                     $cost $this->packagesDefinitions[$currentAction]['cost'];
  92.                     // Check if user has enough credits
  93.                     if ($cost <= $currentUser->getCredits()) {
  94.                         $event->setIsOK(true);
  95.                         $event->setBillPrice($cost);
  96.                         $event->setIsBilled(false);
  97.                         return;
  98.                     } else {
  99.                         // User does not have enough to be debited from his credits
  100.                         $event->setIsOK(false);
  101.                         $event->setIsBilled(false);
  102.                         return;
  103.                     }
  104.                 } else {
  105.                     // Action is not active to be used - set that is ok, bill with nothing and set as paid
  106.                     $event->setIsOk(true);
  107.                     $event->setBillPrice(0);
  108.                     $event->setIsBilled(true);
  109.                     return;
  110.                 }
  111.             }
  112.             // The action is not in the ones from database
  113.             $event->setIsOK(true);
  114.             $event->setBillPrice(0);
  115.             $event->setIsBilled(true);
  116.             return;
  117.         } catch (Exception $exception) {
  118.             $event->setIsOK(false);
  119.             $this->sentry->captureException($exception);
  120.             $this->sentry->captureEvent([
  121.                 'exception' => $exception->getMessage() . ' ' $exception->getLine() . $exception->getFile(),
  122.                 'Culprit'   => 'Credit Consumer - check available credits',
  123.                 'User'      => $event->getUser(),
  124.                 'Action'    => $event->getAction(),
  125.                 'Request'   => $event->getRequest(),
  126.             ]);
  127.         }
  128.     }
  129.     public function consumeCredits(CreditConsumerEvent $event)
  130.     {
  131.         try {
  132.             $currentUser $event->getUser();
  133.             if (!$event->isBilled() && $event->isOK()) {
  134.                 $currentUser->substractCredits($event->getBillPrice() > $event->getBillPrice() : 0);
  135.                 $this->entityManager->persist($currentUser);
  136.                 $this->entityManager->flush();
  137.                 $billingHistory = new CreditUserHistoryEntity();
  138.                 $billingHistory->setUserId($currentUser);
  139.                 $billingHistory->setCost($event->getBillPrice());
  140.                 $billingHistory->setIsFromBonus(false);
  141.                 $billingHistory->setAction($event->getAction());
  142.                 $billingHistory->setType(CreditUserHistoryEntity::ACTION_TYPE_SUBTRACT);
  143.                 $this->entityManager->persist($billingHistory);
  144.                 $this->entityManager->flush();
  145.                 $this->entityManager->refresh($currentUser);
  146.                 $event->setIsBilled(true);
  147.             }
  148.         } catch (Exception $exception) {
  149.             $event->setIsOK(false);
  150.             $event->setIsBilled(false);
  151.         }
  152.     }
  153.     /** @todo - implement in case of rollback */
  154.     public function restoreLastActionConsumed()
  155.     {
  156.     }
  157. }