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

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