vendor/sensio/framework-extra-bundle/EventListener/HttpCacheListener.php line 82

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the Symfony framework.
  4.  *
  5.  * (c) Fabien Potencier <fabien@symfony.com>
  6.  *
  7.  * This source file is subject to the MIT license that is bundled
  8.  * with this source code in the file LICENSE.
  9.  */
  10. namespace Sensio\Bundle\FrameworkExtraBundle\EventListener;
  11. use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
  12. use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
  13. use Symfony\Component\HttpKernel\KernelEvents;
  14. use Symfony\Component\HttpFoundation\Response;
  15. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  16. use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
  17. /**
  18.  * HttpCacheListener handles HTTP cache headers.
  19.  *
  20.  * It can be configured via the Cache annotation.
  21.  *
  22.  * @author Fabien Potencier <fabien@symfony.com>
  23.  */
  24. class HttpCacheListener implements EventSubscriberInterface
  25. {
  26.     private $lastModifiedDates;
  27.     private $etags;
  28.     private $expressionLanguage;
  29.     public function __construct()
  30.     {
  31.         $this->lastModifiedDates = new \SplObjectStorage();
  32.         $this->etags = new \SplObjectStorage();
  33.     }
  34.     /**
  35.      * Handles HTTP validation headers.
  36.      */
  37.     public function onKernelController(FilterControllerEvent $event)
  38.     {
  39.         $request $event->getRequest();
  40.         if (!$configuration $request->attributes->get('_cache')) {
  41.             return;
  42.         }
  43.         $response = new Response();
  44.         $lastModifiedDate '';
  45.         if ($configuration->getLastModified()) {
  46.             $lastModifiedDate $this->getExpressionLanguage()->evaluate($configuration->getLastModified(), $request->attributes->all());
  47.             $response->setLastModified($lastModifiedDate);
  48.         }
  49.         $etag '';
  50.         if ($configuration->getETag()) {
  51.             $etag hash('sha256'$this->getExpressionLanguage()->evaluate($configuration->getETag(), $request->attributes->all()));
  52.             $response->setETag($etag);
  53.         }
  54.         if ($response->isNotModified($request)) {
  55.             $event->setController(function () use ($response) {
  56.                 return $response;
  57.             });
  58.             $event->stopPropagation();
  59.         } else {
  60.             if ($etag) {
  61.                 $this->etags[$request] = $etag;
  62.             }
  63.             if ($lastModifiedDate) {
  64.                 $this->lastModifiedDates[$request] = $lastModifiedDate;
  65.             }
  66.         }
  67.     }
  68.     /**
  69.      * Modifies the response to apply HTTP cache headers when needed.
  70.      */
  71.     public function onKernelResponse(FilterResponseEvent $event)
  72.     {
  73.         $request $event->getRequest();
  74.         if (!$configuration $request->attributes->get('_cache')) {
  75.             return;
  76.         }
  77.         $response $event->getResponse();
  78.         // http://tools.ietf.org/html/draft-ietf-httpbis-p4-conditional-12#section-3.1
  79.         if (!in_array($response->getStatusCode(), array(200203300301302304404410))) {
  80.             return;
  81.         }
  82.         if (null !== $age $configuration->getSMaxAge()) {
  83.             if (!is_numeric($age)) {
  84.                 $now microtime(true);
  85.                 $age ceil(strtotime($configuration->getSMaxAge(), $now) - $now);
  86.             }
  87.             $response->setSharedMaxAge($age);
  88.         }
  89.         if (null !== $age $configuration->getMaxAge()) {
  90.             if (!is_numeric($age)) {
  91.                 $now microtime(true);
  92.                 $age ceil(strtotime($configuration->getMaxAge(), $now) - $now);
  93.             }
  94.             $response->setMaxAge($age);
  95.         }
  96.         if (null !== $configuration->getExpires()) {
  97.             $date = \DateTime::createFromFormat('U'strtotime($configuration->getExpires()), new \DateTimeZone('UTC'));
  98.             $response->setExpires($date);
  99.         }
  100.         if (null !== $configuration->getVary()) {
  101.             $response->setVary($configuration->getVary());
  102.         }
  103.         if ($configuration->isPublic()) {
  104.             $response->setPublic();
  105.         }
  106.         if ($configuration->isPrivate()) {
  107.             $response->setPrivate();
  108.         }
  109.         if (isset($this->lastModifiedDates[$request])) {
  110.             $response->setLastModified($this->lastModifiedDates[$request]);
  111.             unset($this->lastModifiedDates[$request]);
  112.         }
  113.         if (isset($this->etags[$request])) {
  114.             $response->setETag($this->etags[$request]);
  115.             unset($this->etags[$request]);
  116.         }
  117.     }
  118.     public static function getSubscribedEvents()
  119.     {
  120.         return array(
  121.             KernelEvents::CONTROLLER => 'onKernelController',
  122.             KernelEvents::RESPONSE => 'onKernelResponse',
  123.         );
  124.     }
  125.     private function getExpressionLanguage()
  126.     {
  127.         if (null === $this->expressionLanguage) {
  128.             if (!class_exists('Symfony\Component\ExpressionLanguage\ExpressionLanguage')) {
  129.                 throw new \RuntimeException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed.');
  130.             }
  131.             $this->expressionLanguage = new ExpressionLanguage();
  132.         }
  133.         return $this->expressionLanguage;
  134.     }
  135. }