From eb62be80069d3678e36cdbd2061ab7350f24936e Mon Sep 17 00:00:00 2001 From: Shea Date: Tue, 17 Feb 2026 12:07:23 +1300 Subject: [PATCH 1/3] Add Statamic 6 compatibility --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index dcc4db6..e8e633e 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,7 @@ ], "require": { "php": "^8.0", - "statamic/cms": "^5.0" + "statamic/cms": "^5.0|^6.0" }, "require-dev": { "pestphp/pest": "^3.0", From d424266303f473978cfbe5c8ba8a83f3bd7bd2d3 Mon Sep 17 00:00:00 2001 From: Shea Date: Fri, 20 Feb 2026 15:02:18 +1300 Subject: [PATCH 2/3] Add CachePurged event - Create CachePurged event with $urls and $purgedEverything properties - Fire event from PurgeCloudflareCache listener after successful purges - Fire event from PurgeCloudflareCacheJob after successful purges - Supports both synchronous and queued purge paths Co-Authored-By: Claude Sonnet 4.5 --- src/Events/CachePurged.php | 11 +++++++++++ src/Jobs/PurgeCloudflareCacheJob.php | 3 +++ src/Listeners/PurgeCloudflareCache.php | 3 +++ 3 files changed, 17 insertions(+) create mode 100644 src/Events/CachePurged.php diff --git a/src/Events/CachePurged.php b/src/Events/CachePurged.php new file mode 100644 index 0000000..8866bad --- /dev/null +++ b/src/Events/CachePurged.php @@ -0,0 +1,11 @@ +purgeEverything(); + event(new CachePurged([], true)); } elseif (! empty($this->urls)) { if (config('cloudflare-cache.debug')) { Log::debug('[Cloudflare Cache] Queued job purging URLs: ' . implode(', ', $this->urls)); } $client->purgeUrls($this->urls); + event(new CachePurged($this->urls, false)); } else { // This case should ideally not happen if dispatched correctly (null vs empty array) // but we log it just in case. diff --git a/src/Listeners/PurgeCloudflareCache.php b/src/Listeners/PurgeCloudflareCache.php index f75cec7..c3f1a8d 100644 --- a/src/Listeners/PurgeCloudflareCache.php +++ b/src/Listeners/PurgeCloudflareCache.php @@ -2,6 +2,7 @@ namespace Eminos\StatamicCloudflareCache\Listeners; +use Eminos\StatamicCloudflareCache\Events\CachePurged; use Eminos\StatamicCloudflareCache\Jobs\PurgeCloudflareCacheJob; // Updated job import namespace use Eminos\StatamicCloudflareCache\Http\Client; // Updated client import namespace use Statamic\Events\Event; @@ -86,6 +87,7 @@ protected function purgeSynchronously(array $urls): void Log::debug('[Cloudflare Cache] Synchronously purging URLs: ' . implode(', ', $urls)); } $this->client->purgeUrls($urls); + event(new CachePurged($urls, false)); return; } @@ -94,6 +96,7 @@ protected function purgeSynchronously(array $urls): void Log::debug('[Cloudflare Cache] Synchronously purging everything.'); } $this->client->purgeEverything(); + event(new CachePurged([], true)); } } From 74f44d27daab9e97800aa2cdc6e51c9d7ca56c67 Mon Sep 17 00:00:00 2001 From: Shea Date: Fri, 20 Feb 2026 15:11:48 +1300 Subject: [PATCH 3/3] Add tests for CachePurged event - Test event is fired after synchronous purge with URLs - Test event is fired after synchronous purge everything - Test event is fired after queued purge with URLs - Test event is fired after queued purge everything - Test event is not fired when cache is disabled All 22 tests passing. Co-Authored-By: Claude Sonnet 4.5 --- tests/Feature/PurgeCacheJobTest.php | 79 ++++++++++++++++++++++++ tests/Feature/PurgeCacheListenerTest.php | 46 ++++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 tests/Feature/PurgeCacheJobTest.php diff --git a/tests/Feature/PurgeCacheJobTest.php b/tests/Feature/PurgeCacheJobTest.php new file mode 100644 index 0000000..429d7a6 --- /dev/null +++ b/tests/Feature/PurgeCacheJobTest.php @@ -0,0 +1,79 @@ + Http::response([ + 'success' => true, + ], 200), + ]); + } + + #[Test] + public function it_fires_cache_purged_event_after_purging_specific_urls() + { + Event::fake(); + config(['cloudflare-cache.enabled' => true]); + + $urls = ['http://test.com/page1', 'http://test.com/page2']; + $job = new PurgeCloudflareCacheJob($urls); + + $clientMock = $this->mock(Client::class); + $clientMock->shouldReceive('purgeUrls')->once()->with($urls); + + $job->handle($clientMock); + + Event::assertDispatched(CachePurged::class, function ($e) use ($urls) { + return $e->urls === $urls && !$e->purgedEverything; + }); + } + + #[Test] + public function it_fires_cache_purged_event_after_purging_everything() + { + Event::fake(); + config(['cloudflare-cache.enabled' => true]); + + $job = new PurgeCloudflareCacheJob(null); + + $clientMock = $this->mock(Client::class); + $clientMock->shouldReceive('purgeEverything')->once(); + + $job->handle($clientMock); + + Event::assertDispatched(CachePurged::class, function ($e) { + return $e->purgedEverything && empty($e->urls); + }); + } + + #[Test] + public function it_does_not_fire_event_when_cache_is_disabled() + { + Event::fake(); + config(['cloudflare-cache.enabled' => false]); + + $job = new PurgeCloudflareCacheJob(['http://test.com/page']); + + $clientMock = $this->mock(Client::class); + $clientMock->shouldNotReceive('purgeUrls'); + $clientMock->shouldNotReceive('purgeEverything'); + + $job->handle($clientMock); + + Event::assertNotDispatched(CachePurged::class); + } +} diff --git a/tests/Feature/PurgeCacheListenerTest.php b/tests/Feature/PurgeCacheListenerTest.php index 9f989db..cb8a1ac 100644 --- a/tests/Feature/PurgeCacheListenerTest.php +++ b/tests/Feature/PurgeCacheListenerTest.php @@ -10,8 +10,10 @@ use Statamic\Events\GlobalSetDeleted; use Statamic\Contracts\Entries\Entry; use Statamic\Contracts\Entries\Collection; +use Illuminate\Support\Facades\Event; use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Queue; // Add Queue facade +use Eminos\StatamicCloudflareCache\Events\CachePurged; use Eminos\StatamicCloudflareCache\Jobs\PurgeCloudflareCacheJob; use Mockery; use PHPUnit\Framework\Attributes\Test; @@ -309,4 +311,48 @@ public function it_does_not_purge_when_global_set_saved_event_is_disabled_in_con Queue::assertNothingPushed(); Http::assertNothingSent(); } + + #[Test] + public function it_fires_cache_purged_event_after_synchronous_purge_with_urls() + { + Event::fake(); + config(['cloudflare-cache.queue_purge' => false]); + + $entry = $this->mockEntry('http://test.com/entry', 'http://test.com/collection'); + $event = new EntrySaved($entry); + + $clientMock = $this->mock(Client::class); + $clientMock->shouldReceive('purgeUrls')->once(); + + $listener = $this->app->make(PurgeCloudflareCache::class); + $listener->handle($event); + + Event::assertDispatched(CachePurged::class, function ($e) { + return !$e->purgedEverything && count($e->urls) > 0; + }); + } + + #[Test] + public function it_fires_cache_purged_event_after_synchronous_purge_everything() + { + Event::fake(); + config([ + 'cloudflare-cache.queue_purge' => false, + 'cloudflare-cache.purge_urls' => false, + 'cloudflare-cache.purge_everything_fallback' => true, + ]); + + $entry = $this->mockEntry(); + $event = new EntrySaved($entry); + + $clientMock = $this->mock(Client::class); + $clientMock->shouldReceive('purgeEverything')->once(); + + $listener = $this->app->make(PurgeCloudflareCache::class); + $listener->handle($event); + + Event::assertDispatched(CachePurged::class, function ($e) { + return $e->purgedEverything && empty($e->urls); + }); + } }