From 480b05813cd623191729f4b1af2f21a07b486e5e Mon Sep 17 00:00:00 2001 From: Ryan Mitchell Date: Fri, 30 Aug 2024 08:57:32 +0100 Subject: [PATCH 1/2] Support specifying cache headers --- config/statamic-cache.php | 29 +++++++++++++++++++++++++++-- src/Http/Middleware/AutoCache.php | 25 ++++++++++++++++++++++--- src/Jobs/Invalidate.php | 4 +--- src/Jobs/InvalidateModel.php | 4 +--- tests/Cacher/CacherTest.php | 29 +++++++++++++++++++++++++++++ tests/TestCase.php | 2 +- 6 files changed, 81 insertions(+), 12 deletions(-) diff --git a/config/statamic-cache.php b/config/statamic-cache.php index d2645ad..55a2b2c 100644 --- a/config/statamic-cache.php +++ b/config/statamic-cache.php @@ -3,11 +3,36 @@ return [ 'enabled' => env('STATAMIC_AUTOCACHE_ENABLED', true), + /** + * Set the threshold at which we just flush the cache rather than + * invalidating individual pages + */ + 'flush_cache_limit' => env('STATAMIC_AUTOCACHE_FLUSH_LIMIT', 1000), + + /** + * Determine what headers will be set on responses depending + * on whether they were pulled from the cache or not + */ + 'headers' => [ + 'hit' => [ + 'x-statamic-cache' => 'hit', + //'cache.headers' => 'no-cache,private,max-age=1200;etag', // will pass to laravel's middleware + ], + + 'miss' => [ + 'x-statamic-cache' => 'miss', + //'cache.headers' => 'no-cache,private,max-age=900;etag', // will pass to laravel's middleware + ], + + 'not-available' => [ + 'x-statamic-cache' => 'not-available', + //'cache.headers' => 'no-cache,private,max-age=900;etag', // will pass to laravel's middleware + ], + ], + /** * Check if a database entry exists for the page when resolved from cache. * Ensure consistency between cache and database, but requires each request to do a db query */ 'split_brain_check' => env('STATAMIC_AUTOCACHE_SPLITBRAIN_CHECK', false), - - 'flush_cache_limit' => env('STATAMIC_AUTOCACHE_FLUSH_LIMIT', 1000), ]; diff --git a/src/Http/Middleware/AutoCache.php b/src/Http/Middleware/AutoCache.php index d2109e3..04e43a4 100644 --- a/src/Http/Middleware/AutoCache.php +++ b/src/Http/Middleware/AutoCache.php @@ -3,11 +3,13 @@ namespace Tv2regionerne\StatamicCache\Http\Middleware; use Closure; +use Illuminate\Http\Middleware\SetCacheHeaders; use Illuminate\Http\Response; use Statamic\Contracts\Assets\Asset; use Statamic\Contracts\Entries\Entry; use Statamic\Contracts\Globals\Variables; use Statamic\Facades\URL; +use Statamic\Support\Arr; use Statamic\Tags; use Statamic\Taxonomies\LocalizedTerm; use Tv2regionerne\StatamicCache\Facades\Store; @@ -35,7 +37,7 @@ public function handle($request, Closure $next) Store::removeWatcher($key); if (! is_callable([$response, 'wasStaticallyCached'])) { - $response->headers->add(['x-statamic-cache' => 'not-available']); + $response = $this->setHeadersFromConfig($response, 'not-available'); $this->removeStaticCacheIfNoDataIsStored(); @@ -44,7 +46,7 @@ public function handle($request, Closure $next) try { if ($response->wasStaticallyCached()) { - $response->headers->add(['x-statamic-cache' => 'hit']); + $response = $this->setHeadersFromConfig($response, 'hit'); $this->removeStaticCacheIfNoDataIsStored(); @@ -54,13 +56,30 @@ public function handle($request, Closure $next) } - $response->headers->add(['x-statamic-cache' => 'miss']); + $response = $this->setHeadersFromConfig($response, 'miss'); Store::addKeyMappingData($key); return $response; } + private function setHeadersFromConfig($response, string $type) + { + if (! $headers = config('statamic-cache.headers.'.$type, false)) { + return $response; + } + + if ($options = Arr::pull($headers, 'cache.headers')) { + $response = (new SetCacheHeaders)->handle(request(), fn ($next) => $response, $options); + } + + if ($headers = Arr::except($headers, ['cache.headers'])) { + $response->headers->add($headers); + } + + return $response; + } + private function isEnabled($request) { if (! config('statamic-cache.enabled', true)) { diff --git a/src/Jobs/Invalidate.php b/src/Jobs/Invalidate.php index 6a56600..2caa051 100644 --- a/src/Jobs/Invalidate.php +++ b/src/Jobs/Invalidate.php @@ -17,9 +17,7 @@ class Invalidate implements ShouldBeUnique, ShouldQueue /** * Create a new job instance. */ - public function __construct(public array $tags) - { - } + public function __construct(public array $tags) {} public function tags(): array { diff --git a/src/Jobs/InvalidateModel.php b/src/Jobs/InvalidateModel.php index f0118b6..1131a2f 100644 --- a/src/Jobs/InvalidateModel.php +++ b/src/Jobs/InvalidateModel.php @@ -17,9 +17,7 @@ class InvalidateModel implements ShouldBeUnique, ShouldQueue /** * Create a new job instance. */ - public function __construct(public $model) - { - } + public function __construct(public $model) {} public function tags(): array { diff --git a/tests/Cacher/CacherTest.php b/tests/Cacher/CacherTest.php index e57411c..7341fd2 100644 --- a/tests/Cacher/CacherTest.php +++ b/tests/Cacher/CacherTest.php @@ -91,3 +91,32 @@ $this->assertCount(0, StaticCache::all()); }); + +it('sets headers from config', function () { + config()->set('statamic-cache.headers', [ + 'hit' => [ + 'x-statamic-cache' => 'hit', + 'cache.headers' => 'public;max_age=1628000;etag', // will pass to laravel's middleware + ], + + 'miss' => [ + 'x-statamic-cache' => 'miss', + 'cache.headers' => 'public;max_age=2628000;etag', // will pass to laravel's middleware + ], + + 'not-available' => [ + 'x-statamic-cache' => 'not-available', + 'cache.headers' => 'public;max_age=3628000;etag', // will pass to laravel's middleware + ], + ]); + + $response = $this->get('/'); + + $this->assertSame($response->headers->get('cache-control'), 'max-age=2628000, no-cache, public'); + $this->assertSame($response->headers->get('x-statamic-cache'), 'miss'); + + $response = $this->get('/'); + + $this->assertSame($response->headers->get('cache-control'), 'max-age=1628000, public'); + $this->assertSame($response->headers->get('x-statamic-cache'), 'hit'); +}); diff --git a/tests/TestCase.php b/tests/TestCase.php index f4c43ad..6a4a721 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -39,6 +39,6 @@ protected function resolveApplicationConfiguration($app) Encrypter::generateKey($app['config']['app.cipher']) )); - $app['config']->set('statamic-cache', require(__DIR__.'/../config/statamic-cache.php')); + $app['config']->set('statamic-cache', require (__DIR__.'/../config/statamic-cache.php')); } } From 349ca0d1fcb89762c2e370b2c279a7d2f579367a Mon Sep 17 00:00:00 2001 From: ryanmitchell Date: Fri, 30 Aug 2024 07:58:41 +0000 Subject: [PATCH 2/2] Apply pint changes --- src/Jobs/Invalidate.php | 4 +++- src/Jobs/InvalidateModel.php | 4 +++- tests/TestCase.php | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/Jobs/Invalidate.php b/src/Jobs/Invalidate.php index 2caa051..6a56600 100644 --- a/src/Jobs/Invalidate.php +++ b/src/Jobs/Invalidate.php @@ -17,7 +17,9 @@ class Invalidate implements ShouldBeUnique, ShouldQueue /** * Create a new job instance. */ - public function __construct(public array $tags) {} + public function __construct(public array $tags) + { + } public function tags(): array { diff --git a/src/Jobs/InvalidateModel.php b/src/Jobs/InvalidateModel.php index 1131a2f..f0118b6 100644 --- a/src/Jobs/InvalidateModel.php +++ b/src/Jobs/InvalidateModel.php @@ -17,7 +17,9 @@ class InvalidateModel implements ShouldBeUnique, ShouldQueue /** * Create a new job instance. */ - public function __construct(public $model) {} + public function __construct(public $model) + { + } public function tags(): array { diff --git a/tests/TestCase.php b/tests/TestCase.php index 6a4a721..f4c43ad 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -39,6 +39,6 @@ protected function resolveApplicationConfiguration($app) Encrypter::generateKey($app['config']['app.cipher']) )); - $app['config']->set('statamic-cache', require (__DIR__.'/../config/statamic-cache.php')); + $app['config']->set('statamic-cache', require(__DIR__.'/../config/statamic-cache.php')); } }