From 0827bfd53052c73e0ff4eee9cf2d6b46b5e0caf0 Mon Sep 17 00:00:00 2001 From: Ryan Mitchell Date: Thu, 12 Mar 2026 09:56:48 +0000 Subject: [PATCH] Add CLI for flush/invalidate/list --- src/Commands/Flush.php | 22 ++++++++ src/Commands/Invalidate.php | 28 ++++++++++ src/Commands/ListUrls.php | 36 +++++++++++++ src/ServiceProvider.php | 6 +++ tests/Unit/CommandsTest.php | 105 ++++++++++++++++++++++++++++++++++++ 5 files changed, 197 insertions(+) create mode 100644 src/Commands/Flush.php create mode 100644 src/Commands/Invalidate.php create mode 100644 src/Commands/ListUrls.php create mode 100644 tests/Unit/CommandsTest.php diff --git a/src/Commands/Flush.php b/src/Commands/Flush.php new file mode 100644 index 0000000..458e883 --- /dev/null +++ b/src/Commands/Flush.php @@ -0,0 +1,22 @@ +info("Flushed {$count} tracked URL(s)."); + } +} diff --git a/src/Commands/Invalidate.php b/src/Commands/Invalidate.php new file mode 100644 index 0000000..37e777b --- /dev/null +++ b/src/Commands/Invalidate.php @@ -0,0 +1,28 @@ +argument('url'); + + if (! Tracker::has($url)) { + $this->warn("URL not found in tracker: {$url}"); + + return 1; + } + + Tracker::remove($url); + + $this->info("Invalidated: {$url}"); + } +} diff --git a/src/Commands/ListUrls.php b/src/Commands/ListUrls.php new file mode 100644 index 0000000..63ab9a3 --- /dev/null +++ b/src/Commands/ListUrls.php @@ -0,0 +1,36 @@ +option('url')) { + $prefix = rtrim($filter, '*'); + $all = $all->filter(fn ($data) => str_starts_with($data['url'], $prefix)); + } + + if ($all->isEmpty()) { + $this->info('No tracked URLs found.'); + + return; + } + + $this->table( + ['URL', 'Tags'], + $all->map(fn ($data) => [$data['url'], implode(', ', $data['tags'])])->values() + ); + + $this->info("Total: {$all->count()} URL(s)"); + } +} diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php index 05d8545..6b930fa 100644 --- a/src/ServiceProvider.php +++ b/src/ServiceProvider.php @@ -9,6 +9,12 @@ class ServiceProvider extends AddonServiceProvider { + protected $commands = [ + Commands\Flush::class, + Commands\Invalidate::class, + Commands\ListUrls::class, + ]; + protected $actions = [ Actions\ClearCache::class, Actions\ViewCacheTags::class, diff --git a/tests/Unit/CommandsTest.php b/tests/Unit/CommandsTest.php new file mode 100644 index 0000000..64a9d75 --- /dev/null +++ b/tests/Unit/CommandsTest.php @@ -0,0 +1,105 @@ +assertCount(2, Tracker::all()); + + $this->artisan('cache-tracker:flush') + ->expectsOutput('Flushed 2 tracked URL(s).') + ->assertExitCode(0); + + $this->assertCount(0, Tracker::all()); + } + + #[Test] + public function flush_command_reports_zero_when_nothing_tracked() + { + $this->artisan('cache-tracker:flush') + ->expectsOutput('Flushed 0 tracked URL(s).') + ->assertExitCode(0); + } + + #[Test] + public function invalidate_command_removes_url() + { + Tracker::add('/page1', ['products:1']); + Tracker::add('/page2', ['products:2']); + + $this->artisan('cache-tracker:invalidate', ['url' => '/page1']) + ->expectsOutput('Invalidated: /page1') + ->assertExitCode(0); + + $this->assertCount(1, Tracker::all()); + $this->assertNull(Tracker::get('/page1')); + $this->assertNotNull(Tracker::get('/page2')); + } + + #[Test] + public function invalidate_command_warns_when_url_not_found() + { + $this->artisan('cache-tracker:invalidate', ['url' => '/not-tracked']) + ->expectsOutput('URL not found in tracker: /not-tracked') + ->assertExitCode(1); + } + + #[Test] + public function list_command_shows_all_tracked_urls() + { + Tracker::add('/page1', ['products:1', 'category:electronics']); + Tracker::add('/page2', ['products:2']); + + $this->artisan('cache-tracker:list') + ->expectsTable(['URL', 'Tags'], [ + ['/page1', 'products:1, category:electronics'], + ['/page2', 'products:2'], + ]) + ->expectsOutput('Total: 2 URL(s)') + ->assertExitCode(0); + } + + #[Test] + public function list_command_shows_message_when_nothing_tracked() + { + $this->artisan('cache-tracker:list') + ->expectsOutput('No tracked URLs found.') + ->assertExitCode(0); + } + + #[Test] + public function list_command_filters_by_url_prefix() + { + Tracker::add('/blog/post-1', ['entries:1']); + Tracker::add('/blog/post-2', ['entries:2']); + Tracker::add('/about', ['entries:3']); + + $this->artisan('cache-tracker:list', ['--url' => '/blog/*']) + ->expectsTable(['URL', 'Tags'], [ + ['/blog/post-1', 'entries:1'], + ['/blog/post-2', 'entries:2'], + ]) + ->expectsOutput('Total: 2 URL(s)') + ->assertExitCode(0); + } + + #[Test] + public function list_command_filter_returns_no_results_message() + { + Tracker::add('/page1', ['products:1']); + + $this->artisan('cache-tracker:list', ['--url' => '/blog/*']) + ->expectsOutput('No tracked URLs found.') + ->assertExitCode(0); + } +}