src/EventSubscriber/IdempotenceSubscriber.php line 102

Open in your IDE?
  1. <?php
  2. /**
  3.  * @license SILK SOFTWARE HOUSE SP Z O O
  4.  */
  5. namespace App\EventSubscriber;
  6. use App\Annotation\Idempotent;
  7. use App\Entity\CachedResponse;
  8. use App\Repository\CachedResponseRepository;
  9. use Doctrine\ORM\EntityManagerInterface as EntityManager;
  10. use Symfony\Component\HttpFoundation\JsonResponse;
  11. use Symfony\Component\HttpKernel\Event\ControllerEvent;
  12. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  13. use Symfony\Component\HttpKernel\Event\ResponseEvent;
  14. use Symfony\Component\HttpKernel\KernelEvents;
  15. use Doctrine\Common\Annotations\Reader;
  16. use ReflectionClass;
  17. use ReflectionException;
  18. /**
  19.  * Class IdempotenceSubscriber.
  20.  */
  21. class IdempotenceSubscriber implements EventSubscriberInterface
  22. {
  23.     /**
  24.      * Cache repository.
  25.      *
  26.      * @var CachedResponseRepository
  27.      */
  28.     private $cache;
  29.     /**
  30.      * Annotation reader.
  31.      *
  32.      * @var Reader
  33.      */
  34.     private $annotationReader;
  35.     /**
  36.      * IdempotenceSubscriber constructor.
  37.      *
  38.      * @param EntityManager $entityManager
  39.      * @param Reader        $reader
  40.      */
  41.     public function __construct(EntityManager $entityManagerReader $reader)
  42.     {
  43.         $this->cache $entityManager->getRepository(CachedResponse::class);
  44.         $this->annotationReader $reader;
  45.     }
  46.     /**
  47.      * Get subscribed events.
  48.      *
  49.      * @return array
  50.      */
  51.     public static function getSubscribedEvents()
  52.     {
  53.         // return the subscribed events, their methods and priorities
  54.         return [
  55.             KernelEvents::CONTROLLER => [
  56.                 ['onKernelController', -2],
  57.             ],
  58.             KernelEvents::RESPONSE => [
  59.                 ['onKernelResponse'10],
  60.             ],
  61.         ];
  62.     }
  63.     /**
  64.      * On kernel controller.
  65.      *
  66.      * @param ControllerEvent $event
  67.      */
  68.     public function onKernelController(ControllerEvent $event)
  69.     {
  70.         if (!$event->isMasterRequest()) {
  71.             return;
  72.         }
  73.         $annotation $this->getIdempotentAnnotation($event->getController());
  74.         if (null === $annotation) {
  75.             return;
  76.         }
  77.         $idempotenceHash $event->getRequest()->getContent();
  78.         $event->getRequest()->cookies->set('idempotent'$idempotenceHash);
  79.         if ($cached $this->cache->getCachedResponse($idempotenceHash$event->getRequest()->get('_route'))) {
  80.             $event->setController(function () use ($cached) {
  81.                 return $cached;
  82.             });
  83.         }
  84.     }
  85.     /**
  86.      * On kernel response.
  87.      *
  88.      * @param ResponseEvent $event
  89.      */
  90.     public function onKernelResponse(ResponseEvent $event)
  91.     {
  92.         $requestId $event->getRequest()->cookies->get('idempotent');
  93.         if (!$requestId) {
  94.             return;
  95.         }
  96.         $response $event->getResponse();
  97.         if (!$response instanceof JsonResponse || 201 !== $response->getStatusCode()) {
  98.             return;
  99.         }
  100.         $this->cache->cache(
  101.             $requestId,
  102.             $response->getStatusCode(),
  103.             $response->getContent(),
  104.             $event->getRequest()->get('_route')
  105.         );
  106.     }
  107.     /**
  108.      * Does controller have idempotent annotation.
  109.      *
  110.      * @param callable $controllerData
  111.      *
  112.      * @return Idempotent|null
  113.      */
  114.     private function getIdempotentAnnotation($controllerData)
  115.     {
  116.         $annotation null;
  117.         if (!is_array($controllerData)) {
  118.             return null;
  119.         }
  120.         list($controllerObject$methodName) = $controllerData;
  121.         try {
  122.             $controller = new ReflectionClass($controllerObject);
  123.             $method $controller->getMethod($methodName);
  124.             $annotation $this->annotationReader->getMethodAnnotation($methodIdempotent::class);
  125.         } catch (ReflectionException $e) {
  126.             return null;
  127.         }
  128.         return $annotation instanceof Idempotent $annotation null;
  129.     }
  130. }