[!!!][TASK] Remove deprecated $GLOBALS['TYPO3_GLOBALS_EXT']
[Packages/TYPO3.CMS.git] / typo3 / sysext / lowlevel / Classes / Controller / ConfigurationController.php
1 <?php
2 declare(strict_types = 1);
3 namespace TYPO3\CMS\Lowlevel\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\Backend\Configuration\SiteTcaConfiguration;
21 use TYPO3\CMS\Backend\Routing\Router;
22 use TYPO3\CMS\Backend\Template\ModuleTemplate;
23 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
24 use TYPO3\CMS\Core\Cache\CacheManager;
25 use TYPO3\CMS\Core\Http\HtmlResponse;
26 use TYPO3\CMS\Core\Http\MiddlewareStackResolver;
27 use TYPO3\CMS\Core\Localization\LanguageService;
28 use TYPO3\CMS\Core\Package\PackageManager;
29 use TYPO3\CMS\Core\Service\DependencyOrderingService;
30 use TYPO3\CMS\Core\Utility\ArrayUtility;
31 use TYPO3\CMS\Core\Utility\GeneralUtility;
32 use TYPO3\CMS\Fluid\View\StandaloneView;
33 use TYPO3\CMS\Lowlevel\Utility\ArrayBrowser;
34
35 /**
36 * View configuration arrays in the backend
37 * @internal This class is a specific Backend controller implementation and is not part of the TYPO3's Core API.
38 */
39 class ConfigurationController
40 {
41 /**
42 * Available trees to render.
43 * * label is an LLL identifier
44 * * type is used to identify the data source type
45 * * globalKey (only for type=global) is the name of a global variable
46 *
47 * @var array
48 */
49 protected $treeSetup = [
50 'confVars' => [
51 'label' => 'typo3ConfVars',
52 'type' => 'global',
53 'globalKey' => 'TYPO3_CONF_VARS',
54 ],
55 'tca' => [
56 'label' => 'tca',
57 'type' => 'global',
58 'globalKey' => 'TCA',
59 ],
60 'tcaDescr' => [
61 'label' => 'tcaDescr',
62 'type' => 'global',
63 'globalKey' => 'TCA_DESCR',
64 ],
65 'services' => [
66 'label' => 't3services',
67 'key' => 'services',
68 'type' => 'global',
69 'globalKey' => 'T3_SERVICES',
70 ],
71 'tbeModules' => [
72 'label' => 'tbemodules',
73 'type' => 'global',
74 'globalKey' => 'TBE_MODULES',
75 ],
76 'tbeModulesExt' => [
77 'label' => 'tbemodulesext',
78 'type' => 'global',
79 'globalKey' => 'TBE_MODULES_EXT',
80 ],
81 'tbeStyles' => [
82 'label' => 'tbeStyles',
83 'type' => 'global',
84 'globalKey' => 'TBE_STYLES',
85 ],
86 'userSettings' => [
87 'label' => 'usersettings',
88 'type' => 'global',
89 'globalKey' => 'TYPO3_USER_SETTINGS',
90 ],
91 'pagesTypes' => [
92 'label' => 'pagesTypes',
93 'type' => 'global',
94 'globalKey' => 'PAGES_TYPES',
95 ],
96 'beUserUc' => [
97 'label' => 'beUser',
98 'type' => 'uc',
99 ],
100 'beUserTsConfig' => [
101 'label' => 'beUserTsConfig',
102 'type' => 'beUserTsConfig',
103 ],
104 'beRoutes' => [
105 'label' => 'routes',
106 'type' => 'routes',
107 ],
108 'httpMiddlewareStacks' => [
109 'label' => 'httpMiddlewareStacks',
110 'type' => 'httpMiddlewareStacks',
111 ],
112 'siteConfiguration' => [
113 'label' => 'siteConfiguration',
114 'type' => 'siteConfiguration',
115 ],
116 ];
117
118 /**
119 * Blind configurations which should not be visible to mortal admins
120 *
121 * @var array
122 */
123 protected $blindedConfigurationOptions = [
124 'TYPO3_CONF_VARS' => [
125 'DB' => [
126 'database' => '******',
127 'host' => '******',
128 'password' => '******',
129 'port' => '******',
130 'socket' => '******',
131 'username' => '******',
132 'Connections' => [
133 'Default' => [
134 'dbname' => '******',
135 'host' => '******',
136 'password' => '******',
137 'port' => '******',
138 'user' => '******',
139 'unix_socket' => '******',
140 ],
141 ],
142 ],
143 'SYS' => [
144 'encryptionKey' => '******'
145 ],
146 ],
147 ];
148
149 /**
150 * Main controller action determines get/post values, takes care of
151 * stored backend user settings for this module, determines tree
152 * and renders it.
153 *
154 * @param ServerRequestInterface $request the current request
155 * @return ResponseInterface the response with the content
156 * @throws \RuntimeException
157 */
158 public function mainAction(ServerRequestInterface $request): ResponseInterface
159 {
160 $backendUser = $this->getBackendUser();
161 $languageService = $this->getLanguageService();
162
163 $queryParams = $request->getQueryParams();
164 $postValues = $request->getParsedBody();
165
166 $moduleState = $backendUser->uc['moduleData']['system_config'] ?? [];
167
168 // Determine validated tree key and tree detail setup
169 $selectedTreeKey = $this->treeSetup[$queryParams['tree']] ? $queryParams['tree']
170 : ($this->treeSetup[$moduleState['tree']] ? $moduleState['tree'] : key($this->treeSetup));
171 $selectedTreeDetails = $this->treeSetup[$selectedTreeKey];
172 $moduleState['tree'] = $selectedTreeKey;
173
174 // Search string given or regex search enabled?
175 $searchString = (string)($postValues['searchString'] ? trim($postValues['searchString']) : '');
176 $moduleState['regexSearch'] = (bool)($postValues['regexSearch'] ?? $moduleState['regexSearch'] ?? false);
177
178 // Prepare main array
179 $sortKeysByName = true;
180 if ($selectedTreeDetails['type'] === 'global') {
181 $globalArrayKey = $selectedTreeDetails['globalKey'];
182 $renderArray = $GLOBALS[$globalArrayKey];
183
184 // Hook for Processing blindedConfigurationOptions
185 $blindedConfigurationOptions = $this->blindedConfigurationOptions;
186
187 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][self::class]['modifyBlindedConfigurationOptions'] ?? [] as $classReference) {
188 $processingObject = GeneralUtility::makeInstance($classReference);
189 $blindedConfigurationOptions = $processingObject->modifyBlindedConfigurationOptions($blindedConfigurationOptions, $this);
190 }
191
192 if (isset($blindedConfigurationOptions[$globalArrayKey])) {
193 // Prepare blinding for all database connection types
194 foreach (array_keys($GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']) as $connectionName) {
195 if ($connectionName !== 'Default') {
196 $blindedConfigurationOptions['TYPO3_CONF_VARS']['DB']['Connections'][$connectionName] =
197 $blindedConfigurationOptions['TYPO3_CONF_VARS']['DB']['Connections']['Default'];
198 }
199 }
200 ArrayUtility::mergeRecursiveWithOverrule(
201 $renderArray,
202 ArrayUtility::intersectRecursive($blindedConfigurationOptions[$globalArrayKey], $renderArray)
203 );
204 }
205 } elseif ($selectedTreeDetails['type'] === 'beUserTsConfig') {
206 $renderArray = $backendUser->getTSConfig();
207 } elseif ($selectedTreeDetails['type'] === 'uc') {
208 $renderArray = $backendUser->uc;
209 } elseif ($selectedTreeDetails['type'] === 'routes') {
210 $router = GeneralUtility::makeInstance(Router::class);
211 $routes = $router->getRoutes();
212 $renderArray = [];
213 foreach ($routes as $identifier => $route) {
214 /** @var \TYPO3\CMS\Backend\Routing\Route $route */
215 $renderArray[$identifier] = [
216 'path' => $route->getPath(),
217 'options' => $route->getOptions()
218 ];
219 }
220 } elseif ($selectedTreeDetails['type'] === 'httpMiddlewareStacks') {
221 // Keep the order of the keys
222 $sortKeysByName = false;
223 $stackResolver = GeneralUtility::makeInstance(
224 MiddlewareStackResolver::class,
225 GeneralUtility::makeInstance(PackageManager::class),
226 GeneralUtility::makeInstance(DependencyOrderingService::class),
227 GeneralUtility::makeInstance(CacheManager::class)->getCache('cache_core')
228 );
229 $renderArray = [];
230 foreach (['frontend', 'backend'] as $stackName) {
231 // reversing the array allows the admin to read the stack from top to bottom
232 $renderArray[$stackName] = array_reverse($stackResolver->resolve($stackName));
233 }
234 } elseif ($selectedTreeDetails['type'] === 'siteConfiguration') {
235 $renderArray = GeneralUtility::makeInstance(SiteTcaConfiguration::class)->getTca();
236 } else {
237 throw new \RuntimeException('Unknown array type "' . $selectedTreeDetails['type'] . '"', 1507845662);
238 }
239 if ($sortKeysByName) {
240 ArrayUtility::naturalKeySortRecursive($renderArray);
241 }
242
243 // Prepare array renderer class, apply search and expand / collapse states
244 $arrayBrowser = GeneralUtility::makeInstance(ArrayBrowser::class);
245 $arrayBrowser->dontLinkVar = true;
246 $arrayBrowser->searchKeysToo = true;
247 $arrayBrowser->regexMode = $moduleState['regexSearch'];
248 $node = $queryParams['node'];
249 if ($searchString) {
250 $arrayBrowser->depthKeys = $arrayBrowser->getSearchKeys($renderArray, '', $searchString, []);
251 } elseif (is_array($node)) {
252 $newExpandCollapse = $arrayBrowser->depthKeys($node, $moduleState['node_' . $selectedTreeKey]);
253 $arrayBrowser->depthKeys = $newExpandCollapse;
254 $moduleState['node_' . $selectedTreeKey] = $newExpandCollapse;
255 } else {
256 $arrayBrowser->depthKeys = $moduleState['node_' . $selectedTreeKey] ?? [];
257 }
258
259 // Store new state
260 $backendUser->uc['moduleData']['system_config'] = $moduleState;
261 $backendUser->writeUC();
262
263 // Render main body
264 $view = GeneralUtility::makeInstance(StandaloneView::class);
265 $view->getRequest()->setControllerExtensionName('lowlevel');
266 $view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName(
267 'EXT:lowlevel/Resources/Private/Templates/Backend/Configuration.html'
268 ));
269 $view->assignMultiple([
270 'treeName' => $selectedTreeDetails['label'],
271 'searchString' => $searchString,
272 'regexSearch' => $moduleState['regexSearch'],
273 'tree' => $arrayBrowser->tree($renderArray, ''),
274 ]);
275
276 // Prepare module setup
277 $moduleTemplate = GeneralUtility::makeInstance(ModuleTemplate::class);
278 $moduleTemplate->setContent($view->render());
279 $moduleTemplate->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Lowlevel/ConfigurationView');
280
281 // Shortcut in doc header
282 $shortcutButton = $moduleTemplate->getDocHeaderComponent()->getButtonBar()->makeShortcutButton();
283 $shortcutButton->setModuleName('system_config')
284 ->setDisplayName($languageService->sL(
285 'LLL:EXT:lowlevel/Resources/Private/Language/locallang.xlf:' . $selectedTreeDetails['label']
286 ))
287 ->setSetVariables(['tree']);
288 $moduleTemplate->getDocHeaderComponent()->getButtonBar()->addButton($shortcutButton);
289
290 // Main drop down in doc header
291 $menu = $moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->makeMenu();
292 $menu->setIdentifier('tree');
293 foreach ($this->treeSetup as $treeKey => $treeDetails) {
294 $menuItem = $menu->makeMenuItem();
295 /** @var \TYPO3\CMS\Backend\Routing\UriBuilder $uriBuilder */
296 $uriBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Routing\UriBuilder::class);
297 $menuItem->setHref((string)$uriBuilder->buildUriFromRoute('system_config', ['tree' => $treeKey]))
298 ->setTitle($languageService->sL(
299 'LLL:EXT:lowlevel/Resources/Private/Language/locallang.xlf:' . $treeDetails['label']
300 ));
301 if ($selectedTreeKey === $treeKey) {
302 $menuItem->setActive(true);
303 }
304 $menu->addMenuItem($menuItem);
305 }
306 $moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->addMenu($menu);
307
308 return new HtmlResponse($moduleTemplate->renderContent());
309 }
310
311 /**
312 * Returns the Backend User
313 * @return BackendUserAuthentication
314 */
315 protected function getBackendUser()
316 {
317 return $GLOBALS['BE_USER'];
318 }
319
320 /**
321 * @return LanguageService
322 */
323 protected function getLanguageService()
324 {
325 return $GLOBALS['LANG'];
326 }
327 }