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