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