Kevinrob\GuzzleCache\CacheMiddleware::__invoke PHP Method

__invoke() public method

public __invoke ( callable $handler ) : callable
$handler callable
return callable
    public function __invoke(callable $handler)
    {
        return function (RequestInterface $request, array $options) use(&$handler) {
            if (!isset($this->httpMethods[strtoupper($request->getMethod())])) {
                // No caching for this method allowed
                return $handler($request, $options)->then(function (ResponseInterface $response) {
                    return $response->withHeader(self::HEADER_CACHE_INFO, self::HEADER_CACHE_MISS);
                });
            }
            if ($request->hasHeader(self::HEADER_RE_VALIDATION)) {
                // It's a re-validation request, so bypass the cache!
                return $handler($request->withoutHeader(self::HEADER_RE_VALIDATION), $options);
            }
            // Retrieve information from request (Cache-Control)
            $reqCacheControl = new KeyValueHttpHeader($request->getHeader('Cache-Control'));
            $onlyFromCache = $reqCacheControl->has('only-if-cached');
            $staleResponse = $reqCacheControl->has('max-stale') && $reqCacheControl->get('max-stale') === '';
            $maxStaleCache = $reqCacheControl->get('max-stale', null);
            $minFreshCache = $reqCacheControl->get('min-fresh', null);
            // If cache => return new FulfilledPromise(...) with response
            $cacheEntry = $this->cacheStorage->fetch($request);
            if ($cacheEntry instanceof CacheEntry) {
                $body = $cacheEntry->getResponse()->getBody();
                if ($body->tell() > 0) {
                    $body->rewind();
                }
                if ($cacheEntry->isFresh() && ($minFreshCache === null || $cacheEntry->getStaleAge() + (int) $minFreshCache <= 0)) {
                    // Cache HIT!
                    return new FulfilledPromise($cacheEntry->getResponse()->withHeader(self::HEADER_CACHE_INFO, self::HEADER_CACHE_HIT));
                } elseif ($staleResponse || $maxStaleCache !== null && $cacheEntry->getStaleAge() <= $maxStaleCache) {
                    // Staled cache!
                    return new FulfilledPromise($cacheEntry->getResponse()->withHeader(self::HEADER_CACHE_INFO, self::HEADER_CACHE_HIT));
                } elseif ($cacheEntry->hasValidationInformation() && !$onlyFromCache) {
                    // Re-validation header
                    $request = static::getRequestWithReValidationHeader($request, $cacheEntry);
                    if ($cacheEntry->staleWhileValidate()) {
                        static::addReValidationRequest($request, $this->cacheStorage, $cacheEntry);
                        return new FulfilledPromise($cacheEntry->getResponse()->withHeader(self::HEADER_CACHE_INFO, self::HEADER_CACHE_STALE));
                    }
                }
            } else {
                $cacheEntry = null;
            }
            if ($cacheEntry === null && $onlyFromCache) {
                // Explicit asking of a cached response => 504
                return new FulfilledPromise(new Response(504));
            }
            /** @var Promise $promise */
            $promise = $handler($request, $options);
            return $promise->then(function (ResponseInterface $response) use($request, $cacheEntry) {
                // Check if error and looking for a staled content
                if ($response->getStatusCode() >= 500) {
                    $responseStale = static::getStaleResponse($cacheEntry);
                    if ($responseStale instanceof ResponseInterface) {
                        return $responseStale;
                    }
                }
                $update = false;
                if ($response->getStatusCode() == 304 && $cacheEntry instanceof CacheEntry) {
                    // Not modified => cache entry is re-validate
                    /** @var ResponseInterface $response */
                    $response = $response->withStatus($cacheEntry->getResponse()->getStatusCode())->withHeader(self::HEADER_CACHE_INFO, self::HEADER_CACHE_HIT);
                    $response = $response->withBody($cacheEntry->getResponse()->getBody());
                    // Merge headers of the "304 Not Modified" and the cache entry
                    foreach ($cacheEntry->getResponse()->getHeaders() as $headerName => $headerValue) {
                        if (!$response->hasHeader($headerName)) {
                            $response = $response->withHeader($headerName, $headerValue);
                        }
                    }
                    $update = true;
                } else {
                    $response = $response->withHeader(self::HEADER_CACHE_INFO, self::HEADER_CACHE_MISS);
                }
                return self::addToCache($this->cacheStorage, $request, $response, $update);
            }, function (\Exception $ex) use($cacheEntry) {
                if ($ex instanceof TransferException) {
                    $response = static::getStaleResponse($cacheEntry);
                    if ($response instanceof ResponseInterface) {
                        return $response;
                    }
                }
                throw $ex;
            });
        };
    }