From b7aa7ee79a50c906c00e1cfe35c016301cb6c46e Mon Sep 17 00:00:00 2001 From: Tim Kelty Date: Mon, 20 Jul 2026 09:10:32 -0400 Subject: [PATCH] Add static cache purge commands --- src/StaticCache.php | 4 +- src/cli/controllers/StaticCacheController.php | 47 ++++++++++ tests/unit/StaticCacheControllerTest.php | 91 +++++++++++++++++++ 3 files changed, 140 insertions(+), 2 deletions(-) create mode 100644 tests/unit/StaticCacheControllerTest.php diff --git a/src/StaticCache.php b/src/StaticCache.php index 640fb387..0e5d7c06 100644 --- a/src/StaticCache.php +++ b/src/StaticCache.php @@ -195,8 +195,8 @@ private function handleInvalidateElementCaches(InvalidateElementCachesEvent $eve private function handleRegisterCacheOptions(RegisterCacheOptionsEvent $event): void { $event->options[] = [ - 'key' => 'craft-cloud-caches', - 'label' => Craft::t('app', 'Craft Cloud caches'), + 'key' => 'craft-cloud-static-cache', + 'label' => Craft::t('app', 'Craft Cloud static cache'), 'action' => [$this, 'purgeAll'], ]; } diff --git a/src/cli/controllers/StaticCacheController.php b/src/cli/controllers/StaticCacheController.php index c3982962..3dd1f661 100644 --- a/src/cli/controllers/StaticCacheController.php +++ b/src/cli/controllers/StaticCacheController.php @@ -4,10 +4,47 @@ use craft\cloud\Module; use craft\console\Controller; +use yii\console\Exception; use yii\console\ExitCode; class StaticCacheController extends Controller { + public function actionPurgeAll(): int + { + $this->do('Purging static cache', function() { + $module = Module::getInstance(); + $environmentId = $this->environmentId(); + $module->getStaticCache()->purgeTags( + "$environmentId:uri", + "$environmentId:cdn", + ); + }); + + return ExitCode::OK; + } + + public function actionPurgeCdn(): int + { + $this->do('Purging CDN static cache', function() { + $module = Module::getInstance(); + $environmentId = $this->environmentId(); + $module->getStaticCache()->purgeTags("$environmentId:cdn"); + }); + + return ExitCode::OK; + } + + public function actionPurgeOrigin(): int + { + $this->do('Purging origin static cache', function() { + $module = Module::getInstance(); + $environmentId = $this->environmentId(); + $module->getStaticCache()->purgeTags("$environmentId:uri"); + }); + + return ExitCode::OK; + } + public function actionPurgePrefixes(string ...$prefixes): int { $this->do('Purging prefixes', function() use ($prefixes) { @@ -25,4 +62,14 @@ public function actionPurgeTags(string ...$tags): int return ExitCode::OK; } + + private function environmentId(): string + { + $environmentId = Module::getInstance()->getConfig()->environmentId; + if (!$environmentId) { + throw new Exception('Static cache purges require an environment ID.'); + } + + return $environmentId; + } } diff --git a/tests/unit/StaticCacheControllerTest.php b/tests/unit/StaticCacheControllerTest.php new file mode 100644 index 00000000..38f7c5c6 --- /dev/null +++ b/tests/unit/StaticCacheControllerTest.php @@ -0,0 +1,91 @@ +previousModule = Module::getInstance(); + $module = new Module('cloud'); + $module->getConfig()->environmentId = '123-environment-id'; + $this->staticCache = new TestStaticCache(); + $module->set('staticCache', $this->staticCache); + Module::setInstance($module); + } + + protected function _after(): void + { + Module::setInstance($this->previousModule); + + parent::_after(); + } + + public function testPurgeActions(): void + { + $controller = new StaticCacheController('static-cache', Craft::$app); + + $controller->actionPurgeAll(); + $controller->actionPurgeOrigin(); + $controller->actionPurgeCdn(); + + $this->assertSame([ + ['123-environment-id:uri', '123-environment-id:cdn'], + ['123-environment-id:uri'], + ['123-environment-id:cdn'], + ], $this->staticCache->purges); + } + + public function testPurgeFailurePropagates(): void + { + $this->staticCache->fail = true; + $this->expectException(\RuntimeException::class); + + (new StaticCacheController('static-cache', Craft::$app))->actionPurgeAll(); + } + + public function testPurgeRequiresEnvironmentId(): void + { + Module::getInstance()->getConfig()->environmentId = null; + $this->expectException(\yii\console\Exception::class); + $this->expectExceptionMessage('Static cache purges require an environment ID.'); + + (new StaticCacheController('static-cache', Craft::$app))->actionPurgeAll(); + } + + public function testPurgeRequiresNonEmptyEnvironmentId(): void + { + Module::getInstance()->getConfig()->environmentId = ''; + $this->expectException(\yii\console\Exception::class); + $this->expectExceptionMessage('Static cache purges require an environment ID.'); + + (new StaticCacheController('static-cache', Craft::$app))->actionPurgeAll(); + } +} + +class TestStaticCache extends StaticCache +{ + public array $purges = []; + public bool $fail = false; + + public function purgeTags(string|StaticCacheTag ...$tags): void + { + if ($this->fail) { + throw new \RuntimeException('Purge failed.'); + } + + $this->purges[] = $tags; + } +}