From 9c57737ba732709169ae4e2d505f8f981434106a Mon Sep 17 00:00:00 2001 From: Markus Hofmann Date: Wed, 24 Jun 2026 14:18:44 +0200 Subject: [PATCH 1/4] [FEATURE] Add Site Settings support to SourceInterface and Events Co-authored-by: Junie --- .../Events/BeforeSiteSettingsWriteEvent.php | 55 ++++++++++++++++ .../Events/LoadInitialSiteSettingsEvent.php | 65 +++++++++++++++++++ Classes/Sources/LocalDatabase.php | 15 +++++ Classes/Sources/SourceInterface.php | 9 +++ 4 files changed, 144 insertions(+) create mode 100644 Classes/Events/BeforeSiteSettingsWriteEvent.php create mode 100644 Classes/Events/LoadInitialSiteSettingsEvent.php diff --git a/Classes/Events/BeforeSiteSettingsWriteEvent.php b/Classes/Events/BeforeSiteSettingsWriteEvent.php new file mode 100644 index 0000000..ba2e067 --- /dev/null +++ b/Classes/Events/BeforeSiteSettingsWriteEvent.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ + +namespace SUDHAUS7\Sudhaus7Wizard\Events; + +use SUDHAUS7\Sudhaus7Wizard\CreateProcess; +use SUDHAUS7\Sudhaus7Wizard\Interfaces\WizardEventInterface; +use SUDHAUS7\Sudhaus7Wizard\Traits\EventTrait; + +final class BeforeSiteSettingsWriteEvent implements WizardEventInterface +{ + use EventTrait; + + protected CreateProcess $createProcess; + + /** + * @var array + */ + protected array $settings; + + /** + * @param array $settings + */ + public function __construct(array $settings, CreateProcess $createProcess) + { + $this->createProcess = $createProcess; + $this->settings = $settings; + } + + /** + * @return array + */ + public function getSettings(): array + { + return $this->settings; + } + + /** + * @param array $settings + */ + public function setSettings(array $settings): void + { + $this->settings = $settings; + } +} diff --git a/Classes/Events/LoadInitialSiteSettingsEvent.php b/Classes/Events/LoadInitialSiteSettingsEvent.php new file mode 100644 index 0000000..008002b --- /dev/null +++ b/Classes/Events/LoadInitialSiteSettingsEvent.php @@ -0,0 +1,65 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ + +namespace SUDHAUS7\Sudhaus7Wizard\Events; + +use SUDHAUS7\Sudhaus7Wizard\CreateProcess; +use SUDHAUS7\Sudhaus7Wizard\Interfaces\WizardEventInterface; +use SUDHAUS7\Sudhaus7Wizard\Traits\EventTrait; + +final class LoadInitialSiteSettingsEvent implements WizardEventInterface +{ + use EventTrait; + + protected CreateProcess $createProcess; + + protected mixed $pageId; + /** + * @var array + */ + protected array $settings; + + /** + * @param array $settings + */ + public function __construct(mixed $pageId, array $settings, CreateProcess $createProcess) + { + $this->pageId = $pageId; + $this->createProcess = $createProcess; + $this->settings = $settings; + } + + /** + * @return mixed + */ + public function getPageId(): mixed + { + return $this->pageId; + } + + /** + * @return array + */ + public function getSettings(): array + { + return $this->settings; + } + + /** + * @param array $settings + */ + public function setSettings(array $settings): void + { + $this->settings = $settings; + } +} diff --git a/Classes/Sources/LocalDatabase.php b/Classes/Sources/LocalDatabase.php index 7384330..3506ca0 100644 --- a/Classes/Sources/LocalDatabase.php +++ b/Classes/Sources/LocalDatabase.php @@ -164,6 +164,21 @@ public function getSiteConfig(mixed $id): array return $this->siteconfig; } + /** + * @return array + */ + public function getSiteSettings(mixed $id): array + { + $siteFinder = GeneralUtility::makeInstance(SiteFinder::class); + try { + $site = $siteFinder->getSiteByRootPageId((int)$id); + return $site->getSettings()->getAll(); + } catch (SiteNotFoundException|\Exception $e) { + $this->logger?->debug($e->getMessage(), [$id]); + } + return []; + } + public function ping(): void { $db = $this->connectionPool->getConnectionByName('Default'); diff --git a/Classes/Sources/SourceInterface.php b/Classes/Sources/SourceInterface.php index 8f69da3..0f5ddaa 100644 --- a/Classes/Sources/SourceInterface.php +++ b/Classes/Sources/SourceInterface.php @@ -34,6 +34,15 @@ public function getCreator(): Creator; */ public function getSiteConfig(mixed $id): array; + /** + * Returns the Site Settings as an array + * + * @param mixed $id + * + * @return array + */ + public function getSiteSettings(mixed $id): array; + /** * @param array $where */ From 9aa1aca56a4460eba5824233f615bb09b9eba5e8 Mon Sep 17 00:00:00 2001 From: Markus Hofmann Date: Wed, 24 Jun 2026 14:35:26 +0200 Subject: [PATCH 2/4] [FEATURE] Implement Site Settings handling in CreateProcess and Factory Co-authored-by: Junie --- Classes/CreateProcess.php | 30 ++++++++++++++++++- .../Services/AbstractCreateProcessFactory.php | 7 +++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/Classes/CreateProcess.php b/Classes/CreateProcess.php index 3e2b426..0ba8b2e 100644 --- a/Classes/CreateProcess.php +++ b/Classes/CreateProcess.php @@ -29,6 +29,7 @@ use SUDHAUS7\Sudhaus7Wizard\Events\BeforeClonedTreeInsertEvent; use SUDHAUS7\Sudhaus7Wizard\Events\BeforeContentCloneEvent; use SUDHAUS7\Sudhaus7Wizard\Events\BeforeSiteConfigWriteEvent; +use SUDHAUS7\Sudhaus7Wizard\Events\BeforeSiteSettingsWriteEvent; use SUDHAUS7\Sudhaus7Wizard\Events\BeforeUserCreationUCDefaultsEvent; use SUDHAUS7\Sudhaus7Wizard\Events\CalcualteMountpointNameEvent; use SUDHAUS7\Sudhaus7Wizard\Events\CalculateBackendUserGroupNameEvent; @@ -90,6 +91,11 @@ final class CreateProcess implements LoggerAwareInterface */ public array $siteConfig = []; + /** + * @var array + */ + public array $siteSettings = []; + /** * @var array */ @@ -1719,6 +1725,10 @@ private function finalYaml(): void $this->eventDispatcher->dispatch($event); $this->siteConfig = $event->getSiteconfig(); + $event = new BeforeSiteSettingsWriteEvent($this->siteSettings, $this); + $this->eventDispatcher->dispatch($event); + $this->siteSettings = $event->getSettings(); + // Fallback to ensure a site folder in case of a failing preg_replace on slug generation if ($identifier === null) { $entryPoint = 'autogenerated-' . $this->getSiteRootId(); @@ -1727,7 +1737,9 @@ private function finalYaml(): void $this->calculatedSiteconfigIdentifier = $identifier; - GeneralUtility::makeInstance(SiteWriter::class)->write($identifier, $this->siteConfig); + $siteWriter = GeneralUtility::makeInstance(SiteWriter::class); + $siteWriter->write($identifier, $this->siteConfig); + $siteWriter->writeSettings($identifier, $this->siteSettings); } /** @@ -1746,6 +1758,22 @@ public function setSiteConfig(array $siteConfig): void $this->siteConfig = $siteConfig; } + /** + * @return array + */ + public function getSiteSettings(): array + { + return $this->siteSettings; + } + + /** + * @param array $siteSettings + */ + public function setSiteSettings(array $siteSettings): void + { + $this->siteSettings = $siteSettings; + } + /** * @return string[] */ diff --git a/Classes/Services/AbstractCreateProcessFactory.php b/Classes/Services/AbstractCreateProcessFactory.php index f35cbfa..6698b4f 100644 --- a/Classes/Services/AbstractCreateProcessFactory.php +++ b/Classes/Services/AbstractCreateProcessFactory.php @@ -21,6 +21,7 @@ use SUDHAUS7\Sudhaus7Wizard\CreateProcess; use SUDHAUS7\Sudhaus7Wizard\Domain\Model\Creator; use SUDHAUS7\Sudhaus7Wizard\Events\LoadInitialSiteConfigEvent; +use SUDHAUS7\Sudhaus7Wizard\Events\LoadInitialSiteSettingsEvent; use SUDHAUS7\Sudhaus7Wizard\Interfaces\WizardProcessInterface; use SUDHAUS7\Sudhaus7Wizard\Sources\LocalDatabase; use SUDHAUS7\Sudhaus7Wizard\Sources\SourceInterface; @@ -59,11 +60,17 @@ public function get(Creator $creator, ?LoggerInterface $logger = null): CreatePr } $pid = $creator->getSourcepid(); $siteconfig = $task->getSource()->getSiteConfig($pid); + $settings = $task->getSource()->getSiteSettings($pid); // wanted to do this early to have more control over where the source is loaded $event = new LoadInitialSiteConfigEvent($pid, $siteconfig, $task); GeneralUtility::makeInstance(EventDispatcher::class)->dispatch($event); $task->setSiteConfig($event->getSiteconfig()); + + $event = new LoadInitialSiteSettingsEvent($pid, $settings, $task); + GeneralUtility::makeInstance(EventDispatcher::class)->dispatch($event); + $task->setSiteSettings($event->getSettings()); + return $task; } } From 23c6aabe0e71769a1ac58f558fd32cd7c1dd336a Mon Sep 17 00:00:00 2001 From: Markus Hofmann Date: Wed, 24 Jun 2026 14:36:56 +0200 Subject: [PATCH 3/4] [TASK] Implement getSiteSettings in RestWizardServerSource Co-authored-by: Junie --- Classes/Sources/RestWizardServerSource.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Classes/Sources/RestWizardServerSource.php b/Classes/Sources/RestWizardServerSource.php index fe5a18a..6b324ef 100644 --- a/Classes/Sources/RestWizardServerSource.php +++ b/Classes/Sources/RestWizardServerSource.php @@ -125,6 +125,19 @@ public function getSiteConfig(mixed $id): array return $this->siteconfig; } + /** + * @inheritDoc + * @throws \Exception + */ + public function getSiteSettings(mixed $id): array + { + $result = $this->getAPI()->request('/sitesettings/' . $id); + if (is_array($result) && $result !== []) { + return $result; + } + return []; + } + /** * @inheritDoc */ From 9443545b551f9812cac37c3843810e36ca08a938 Mon Sep 17 00:00:00 2001 From: Markus Hofmann Date: Wed, 24 Jun 2026 14:42:54 +0200 Subject: [PATCH 4/4] [FEATURE] Add Site Settings test case and fix LocalDatabase handleFile Co-authored-by: Junie --- Classes/Sources/LocalDatabase.php | 2 +- Tests/Functional/Wizard/WizardTest.php | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/Classes/Sources/LocalDatabase.php b/Classes/Sources/LocalDatabase.php index 3506ca0..b1be977 100644 --- a/Classes/Sources/LocalDatabase.php +++ b/Classes/Sources/LocalDatabase.php @@ -284,7 +284,7 @@ public function handleFile(array $sysFile, string $newIdentifier): array 'sys_file', ['identifier' => $newIdentifier] ); - return $res->fetchAssociative() ?: []; + return $res->fetchAssociative() ?: $sysFile; } $this->logger?->notice('cp ' . Environment::getPublicPath() . '/fileadmin' . $sysFile['identifier'] . ' ' . Environment::getPublicPath() . '/fileadmin' . $newIdentifier); diff --git a/Tests/Functional/Wizard/WizardTest.php b/Tests/Functional/Wizard/WizardTest.php index 608db69..87c206f 100644 --- a/Tests/Functional/Wizard/WizardTest.php +++ b/Tests/Functional/Wizard/WizardTest.php @@ -10,6 +10,8 @@ use SBUERK\TYPO3\Testing\TestCase\FunctionalTestCase; use SUDHAUS7\Sudhaus7Wizard\Cli\RunCommand; use Symfony\Component\Console\Tester\CommandTester; +use TYPO3\CMS\Core\Configuration\Event\SiteConfigurationChangedEvent; +use TYPO3\CMS\Core\Configuration\SiteWriter; use TYPO3\CMS\Core\Localization\LanguageServiceFactory; use TYPO3\CMS\Core\Site\Entity\Site; use TYPO3\CMS\Core\Site\SiteFinder; @@ -112,4 +114,28 @@ public function wizardGeneratesNewSite(): void self::assertIsArray($site->getAttribute('dependencies')); self::assertEquals(['sudhaus7/template'], $site->getAttribute('dependencies')); } + + #[Test] + #[Group('not-postgres')] + public function wizardGeneratesNewSiteWithSettings(): void + { + /** @var SiteWriter $siteWriter */ + $siteWriter = $this->get(SiteWriter::class); + $siteWriter->writeSettings('acme', ['my_setting' => 'my_value']); + $this->get(\Psr\EventDispatcher\EventDispatcherInterface::class)->dispatch(new SiteConfigurationChangedEvent('acme')); + $this->get('cache.core')->flush(); + + $tester = new CommandTester($this->get(RunCommand::class)); + $tester->execute([ + 'mode' => 'next', + ]); + + $tester->assertCommandIsSuccessful($tester->getDisplay()); + + /** @var SiteFinder $siteFinder */ + $siteFinder = $this->get(SiteFinder::class); + $site = $siteFinder->getSiteByIdentifier('readytemplate'); + self::assertInstanceOf(Site::class, $site); + self::assertEquals('my_value', $site->getSettings()->get('my_setting')); + } }