getAttribute('moduleData'); $mode = SetupSettingsViewMode::tryFrom($moduleData->get('settingsMode') ?? '') ?? SetupSettingsViewMode::BASIC; $moduleData->set('settingsMode', $mode->value); $identifier = $request->getQueryParams()['site'] ?? null; if ($identifier === null) { throw new \RuntimeException('Site identifier to edit must be set', 1713394528); } $returnUrl = GeneralUtility::sanitizeLocalUrl( (string)($request->getQueryParams()['returnUrl'] ?? ''), $request ) ?: null; $overviewUrl = (string)$this->uriBuilder->buildUriFromRoute('site_configuration'); $site = $this->siteFinder->getSiteByIdentifier($identifier); $view = $this->moduleTemplateFactory->create($request); $settings = $this->siteSettingsService->getUncachedSettings($site); $setSettings = $this->siteSettingsService->getSetSettings($site); $categoryEnhancer = function (Category $category) use (&$categoryEnhancer, $settings, $setSettings): Category { return new Category(...[ ...get_object_vars($category), 'label' => $this->getLanguageService()->sL($category->label), 'description' => $category->description !== null ? $this->getLanguageService()->sL($category->description) : $category->description, 'categories' => array_map($categoryEnhancer, $category->categories), 'settings' => array_map( fn(SettingDefinition $definition): EditableSetting => new EditableSetting( definition: $this->resolveSettingLabels($definition), value: $settings->get($definition->key), systemDefault: $setSettings->get($definition->key), typeImplementation: $this->settingsTypeRegistry->get($definition->type)->getJavaScriptModule(), ), $category->settings ), ]); }; $categories = array_map( $categoryEnhancer, $this->categoryRegistry->getCategories(...$site->getSets()) ); $hasSettings = count($categories) > 0; $this->addDocHeaderBreadcrumb($view, $site); $this->addDocHeaderCloseAndSaveButtons($view, $returnUrl ?? $overviewUrl, $hasSettings); $this->addDocHeaderViewModeButton($view, $site, $mode); $this->addDocHeaderSiteConfigurationButton($view, $site); if ($hasSettings) { $this->addDocHeaderExportButton($view, $mode); } // Set shortcut context - reload button is added automatically $view->getDocHeaderComponent()->setShortcutContext( 'site_configuration.editSettings', sprintf($this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_sitesettings.xlf:labels.edit'), $site->getIdentifier()), ['site' => $site->getIdentifier()] ); $view->setLayout(ModuleLayout::NORMAL); $view->assign('site', $site); $view->assign('siteTitle', $this->getSiteTitle($site)); $view->assign('rootPageId', $site->getRootPageId()); $view->assign('actionUrl', (string)$this->uriBuilder->buildUriFromRoute('site_configuration.saveSettings', array_filter([ 'site' => $site->getIdentifier(), 'returnUrl' => $returnUrl, ]))); $view->assign('returnUrl', $returnUrl); $view->assign('dumpUrl', (string)$this->uriBuilder->buildUriFromRoute('site_configuration.dumpSettings', ['site' => $site->getIdentifier()])); $view->assign('categories', $categories); $view->assign('mode', $mode); $formProtection = $this->formProtectionFactory->createFromRequest($request); $view->assign('formToken', $formProtection->generateToken('site_configuration', 'saveSettings')); return $view->renderResponse('SiteSettings/Edit'); } private function resolveSettingLabels(SettingDefinition $definition): SettingDefinition { $languageService = $this->getLanguageService(); return new SettingDefinition(...[ ...get_object_vars($definition), 'label' => $languageService->sL($definition->label), 'description' => $definition->description !== null ? $languageService->sL($definition->description) : null, 'enum' => array_map( static fn(string|int|float|bool $label): string => $languageService->sL((string)$label), $definition->enum ), ]); } public function saveAction(ServerRequestInterface $request): ResponseInterface { $identifier = $request->getQueryParams()['site'] ?? null; if ($identifier === null) { throw new \RuntimeException('Site identifier to edit must be set', 1713394529); } $site = $this->siteFinder->getSiteByIdentifier($identifier); $parsedBody = $request->getParsedBody(); $formProtection = $this->formProtectionFactory->createFromRequest($request); if (!$formProtection->validateToken((string)($parsedBody['formToken'] ?? ''), 'site_configuration', 'saveSettings')) { return $this->responseFactory ->createResponse(400, 'Invalid request token given') ->withHeader('Location', (string)$this->uriBuilder->buildUriFromRoute('site_configuration.editSettings', [ 'site' => $site->getIdentifier(), ])); } $returnUrl = GeneralUtility::sanitizeLocalUrl( (string)($parsedBody['returnUrl'] ?? ''), $request ) ?: null; $overviewUrl = $this->uriBuilder->buildUriFromRoute('site_configuration'); $CMD = $parsedBody['CMD'] ?? ''; $isSave = $CMD === 'save' || $CMD === 'saveclose'; $isSaveClose = $parsedBody['CMD'] === 'saveclose'; if (!$isSave) { return new RedirectResponse($returnUrl ?? $overviewUrl); } $newSettings = $this->siteSettingsService->createSettingsFromFormData($site, $parsedBody['settings'] ?? []); $settingsDiff = $this->siteSettingsService->computeSettingsDiff($site, $newSettings); $this->siteSettingsService->writeSettings($site, $settingsDiff->asArray()); if ($settingsDiff->changes !== [] || $settingsDiff->deletions !== []) { $this->getBackendUser()->writelog( Type::SITE, SettingAction::CHANGE, SystemLogErrorClassification::MESSAGE, null, 'Site settings changed for \'%s\': %s', [$site->getIdentifier(), json_encode($settingsDiff)], 'site' ); $languageService = $this->getLanguageService(); $message = $languageService->sL('LLL:EXT:backend/Resources/Private/Language/locallang_sitesettings.xlf:save.message.updated'); $flashMessage = new FlashMessage($message, '', ContextualFeedbackSeverity::OK, true); $defaultFlashMessageQueue = $this->flashMessageService->getMessageQueueByIdentifier(); $defaultFlashMessageQueue->enqueue($flashMessage); } if ($isSaveClose) { return new RedirectResponse($returnUrl ?? $overviewUrl); } $editRoute = $this->uriBuilder->buildUriFromRoute('site_configuration.editSettings', array_filter([ 'site' => $site->getIdentifier(), 'returnUrl' => $returnUrl, ], static fn(?string $v): bool => $v !== null)); return new RedirectResponse($editRoute); } public function dumpAction(ServerRequestInterface $request): ResponseInterface { $identifier = $request->getQueryParams()['site'] ?? null; if ($identifier === null) { throw new \RuntimeException('Site identifier to edit must be set', 1724772561); } $site = $this->siteFinder->getSiteByIdentifier($identifier); $parsedBody = $request->getParsedBody(); $specificSetting = (string)($parsedBody['specificSetting'] ?? ''); $minify = $specificSetting !== '' ? false : true; $newSettings = $this->siteSettingsService->createSettingsFromFormData($site, $parsedBody['settings'] ?? []); $settingsDiff = $this->siteSettingsService->computeSettingsDiff($site, $newSettings, $minify); $settings = $settingsDiff->asArray(); if ($specificSetting !== '' && isset($settings[$specificSetting])) { $settings = [ $specificSetting => $settings[$specificSetting], ]; } $yamlContents = Yaml::dump($settings, 99, 2, Yaml::DUMP_EMPTY_ARRAY_AS_SEQUENCE | Yaml::DUMP_OBJECT_AS_MAP); return new JsonResponse([ 'yaml' => $yamlContents, ]); } protected function addDocHeaderBreadcrumb(ModuleTemplate $moduleTemplate, Site $site): void { $record = BackendUtility::getRecord('pages', $site->getRootPageId()); $moduleTemplate->getDocHeaderComponent()->setPageBreadcrumb($record ?? []); } protected function addDocHeaderCloseAndSaveButtons(ModuleTemplate $moduleTemplate, string $closeUrl, bool $saveEnabled): void { $moduleTemplate->addButtonToButtonBar($this->componentFactory->createCloseButton($closeUrl)); $saveButton = $this->componentFactory->createSaveButton('sitesettings_form') ->setName('CMD') ->setValue('save') ->setDisabled(!$saveEnabled); $moduleTemplate->addButtonToButtonBar($saveButton, ButtonBar::BUTTON_POSITION_LEFT, 2); } protected function addDocHeaderViewModeButton(ModuleTemplate $moduleTemplate, Site $site, SetupSettingsViewMode $mode): void { $languageService = $this->getLanguageService(); $viewModeButton = $this->componentFactory->createDropDownButton() ->setLabel($languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.view')) ->setShowLabelText(true); $viewModeButton->addItem( $this->componentFactory->createDropDownRadio() ->setActive(($mode === SetupSettingsViewMode::BASIC)) ->setHref( (string)$this->uriBuilder->buildUriFromRoute( 'site_configuration.editSettings', array_filter([ 'site' => $site->getIdentifier(), 'settingsMode' => SetupSettingsViewMode::BASIC->value, ]) ) ) ->setLabel($languageService->sL('LLL:EXT:backend/Resources/Private/Language/locallang_settingseditor.xlf:settingseditor.mode.basic')) ->setIcon($this->iconFactory->getIcon('actions-window', IconSize::SMALL)) ); $viewModeButton->addItem( $this->componentFactory->createDropDownRadio() ->setActive(($mode === SetupSettingsViewMode::ADVANCED)) ->setHref( (string)$this->uriBuilder->buildUriFromRoute( 'site_configuration.editSettings', array_filter([ 'site' => $site->getIdentifier(), 'settingsMode' => SetupSettingsViewMode::ADVANCED->value, ]) ) ) ->setLabel($languageService->sL('LLL:EXT:backend/Resources/Private/Language/locallang_settingseditor.xlf:settingseditor.mode.advanced')) ->setIcon($this->iconFactory->getIcon('actions-window-cog', IconSize::SMALL)) ); $moduleTemplate->addButtonToButtonBar($viewModeButton, ButtonBar::BUTTON_POSITION_RIGHT, 2); } protected function addDocHeaderExportButton(ModuleTemplate $moduleTemplate, SetupSettingsViewMode $mode): void { if ($mode === SetupSettingsViewMode::ADVANCED) { $languageService = $this->getLanguageService(); $exportButton = $this->componentFactory->createInputButton() ->setTitle($languageService->sL('LLL:EXT:backend/Resources/Private/Language/locallang_sitesettings.xlf:edit.yamlExport')) ->setIcon($this->iconFactory->getIcon('actions-database-export', IconSize::SMALL)) ->setShowLabelText(true) ->setName('CMD') ->setValue('export') ->setForm('sitesettings_form'); $moduleTemplate->addButtonToButtonBar($exportButton, ButtonBar::BUTTON_POSITION_RIGHT); } } protected function addDocHeaderSiteConfigurationButton(ModuleTemplate $moduleTemplate, Site $site): void { $languageService = $this->getLanguageService(); $exportButton = $this->componentFactory->createLinkButton() ->setTitle($languageService->sL('LLL:EXT:backend/Resources/Private/Language/locallang_sitesettings.xlf:edit.editSiteConfiguration')) ->setIcon($this->iconFactory->getIcon('actions-open', IconSize::SMALL)) ->setShowLabelText(true) ->setHref((string)$this->uriBuilder->buildUriFromRoute('site_configuration.edit', [ 'site' => $site->getIdentifier(), 'returnUrl' => $this->uriBuilder->buildUriFromRoute('site_configuration.editSettings', [ 'site' => $site->getIdentifier(), ]), ])); $moduleTemplate->addButtonToButtonBar($exportButton, ButtonBar::BUTTON_POSITION_LEFT, 3); } protected function getSiteTitle(Site $site): string { $websiteTitle = $site->getConfiguration()['websiteTitle'] ?? ''; if ($websiteTitle !== '') { return $websiteTitle; } $rootPage = BackendUtility::getRecord('pages', $site->getRootPageId()); $title = $rootPage['title'] ?? ''; if ($title !== '') { return $title; } return '(unknown)'; } protected function getLanguageService(): LanguageService { return $GLOBALS['LANG']; } protected function getBackendUser(): BackendUserAuthentication { return $GLOBALS['BE_USER']; } }