318115b502b604017cb08f1d825a4b3da6afcddf
[Packages/TYPO3.CMS.git] / typo3 / sysext / install / Classes / Controller / LayoutController.php
1 <?php
2 declare(strict_types = 1);
3 namespace TYPO3\CMS\Install\Controller;
4
5 /*
6 * This file is part of the TYPO3 CMS project.
7 *
8 * It is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, either version 2
10 * of the License, or any later version.
11 *
12 * For the full copyright and license information, please read the
13 * LICENSE.txt file that was distributed with this source code.
14 *
15 * The TYPO3 project - inspiring people to share!
16 */
17
18 use Psr\Http\Message\ResponseInterface;
19 use Psr\Http\Message\ServerRequestInterface;
20 use TYPO3\CMS\Core\Configuration\ConfigurationManager;
21 use TYPO3\CMS\Core\Configuration\ExtensionConfiguration;
22 use TYPO3\CMS\Core\Http\HtmlResponse;
23 use TYPO3\CMS\Core\Http\JsonResponse;
24 use TYPO3\CMS\Core\Utility\Exception\MissingArrayPathException;
25 use TYPO3\CMS\Install\Service\Exception\ConfigurationChangedException;
26 use TYPO3\CMS\Install\Service\SilentConfigurationUpgradeService;
27
28 /**
29 * Layout controller
30 *
31 * Renders a first "load the Javascript in <head>" view, and the
32 * main layout of the install tool in second action.
33 * @internal This class is a specific controller implementation and is not considered part of the Public TYPO3 API.
34 */
35 class LayoutController extends AbstractController
36 {
37 /**
38 * The init action renders an HTML response with HTML view having <head> section
39 * containing resources to main .js routing.
40 *
41 * @param ServerRequestInterface $request
42 * @return ResponseInterface
43 */
44 public function initAction(ServerRequestInterface $request): ResponseInterface
45 {
46 $view = $this->initializeStandaloneView($request, 'Layout/Init.html');
47 $view->assignMultiple([
48 // time is used as cache bust for js and css resources
49 'time' => time(),
50 'siteName' => $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'],
51 ]);
52 return new HtmlResponse(
53 $view->render(),
54 200,
55 [
56 'Cache-Control' => 'no-cache, must-revalidate',
57 'Pragma' => 'no-cache'
58 ]
59 );
60 }
61
62 /**
63 * Return a json response with the main HTML layout body: Toolbar, main menu and
64 * doc header in standalone, doc header only in backend context. Silent updaters
65 * are executed before this main view is loaded.
66 *
67 * @param ServerRequestInterface $request
68 * @return ResponseInterface
69 */
70 public function mainLayoutAction(ServerRequestInterface $request): ResponseInterface
71 {
72 $view = $this->initializeStandaloneView($request, 'Layout/MainLayout.html');
73 return new JsonResponse([
74 'success' => true,
75 'html' => $view->render(),
76 ]);
77 }
78
79 /**
80 * Execute silent configuration update. May be called multiple times until success = true is returned.
81 *
82 * @return ResponseInterface success = true if no change has been done
83 */
84 public function executeSilentConfigurationUpdateAction(): ResponseInterface
85 {
86 $silentUpdate = new SilentConfigurationUpgradeService();
87 $success = true;
88 try {
89 $silentUpdate->execute();
90 } catch (ConfigurationChangedException $e) {
91 $success = false;
92 }
93 return new JsonResponse([
94 'success' => $success,
95 ]);
96 }
97
98 /**
99 * Legacy ajax call. This silent updater takes care that all extensions configured in LocalConfiguration
100 * EXT/extConf serialized array are "upmerged" to arrays within EXTENSIONS if this extension does not
101 * exist in EXTENSIONS yet.
102 *
103 * @return ResponseInterface
104 * @deprecated since TYPO3 v9, will be removed with TYPO3 v10.0
105 */
106 public function executeSilentLegacyExtConfExtensionConfigurationUpdateAction(): ResponseInterface
107 {
108 $configurationManager = new ConfigurationManager();
109 try {
110 $oldExtConfSettings = $configurationManager->getConfigurationValueByPath('EXT/extConf');
111 } catch (MissingArrayPathException $e) {
112 // The old 'extConf' array may not exist anymore, set to empty array if so.
113 $oldExtConfSettings = [];
114 }
115 try {
116 $newExtensionSettings = $configurationManager->getConfigurationValueByPath('EXTENSIONS');
117 } catch (MissingArrayPathException $e) {
118 // New 'EXTENSIONS' array may not exist yet, for instance if just upgrading to v9
119 $newExtensionSettings = [];
120 }
121 foreach ($oldExtConfSettings as $extensionName => $extensionSettings) {
122 if (!array_key_exists($extensionName, $newExtensionSettings)) {
123 $newExtensionSettings = $this->removeDotsFromArrayKeysRecursive(unserialize($extensionSettings, ['allowed_classes' => false]));
124 $configurationManager->setLocalConfigurationValueByPath('EXTENSIONS/' . $extensionName, $newExtensionSettings);
125 }
126 }
127 return new JsonResponse([
128 'success' => true,
129 ]);
130 }
131
132 /**
133 * Synchronize TYPO3_CONF_VARS['EXTENSIONS'] with possibly new defaults from extensions
134 * ext_conf_template.txt files. This make LocalConfiguration the only source of truth for
135 * extension configuration and it is always up to date, also if an extension has been
136 * updated.
137 *
138 * @return ResponseInterface
139 */
140 public function executeSilentExtensionConfigurationSynchronizationAction(): ResponseInterface
141 {
142 $extensionConfiguration = new ExtensionConfiguration();
143 $extensionConfiguration->synchronizeExtConfTemplateWithLocalConfigurationOfAllExtensions();
144 return new JsonResponse([
145 'success' => true,
146 ]);
147 }
148
149 /**
150 * Helper method for executeSilentLegacyExtConfExtensionConfigurationUpdateAction(). Old EXT/extConf
151 * settings have dots at the end of array keys if nested arrays were used. The new configuration does
152 * not use this funny nested representation anymore. The method removes all dots at the end of given
153 * array keys recursive to do this transition.
154 *
155 * @param array $settings
156 * @return array New settings
157 * @deprecated since TYPO3 v9, will be removed with TYPO3 v10.0 along with executeSilentLegacyExtConfExtensionConfigurationUpdateAction()
158 */
159 private function removeDotsFromArrayKeysRecursive(array $settings): array
160 {
161 $settingsWithoutDots = [];
162 foreach ($settings as $key => $value) {
163 if (is_array($value)) {
164 $settingsWithoutDots[rtrim($key, '.')] = $this->removeDotsFromArrayKeysRecursive($value);
165 } else {
166 $settingsWithoutDots[$key] = $value;
167 }
168 }
169 return $settingsWithoutDots;
170 }
171 }