" view, and the * main layout of the install tool in second action. * * @internal This class is a specific controller implementation and is not considered part of the Public TYPO3 API. */ class LayoutController extends AbstractController { use ControllerTrait; public function __construct( private readonly SilentConfigurationUpgradeService $silentConfigurationUpgradeService, private readonly SilentTemplateFileUpgradeService $silentTemplateFileUpgradeService, private readonly BackendEntryPointResolver $backendEntryPointResolver, private readonly ImportMapFactory $importMapFactory, private readonly HashService $hashService, private readonly IconRegistry $iconRegistry, private readonly DirectiveHashCollection $directiveHashCollection, ) {} /** * The init action renders an HTML response with HTML view having section * containing resources to main .js routing. */ public function initAction(ServerRequestInterface $request): ResponseInterface { $bust = $GLOBALS['EXEC_TIME']; if (!Environment::getContext()->isDevelopment()) { $bust = $this->hashService->hmac((new Typo3Version()) . Environment::getProjectPath(), self::class); } $sitePath = $request->getAttribute('normalizedParams')->getSitePath(); $importMap = $this->importMapFactory->create($sitePath); $initModule = $importMap->resolveImport('@typo3/install/init-install.js', true, $sitePath); $view = $this->initializeView($request); $nonce = new ConsumableNonce(); $view->assignMultiple([ // time is used as cache bust for js and css resources 'bust' => $bust, 'iconCacheIdentifier' => sha1($this->iconRegistry->getBackendIconsCacheIdentifier()), 'initModule' => $initModule, 'importmap' => $importMap->render($sitePath, $nonce), ]); return new HtmlResponse( $view->render('Layout/Init'), 200, [ 'Cache-Control' => 'no-cache, no-store', 'Content-Security-Policy' => $this->createContentSecurityPolicy()->compile(new PolicyBag(Scope::backend(), new Map(), new Behavior(), $nonce, $this->directiveHashCollection)), 'Pragma' => 'no-cache', ] ); } /** * Return a json response with the main HTML layout body: Toolbar, main menu and * doc header in standalone, doc header only in backend context. Silent updaters * are executed before this main view is loaded. */ public function mainLayoutAction(ServerRequestInterface $request): ResponseInterface { $view = $this->initializeView($request); $view->assign('moduleName', 'system_' . ($request->getQueryParams()['install']['module'] ?? 'layout')); $view->assign('backendUrl', (string)$this->backendEntryPointResolver->getUriFromRequest($request)); $view->assign('frontendUrl', $request->getAttribute('normalizedParams')->getSiteUrl()); return new JsonResponse([ 'success' => true, 'html' => $view->render('Layout/MainLayout'), ]); } /** * Execute silent configuration update. May be called multiple times until success = true is returned. * * @return ResponseInterface success = true if no change has been done */ public function executeSilentConfigurationUpdateAction(): ResponseInterface { $success = true; try { $this->silentConfigurationUpgradeService->execute(); } catch (ConfigurationChangedException) { $success = false; } catch (SettingsWriteException $e) { throw new SilentConfigurationUpgradeReadonlyException(1688462974, $e); } return new JsonResponse([ 'success' => $success, ]); } /** * Execute silent template files update. May be called multiple times until success = true is returned. * * @return ResponseInterface success = true if no change has been done */ public function executeSilentTemplateFileUpdateAction(): ResponseInterface { $success = true; try { $this->silentTemplateFileUpgradeService->execute(); } catch (TemplateFileChangedException $e) { $success = false; } return new JsonResponse([ 'success' => $success, ]); } /** * Synchronize TYPO3_CONF_VARS['EXTENSIONS'] with possibly new defaults from extensions * ext_conf_template.txt files. This make LocalConfiguration the only source of truth for * extension configuration, and it is always up-to-date, also if an extension has been * updated. */ public function executeSilentExtensionConfigurationSynchronizationAction(): ResponseInterface { $extensionConfiguration = new ExtensionConfiguration(); $extensionConfiguration->synchronizeExtConfTemplateWithLocalConfigurationOfAllExtensions(); return new JsonResponse([ 'success' => true, ]); } }