Bläddra i källkod

[HttpKernel] added a way to change the ESI cache strategy

Fabien Potencier 14 år sedan
förälder
incheckning
cef86a3771

+ 1 - 0
src/Symfony/Bundle/FrameworkBundle/HttpCache/HttpCache.php

@@ -5,6 +5,7 @@ namespace Symfony\Bundle\FrameworkBundle\HttpCache;
 use Symfony\Component\HttpKernel\HttpKernelInterface;
 use Symfony\Component\HttpKernel\HttpCache\HttpCache as BaseHttpCache;
 use Symfony\Component\HttpKernel\HttpCache\Esi;
+use Symfony\Component\HttpKernel\HttpCache\EsiResponseCacheStrategy;
 use Symfony\Component\HttpKernel\HttpCache\Store;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\HttpFoundation\Response;

+ 10 - 0
src/Symfony/Component/HttpKernel/HttpCache/Esi.php

@@ -41,6 +41,16 @@ class Esi
         $this->contentTypes = $contentTypes;
     }
 
+    /**
+     * Returns a new cache strategy instance.
+     *
+     * @return EsiResponseCacheStrategyInterface A EsiResponseCacheStrategyInterface instance
+     */
+    public function createCacheStrategy()
+    {
+        return new EsiResponseCacheStrategy();
+    }
+
     /**
      * Checks that at least one surrogate has ESI/1.0 capability.
      *

+ 68 - 0
src/Symfony/Component/HttpKernel/HttpCache/EsiResponseCacheStrategy.php

@@ -0,0 +1,68 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * This code is partially based on the Rack-Cache library by Ryan Tomayko,
+ * which is released under the MIT license.
+ * (based on commit 02d2b48d75bcb63cf1c0c7149c077ad256542801)
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpKernel\HttpCache;
+
+use Symfony\Component\HttpFoundation\Response;
+
+/**
+ * EsiResponseCacheStrategy knows how to compute the Response cache HTTP header
+ * based on the different ESI response cache headers.
+ *
+ * This implementation changes the master response TTL to the smallest TTL received
+ * or force validation if one of the ESI has validation cache strategy.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class EsiResponseCacheStrategy implements EsiResponseCacheStrategyInterface
+{
+    protected $cacheable = true;
+    protected $ttls = array();
+    protected $maxAges = array();
+
+    /**
+     * Adds a Response.
+     *
+     * @param Response $response
+     */
+    public function add(Response $response)
+    {
+        if ($response->isValidateable()) {
+            $this->cacheable = false;
+        } else {
+            $this->ttls[] = $response->getTtl();
+            $this->maxAges[] = $response->getMaxAge();
+        }
+    }
+
+    /**
+     * Updates the Response HTTP headers based on the embedded Responses.
+     *
+     * @param Response $response
+     */
+    public function update(Response $response)
+    {
+        if (!$this->cacheable) {
+            $response->headers->set('Cache-Control', 'no-cache, must-revalidate');
+
+            return;
+        }
+
+        $maxAge = min($this->maxAges);
+        $response->setSharedMaxAge($maxAge);
+        $response->setMaxAge(0);
+        $response->headers->set('Age', $maxAge - min($this->ttls));
+    }
+}

+ 41 - 0
src/Symfony/Component/HttpKernel/HttpCache/EsiResponseCacheStrategyInterface.php

@@ -0,0 +1,41 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * This code is partially based on the Rack-Cache library by Ryan Tomayko,
+ * which is released under the MIT license.
+ * (based on commit 02d2b48d75bcb63cf1c0c7149c077ad256542801)
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpKernel\HttpCache;
+
+use Symfony\Component\HttpFoundation\Response;
+
+/**
+ * EsiResponseCacheStrategyInterface implementations know how to compute the
+ * Response cache HTTP header based on the different ESI response cache headers.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+interface EsiResponseCacheStrategyInterface
+{
+    /**
+     * Adds a Response.
+     *
+     * @param Response $response
+     */
+    function add(Response $response);
+
+    /**
+     * Updates the Response HTTP headers based on the embedded Responses.
+     *
+     * @param Response $response
+     */
+    function update(Response $response);
+}

+ 7 - 32
src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php

@@ -31,7 +31,7 @@ class HttpCache implements HttpKernelInterface
     protected $store;
     protected $request;
     protected $esi;
-    protected $esiTtls;
+    protected $esiCacheStrategy;
 
     /**
      * Constructor.
@@ -137,7 +137,9 @@ class HttpCache implements HttpKernelInterface
         if (HttpKernelInterface::MASTER_REQUEST === $type) {
             $this->traces = array();
             $this->request = $request;
-            $this->esiTtls = array();
+            if (null !== $this->esi) {
+                $this->esiCacheStrategy = $this->esi->createCacheStrategy();
+            }
         }
 
         $path = $request->getPathInfo();
@@ -163,43 +165,16 @@ class HttpCache implements HttpKernelInterface
         }
 
         if (null !== $this->esi) {
-            $this->addEsiTtl($response);
+            $this->esiCacheStrategy->add($response);
 
-            if ($request === $this->request) {
-                $this->updateResponseCacheControl($response);
+            if (HttpKernelInterface::MASTER_REQUEST === $type) {
+                $this->esiCacheStrategy->update($response);
             }
         }
 
         return $response;
     }
 
-    /**
-     * Stores the response's TTL locally.
-     *
-     * @param Response $response
-     */
-    protected function addEsiTtl(Response $response)
-    {
-        $this->esiTtls[] = $response->isValidateable() ? -1 : $response->getTtl();
-    }
-
-    /**
-     * Changes the master response TTL to the smallest TTL received or force validation if
-     * one of the ESI has validation cache strategy.
-     *
-     * @param Response $response
-     */
-    protected function updateResponseCacheControl(Response $response)
-    {
-        $ttl = min($this->esiTtls);
-        if (-1 === $ttl) {
-            $response->headers->set('Cache-Control', 'no-cache, must-revalidate');
-        } else {
-            $response->setSharedMaxAge($ttl);
-            $response->setMaxAge(0);
-        }
-    }
-
     /**
      * Forwards the Request to the backend without storing the Response in the cache.
      *