diff --git a/src/Events/SiteCreated.php b/src/Events/SiteCreated.php new file mode 100644 index 00000000000..19e76434dba --- /dev/null +++ b/src/Events/SiteCreated.php @@ -0,0 +1,13 @@ +getSavedSites(); - $this->sites = collect($sites)->map(fn ($site, $handle) => new Site($handle, $site)); + $this->sites = $this->hydrateConfig($sites); return $this; } @@ -138,7 +142,19 @@ protected function getSavedSites() public function save() { + // Track for `SiteCreated` and `SiteDeleted` events, before saving to file + $newSites = $this->getNewSites(); + $deletedSites = $this->getDeletedSites(); + + // Save to file File::put($this->path(), YAML::dump($this->config())); + + // Dispatch our tracked `SiteCreated` and `SiteDeleted` events + $newSites->each(fn ($site) => SiteCreated::dispatch($site)); + $deletedSites->each(fn ($site) => SiteDeleted::dispatch($site)); + + // Dispatch `SiteSaved` events + $this->sites->each(fn ($site) => SiteSaved::dispatch($site)); } public function blueprint() @@ -242,6 +258,31 @@ public function config(): array ->all(); } + protected function hydrateConfig($config): Collection + { + return collect($config)->map(fn ($site, $handle) => new Site($handle, $site)); + } + + protected function getNewSites(): Collection + { + $currentSites = $this->getSavedSites(); + $newSites = $this->config(); + + return $this->hydrateConfig( + collect($newSites)->diffKeys($currentSites) + ); + } + + protected function getDeletedSites(): Collection + { + $currentSites = $this->getSavedSites(); + $newSites = $this->config(); + + return $this->hydrateConfig( + collect($currentSites)->diffKeys($newSites) + ); + } + /** * Deprecated! This is being replaced by `setSites()` and `setSiteValue()`. * diff --git a/tests/Sites/SitesConfigTest.php b/tests/Sites/SitesConfigTest.php index 145823ca511..dfa0d4ac134 100644 --- a/tests/Sites/SitesConfigTest.php +++ b/tests/Sites/SitesConfigTest.php @@ -2,8 +2,12 @@ namespace Tests\Sites; +use Illuminate\Support\Facades\Event; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\Test; +use Statamic\Events\SiteCreated; +use Statamic\Events\SiteDeleted; +use Statamic\Events\SiteSaved; use Statamic\Facades\Config; use Statamic\Facades\File; use Statamic\Facades\Site; @@ -436,4 +440,75 @@ public function it_validates_at_least_one_site_is_required_for_multiple_sites_th 'sites' => ['This field is required.'], ]]); } + + #[Test] + public function it_dispatches_site_saved_events() + { + Event::fake(); + + Site::save(); + + Event::assertDispatched(SiteSaved::class, 2); + + Event::assertDispatched(function (SiteSaved $event) { + return $event->site->handle() === 'english'; + }); + + Event::assertDispatched(function (SiteSaved $event) { + return $event->site->handle() === 'french'; + }); + } + + #[Test] + public function it_dispatches_site_created_events() + { + Event::fake(); + + Site::setSites( + collect(Site::config()) + ->put('german', ['name' => 'German', 'url' => '/de/']) + ->put('polish', ['name' => 'Polish', 'url' => '/pl/']) + ->all() + )->save(); + + Event::assertDispatched(SiteCreated::class, 2); + + Event::assertDispatched(function (SiteCreated $event) { + return $event->site->handle() === 'german'; + }); + + Event::assertDispatched(function (SiteCreated $event) { + return $event->site->handle() === 'polish'; + }); + + // We're saving a total of 4 sites to yaml after the above changes, so we should see 4 `SiteSaved` events as well + Event::assertDispatched(SiteSaved::class, 4); + } + + #[Test] + public function it_dispatches_site_deleted_events() + { + Event::fake(); + + Site::setSites( + collect(Site::config()) + ->put('german', ['name' => 'German', 'url' => '/de/']) + ->forget('english') + ->forget('french') + ->all() + )->save(); + + Event::assertDispatched(SiteDeleted::class, 2); + + Event::assertDispatched(function (SiteDeleted $event) { + return $event->site->handle() === 'english'; + }); + + Event::assertDispatched(function (SiteDeleted $event) { + return $event->site->handle() === 'french'; + }); + + // We're saving a total of 1 site to yaml after the above changes, so we should see 1 `SiteSaved` event as well + Event::assertDispatched(SiteSaved::class, 1); + } }