Source of file RequestCacheMiddleware.php
Size: 8,951 Bytes - Last Modified: 2021-12-24T06:50:57+00:00
/var/www/docs.ssmods.com/process/src/src/SilverStripe/RequestCacheMiddleware.php
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351 | <?php namespace Heyday\CacheInclude\SilverStripe; use Heyday\CacheInclude\CacheInclude; use Heyday\CacheInclude\ExpressionLanguage; use SilverStripe\Control\Controller; use SilverStripe\Control\HTTPRequest; use SilverStripe\Control\HTTPRequestBuilder; use SilverStripe\Control\HTTPResponse; use SilverStripe\Control\Middleware\HTTPMiddleware; use SilverStripe\Core\Injector\Injector; use SilverStripe\Core\Startup\ErrorDirector; use SilverStripe\Security\Security; use SilverStripe\Security\SecurityToken; use SilverStripe\Versioned\Versioned; /** * Class RequestCache * @package Heyday\CacheInclude */ class RequestCacheMiddleware implements HTTPMiddleware { /** * The constant used when replacing tokens in an response */ const REPLACED_TOKEN_PREFIX = '!!ReplacedToken.'; /** * @var CacheInclude */ protected $cache; /** * @var string */ protected $name; /** * @var array */ protected $saveExcludeRules = []; /** * @var array */ protected $saveIncludeRules = []; /** * @var array */ protected $fetchExcludeRules = []; /** * @var array */ protected $fetchIncludeRules = []; /** * @var array */ protected $tokens = []; /** * @var ExpressionLanguage */ protected $expressionLanguage; /** * @var array */ protected $extraExpressionVars = []; /** * @param CacheInclude $cache * @param ExpressionLanguage $expressionLanguage * @param string $name * @param array $tokens */ public function __construct( CacheInclude $cache, ExpressionLanguage $expressionLanguage, $name = 'Global', $tokens = [] ) { $this->cache = $cache; $this->expressionLanguage = $expressionLanguage; $this->name = $name; $this->setTokens($tokens); } /** * @param CacheInclude $cache */ public function setCache(CacheInclude $cache) { $this->cache = $cache; } /** * @param mixed $fetchExcludeRules */ public function setFetchExcludeRules(array $fetchExcludeRules) { $this->fetchExcludeRules = $fetchExcludeRules; } /** * @param mixed $fetchIncludeRules */ public function setFetchIncludeRules(array $fetchIncludeRules) { $this->fetchIncludeRules = $fetchIncludeRules; } /** * @param mixed $saveExcludeRules */ public function setSaveExcludeRules(array $saveExcludeRules) { $this->saveExcludeRules = $saveExcludeRules; } /** * @param mixed $saveIncludeRules */ public function setSaveIncludeRules(array $saveIncludeRules) { $this->saveIncludeRules = $saveIncludeRules; } /** * @param array $extraExpressionVars */ public function setExtraExpressionVars($extraExpressionVars) { $this->extraExpressionVars = $extraExpressionVars; } /** * @param $tokens */ public function setTokens($tokens) { if (is_array($tokens)) { foreach ($tokens as $token) { if ($token instanceof SecurityToken) { $this->tokens[] = $token; } } } } /** * @return bool */ protected function hasTokens() { return count($this->tokens) > 0; } /** * Checks whether the middleware has been called by ErrorDirector instead of Director, * indicating that we're in an unstable state unsuitable for caching (e.g. dev/build) * * @return bool */ protected function getIsInErrorDirector() { $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); foreach ($backtrace as $frame) { if (isset($frame['class']) && $frame['class'] === ErrorDirector::class) { return true; } } return false; } /** * @param HTTPRequest $request * @param callable $delegate * @return bool|HTTPResponse * @throws \Psr\SimpleCache\InvalidArgumentException */ public function process(HTTPRequest $request, callable $delegate) { if ($this->getIsInErrorDirector()) { return $delegate($request); } if ($this->allowFetch($request) && $response = $this->getCachedResponse($request)) { return $response; } $response = $delegate($request); if ($this->allowSave($request, $response)) { $this->saveResponseToCache($response, $request); } return $response; } /** * @param HTTPRequest $request * @return HTTPResponse * @throws \Psr\SimpleCache\InvalidArgumentException */ protected function getCachedResponse(HTTPRequest $request) { Versioned::choose_site_stage($request); if ($request->getURL() == '') { $request = clone $request; $request->setUrl('home'); } $response = $this->cache->get( $this->name, Injector::inst()->create('CacheIncludeKeyCreator', $this->getController($request)) ); if (!$response instanceof HTTPResponse) { return null; } $response = $this->replaceTokensInResponseBody( $response, function($token) { return self::REPLACED_TOKEN_PREFIX . $token->getName(); }, function($token) { return $token->getValue(); } ); return $response; } /** * @param HTTPResponse $response * @param HTTPRequest $request */ protected function saveResponseToCache(HTTPResponse $response, HTTPRequest $request) { $response = $this->replaceTokensInResponseBody( clone $response, function($token) { return $token->getValue(); }, function($token) { return self::REPLACED_TOKEN_PREFIX . $token->getName(); } ); $this->cache->set( $this->name, $response, Injector::inst()->create('CacheIncludeKeyCreator', $this->getController($request)) ); } /** * @param HTTPResponse $response * @param callable $find * @param callable $replace * @return HTTPResponse */ protected function replaceTokensInResponseBody(HTTPResponse $response, callable $find, callable $replace) { if (!$this->hasTokens()) { return $response; } $body = $response->getBody(); foreach ($this->tokens as $token) { $body = str_replace($find($token), $replace($token), $body); } return $response->setBody($body); } /** * @param HTTPRequest $request * @return Controller */ protected function getController(HTTPRequest $request) { $controller = new Controller(); $controller->setRequest($request); $controller->setURLParams($request->allParams()); return $controller; } /** * @param HTTPRequest $request * @return bool */ protected function allowFetch(HTTPRequest $request) { $vars = [ 'request' => $request, 'member' => Security::getCurrentUser(), 'session' => $request->getSession()->getAll() ] + $this->extraExpressionVars; if (count($this->fetchExcludeRules)) { foreach ($this->fetchExcludeRules as $rule) { if ($this->expressionLanguage->evaluate($rule, $vars)) { return false; } } } if (count($this->fetchIncludeRules)) { foreach ($this->fetchIncludeRules as $rule) { if (!$this->expressionLanguage->evaluate($rule, $vars)) { return false; } } } return true; } /** * @param HTTPRequest $request * @param HTTPResponse $response * @return bool */ protected function allowSave(HTTPRequest $request, HTTPResponse $response) { $vars = [ 'request' => $request, 'response' => $response, 'member' => Security::getCurrentUser(), 'session' => $request->getSession()->getAll() ] + $this->extraExpressionVars; if (count($this->saveExcludeRules)) { foreach ($this->saveExcludeRules as $rule) { if ($this->expressionLanguage->evaluate($rule, $vars)) { return false; } } } if (count($this->saveIncludeRules)) { foreach ($this->saveIncludeRules as $rule) { if (!$this->expressionLanguage->evaluate($rule, $vars)) { return false; } } } return true; } } |