name: ResponseCacheStrategy class_comment: '# * ResponseCacheStrategy knows how to compute the Response cache HTTP header # * based on the different response cache headers. # * # * This implementation changes the main response TTL to the smallest TTL received # * or force validation if one of the surrogates has validation cache strategy. # * # * @author Fabien Potencier ' dependencies: - name: Response type: class source: Symfony\Component\HttpFoundation\Response properties: [] methods: - name: willMakeFinalResponseUncacheable visibility: private parameters: - name: response comment: "# * ResponseCacheStrategy knows how to compute the Response cache HTTP\ \ header\n# * based on the different response cache headers.\n# *\n# * This implementation\ \ changes the main response TTL to the smallest TTL received\n# * or force validation\ \ if one of the surrogates has validation cache strategy.\n# *\n# * @author Fabien\ \ Potencier \n# */\n# class ResponseCacheStrategy implements\ \ ResponseCacheStrategyInterface\n# {\n# /**\n# * Cache-Control headers that are\ \ sent to the final response if they appear in ANY of the responses.\n# */\n#\ \ private const OVERRIDE_DIRECTIVES = ['private', 'no-cache', 'no-store', 'no-transform',\ \ 'must-revalidate', 'proxy-revalidate'];\n# \n# /**\n# * Cache-Control headers\ \ that are sent to the final response if they appear in ALL of the responses.\n\ # */\n# private const INHERIT_DIRECTIVES = ['public', 'immutable'];\n# \n# private\ \ int $embeddedResponses = 0;\n# private bool $isNotCacheableResponseEmbedded\ \ = false;\n# private int $age = 0;\n# private \\DateTimeInterface|false|null\ \ $lastModified = null;\n# private array $flagDirectives = [\n# 'no-cache' =>\ \ null,\n# 'no-store' => null,\n# 'no-transform' => null,\n# 'must-revalidate'\ \ => null,\n# 'proxy-revalidate' => null,\n# 'public' => null,\n# 'private' =>\ \ null,\n# 'immutable' => null,\n# ];\n# private array $ageDirectives = [\n# 'max-age'\ \ => null,\n# 's-maxage' => null,\n# 'expires' => null,\n# ];\n# \n# public function\ \ add(Response $response): void\n# {\n# ++$this->embeddedResponses;\n# \n# foreach\ \ (self::OVERRIDE_DIRECTIVES as $directive) {\n# if ($response->headers->hasCacheControlDirective($directive))\ \ {\n# $this->flagDirectives[$directive] = true;\n# }\n# }\n# \n# foreach (self::INHERIT_DIRECTIVES\ \ as $directive) {\n# if (false !== $this->flagDirectives[$directive]) {\n# $this->flagDirectives[$directive]\ \ = $response->headers->hasCacheControlDirective($directive);\n# }\n# }\n# \n\ # $age = $response->getAge();\n# $this->age = max($this->age, $age);\n# \n# if\ \ ($this->willMakeFinalResponseUncacheable($response)) {\n# $this->isNotCacheableResponseEmbedded\ \ = true;\n# \n# return;\n# }\n# \n# $isHeuristicallyCacheable = $response->headers->hasCacheControlDirective('public');\n\ # $maxAge = $response->headers->hasCacheControlDirective('max-age') ? (int) $response->headers->getCacheControlDirective('max-age')\ \ : null;\n# $this->storeRelativeAgeDirective('max-age', $maxAge, $age, $isHeuristicallyCacheable);\n\ # $sharedMaxAge = $response->headers->hasCacheControlDirective('s-maxage') ? (int)\ \ $response->headers->getCacheControlDirective('s-maxage') : $maxAge;\n# $this->storeRelativeAgeDirective('s-maxage',\ \ $sharedMaxAge, $age, $isHeuristicallyCacheable);\n# \n# $expires = $response->getExpires();\n\ # $expires = null !== $expires ? (int) $expires->format('U') - (int) $response->getDate()->format('U')\ \ : null;\n# $this->storeRelativeAgeDirective('expires', $expires >= 0 ? $expires\ \ : null, 0, $isHeuristicallyCacheable);\n# \n# if (false !== $this->lastModified)\ \ {\n# $lastModified = $response->getLastModified();\n# $this->lastModified =\ \ $lastModified ? max($this->lastModified, $lastModified) : false;\n# }\n# }\n\ # \n# public function update(Response $response): void\n# {\n# // if we have no\ \ embedded Response, do nothing\n# if (0 === $this->embeddedResponses) {\n# return;\n\ # }\n# \n# // Remove Etag since it cannot be merged from embedded responses.\n\ # $response->setEtag(null);\n# \n# $this->add($response);\n# \n# $response->headers->set('Age',\ \ $this->age);\n# \n# if ($this->isNotCacheableResponseEmbedded) {\n# $response->setLastModified(null);\n\ # \n# if ($this->flagDirectives['no-store']) {\n# $response->headers->set('Cache-Control',\ \ 'no-cache, no-store, must-revalidate');\n# } else {\n# $response->headers->set('Cache-Control',\ \ 'no-cache, must-revalidate');\n# }\n# \n# return;\n# }\n# \n# $response->setLastModified($this->lastModified\ \ ?: null);\n# \n# $flags = array_filter($this->flagDirectives);\n# \n# if (isset($flags['must-revalidate']))\ \ {\n# $flags['no-cache'] = true;\n# }\n# \n# $response->headers->set('Cache-Control',\ \ implode(', ', array_keys($flags)));\n# \n# $maxAge = null;\n# \n# if (is_numeric($this->ageDirectives['max-age']))\ \ {\n# $maxAge = $this->ageDirectives['max-age'] + $this->age;\n# $response->headers->addCacheControlDirective('max-age',\ \ $maxAge);\n# }\n# \n# if (is_numeric($this->ageDirectives['s-maxage'])) {\n\ # $sMaxage = $this->ageDirectives['s-maxage'] + $this->age;\n# \n# if ($maxAge\ \ !== $sMaxage) {\n# $response->headers->addCacheControlDirective('s-maxage',\ \ $sMaxage);\n# }\n# }\n# \n# if (is_numeric($this->ageDirectives['expires']))\ \ {\n# $date = clone $response->getDate();\n# $date = $date->modify('+'.($this->ageDirectives['expires']\ \ + $this->age).' seconds');\n# $response->setExpires($date);\n# }\n# }\n# \n\ # /**\n# * RFC2616, Section 13.4.\n# *\n# * @see https://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.4" - name: storeRelativeAgeDirective visibility: private parameters: - name: directive - name: value - name: age - name: isHeuristicallyCacheable comment: '# * Store lowest max-age/s-maxage/expires for the final response. # * # * The response might have been stored in cache a while ago. To keep things comparable, # * we have to subtract the age so that the value is normalized for an age of 0. # * # * If the value is lower than the currently stored value, we update the value, to keep a rolling # * minimal value of each instruction. # * # * If the value is NULL and the isHeuristicallyCacheable parameter is false, the directive will # * not be set on the final response. In this case, not all responses had the directive set and no # * value can be found that satisfies the requirements of all responses. The directive will be dropped # * from the final response. # * # * If the isHeuristicallyCacheable parameter is true, however, the current response has been marked # * as cacheable in a public (shared) cache, but did not provide an explicit lifetime that would serve # * as an upper bound. In this case, we can proceed and possibly keep the directive on the final response.' traits: - Symfony\Component\HttpFoundation\Response interfaces: - ResponseCacheStrategyInterface