‪TYPO3CMS  ‪main
MaintenanceController.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
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 
19 
20 use Psr\Http\Message\ResponseInterface;
21 use Psr\Http\Message\ServerRequestInterface;
23 use TYPO3\CMS\Core\Configuration\ConfigurationManager;
48 
54 {
56 
57  public function ‪__construct(
58  private readonly ‪LateBootService $lateBootService,
59  private readonly ‪ClearCacheService $clearCacheService,
60  private readonly ‪ClearTableService $clearTableService,
61  private readonly ConfigurationManager $configurationManager,
62  private readonly ‪PasswordHashFactory $passwordHashFactory,
63  private readonly ‪Locales $locales,
64  private readonly ‪LanguageServiceFactory $languageServiceFactory,
65  private readonly ‪FormProtectionFactory $formProtectionFactory,
66  private readonly ‪SchemaMigrator $schemaMigrator,
67  ) {
68  ‪$GLOBALS['LANG'] = $this->languageServiceFactory->create('en');
69  $passwordPolicy = ‪$GLOBALS['TYPO3_CONF_VARS']['BE']['passwordPolicy'] ?? 'default';
70  $this->passwordPolicyValidator = GeneralUtility::makeInstance(
71  PasswordPolicyValidator::class,
73  is_string($passwordPolicy) ? $passwordPolicy : ''
74  );
75  }
76 
80  public function ‪cardsAction(ServerRequestInterface $request): ResponseInterface
81  {
82  $view = $this->‪initializeView($request);
83  return new ‪JsonResponse([
84  'success' => true,
85  'html' => $view->render('Maintenance/Cards'),
86  ]);
87  }
88 
92  public function ‪cacheClearAllAction(): ResponseInterface
93  {
94  $this->clearCacheService->clearAll();
95  GeneralUtility::makeInstance(OpcodeCacheService::class)->clearAllActive();
96  $messageQueue = new ‪FlashMessageQueue('install');
97  $messageQueue->enqueue(
98  new ‪FlashMessage('Successfully cleared all caches and all available opcode caches.', 'Caches cleared')
99  );
100  return new ‪JsonResponse([
101  'success' => true,
102  'status' => $messageQueue,
103  ]);
104  }
105 
109  public function ‪clearTypo3tempFilesStatsAction(ServerRequestInterface $request): ResponseInterface
110  {
111  $container = $this->lateBootService->loadExtLocalconfDatabaseAndExtTables(false);
112  $typo3tempFileService = $container->get(Typo3tempFileService::class);
113 
114  $view = $this->‪initializeView($request);
115  $formProtection = $this->formProtectionFactory->createFromRequest($request);
116  $view->assignMultiple([
117  'clearTypo3tempFilesToken' => $formProtection->generateToken('installTool', 'clearTypo3tempFiles'),
118  ]);
119  return new ‪JsonResponse(
120  [
121  'success' => true,
122  'stats' => $typo3tempFileService->getDirectoryStatistics(),
123  'html' => $view->render('Maintenance/ClearTypo3tempFiles'),
124  'buttons' => [
125  [
126  'btnClass' => 'btn-default t3js-clearTypo3temp-stats',
127  'text' => 'Scan again',
128  ],
129  ],
130  ]
131  );
132  }
133 
137  public function ‪clearTypo3tempFilesAction(ServerRequestInterface $request): ResponseInterface
138  {
139  $container = $this->lateBootService->loadExtLocalconfDatabaseAndExtTables(false);
140  $typo3tempFileService = $container->get(Typo3tempFileService::class);
141  $messageQueue = new ‪FlashMessageQueue('install');
142  $folder = $request->getParsedBody()['install']['folder'];
143  // storageUid is an optional post param if FAL storages should be cleaned
144  $storageUid = $request->getParsedBody()['install']['storageUid'] ?? null;
145  if ($storageUid === null) {
146  $typo3tempFileService->clearAssetsFolder($folder);
147  $messageQueue->enqueue(new ‪FlashMessage('The directory "' . $folder . '" has been cleared successfully', 'Directory cleared'));
148  } else {
149  $storageUid = (int)$storageUid;
150  // We have to get the stats before deleting files, otherwise we're not able to retrieve the amount of files anymore
151  $stats = $typo3tempFileService->getStatsFromStorageByUid($storageUid);
152  $failedDeletions = $typo3tempFileService->clearProcessedFiles($storageUid);
153  if ($failedDeletions) {
154  $messageQueue->enqueue(new ‪FlashMessage(
155  'Failed to delete ' . $failedDeletions . ' processed files. See TYPO3 log (by default typo3temp/var/log/typo3_*.log)',
156  'Failed to delete files',
157  ContextualFeedbackSeverity::ERROR
158  ));
159  } else {
160  $messageQueue->enqueue(new ‪FlashMessage(
161  sprintf('Removed %d files from directory "%s"', $stats['numberOfFiles'], $stats['directory']),
162  'Deleted processed files'
163  ));
164  }
165  }
166  return new ‪JsonResponse([
167  'success' => true,
168  'status' => $messageQueue,
169  ]);
170  }
171 
175  public function ‪dumpAutoloadAction(): ResponseInterface
176  {
177  $messageQueue = new ‪FlashMessageQueue('install');
179  $messageQueue->enqueue(new ‪FlashMessage(
180  'Skipped generating additional class loading information in Composer mode.',
181  'Autoloader not dumped',
182  ContextualFeedbackSeverity::NOTICE
183  ));
184  } else {
186  $messageQueue->enqueue(new ‪FlashMessage(
187  'Successfully dumped class loading information for extensions.',
188  'Dumped autoloader'
189  ));
190  }
191  return new ‪JsonResponse([
192  'success' => true,
193  'status' => $messageQueue,
194  ]);
195  }
196 
200  public function ‪databaseAnalyzerAction(ServerRequestInterface $request): ResponseInterface
201  {
202  $view = $this->‪initializeView($request);
203  $formProtection = $this->formProtectionFactory->createFromRequest($request);
204  $view->assignMultiple([
205  'databaseAnalyzerExecuteToken' => $formProtection->generateToken('installTool', 'databaseAnalyzerExecute'),
206  ]);
207  return new ‪JsonResponse([
208  'success' => true,
209  'html' => $view->render('Maintenance/DatabaseAnalyzer'),
210  'buttons' => [
211  [
212  'btnClass' => 'btn-default t3js-databaseAnalyzer-analyze',
213  'text' => 'Run database compare again',
214  ], [
215  'btnClass' => 'btn-warning t3js-databaseAnalyzer-execute',
216  'text' => 'Apply selected changes',
217  ],
218  ],
219  ]);
220  }
221 
225  public function ‪databaseAnalyzerAnalyzeAction(ServerRequestInterface $request): ResponseInterface
226  {
227  $container = $this->lateBootService->loadExtLocalconfDatabaseAndExtTables();
228  $messageQueue = new ‪FlashMessageQueue('install');
229  $suggestions = [];
230  try {
231  $sqlReader = $container->get(SqlReader::class);
232  $sqlStatements = $sqlReader->getCreateTableStatementArray($sqlReader->getTablesDefinitionString());
233  $addCreateChange = $this->schemaMigrator->getUpdateSuggestions($sqlStatements);
234 
235  // Aggregate the per-connection statements into one flat array
236  $addCreateChange = array_merge_recursive(...array_values($addCreateChange));
237  if (!empty($addCreateChange['create_table'])) {
238  $suggestion = [
239  'key' => 'addTable',
240  'label' => 'Add tables',
241  'enabled' => true,
242  'children' => [],
243  ];
244  foreach ($addCreateChange['create_table'] as $hash => $statement) {
245  $suggestion['children'][] = [
246  'hash' => $hash,
247  'statement' => $statement,
248  ];
249  }
250  $suggestions[] = $suggestion;
251  }
252  if (!empty($addCreateChange['add'])) {
253  $suggestion = [
254  'key' => 'addField',
255  'label' => 'Add fields to tables',
256  'enabled' => true,
257  'children' => [],
258  ];
259  foreach ($addCreateChange['add'] as $hash => $statement) {
260  $suggestion['children'][] = [
261  'hash' => $hash,
262  'statement' => $statement,
263  ];
264  }
265  $suggestions[] = $suggestion;
266  }
267  if (!empty($addCreateChange['change'])) {
268  $suggestion = [
269  'key' => 'change',
270  'label' => 'Change fields',
271  'enabled' => false,
272  'children' => [],
273  ];
274  foreach ($addCreateChange['change'] as $hash => $statement) {
275  $child = [
276  'hash' => $hash,
277  'statement' => $statement,
278  ];
279  if (isset($addCreateChange['change_currentValue'][$hash])) {
280  $child['current'] = $addCreateChange['change_currentValue'][$hash];
281  }
282  $suggestion['children'][] = $child;
283  }
284  $suggestions[] = $suggestion;
285  }
286 
287  // Difference from current to expected
288  $dropRename = $this->schemaMigrator->getUpdateSuggestions($sqlStatements, true);
289 
290  // Aggregate the per-connection statements into one flat array
291  $dropRename = array_merge_recursive(...array_values($dropRename));
292  if (!empty($dropRename['change_table'])) {
293  $suggestion = [
294  'key' => 'renameTableToUnused',
295  'label' => 'Remove tables (rename with prefix)',
296  'enabled' => false,
297  'children' => [],
298  ];
299  foreach ($dropRename['change_table'] as $hash => $statement) {
300  $child = [
301  'hash' => $hash,
302  'statement' => $statement,
303  ];
304  if (!empty($dropRename['tables_count'][$hash])) {
305  $child['rowCount'] = $dropRename['tables_count'][$hash];
306  }
307  $suggestion['children'][] = $child;
308  }
309  $suggestions[] = $suggestion;
310  }
311  if (!empty($dropRename['change'])) {
312  $suggestion = [
313  'key' => 'renameTableFieldToUnused',
314  'label' => 'Remove unused fields (rename with prefix)',
315  'enabled' => false,
316  'children' => [],
317  ];
318  foreach ($dropRename['change'] as $hash => $statement) {
319  $suggestion['children'][] = [
320  'hash' => $hash,
321  'statement' => $statement,
322  ];
323  }
324  $suggestions[] = $suggestion;
325  }
326  if (!empty($dropRename['drop'])) {
327  $suggestion = [
328  'key' => 'deleteField',
329  'label' => 'Drop fields (really!)',
330  'enabled' => false,
331  'children' => [],
332  ];
333  foreach ($dropRename['drop'] as $hash => $statement) {
334  $suggestion['children'][] = [
335  'hash' => $hash,
336  'statement' => $statement,
337  ];
338  }
339  $suggestions[] = $suggestion;
340  }
341  if (!empty($dropRename['drop_table'])) {
342  $suggestion = [
343  'key' => 'deleteTable',
344  'label' => 'Drop tables (really!)',
345  'enabled' => false,
346  'children' => [],
347  ];
348  foreach ($dropRename['drop_table'] as $hash => $statement) {
349  $child = [
350  'hash' => $hash,
351  'statement' => $statement,
352  ];
353  if (!empty($dropRename['tables_count'][$hash])) {
354  $child['rowCount'] = $dropRename['tables_count'][$hash];
355  }
356  $suggestion['children'][] = $child;
357  }
358  $suggestions[] = $suggestion;
359  }
360  } catch (‪StatementException $e) {
361  $messageQueue->enqueue(new ‪FlashMessage(
362  $e->getMessage(),
363  'Database analysis failed',
364  ContextualFeedbackSeverity::ERROR
365  ));
366  }
367  return new ‪JsonResponse([
368  'success' => true,
369  'status' => $messageQueue,
370  'suggestions' => $suggestions,
371  ]);
372  }
373 
377  public function ‪databaseAnalyzerExecuteAction(ServerRequestInterface $request): ResponseInterface
378  {
379  $container = $this->lateBootService->loadExtLocalconfDatabaseAndExtTables();
380  $messageQueue = new ‪FlashMessageQueue('install');
381  $selectedHashes = $request->getParsedBody()['install']['hashes'] ?? [];
382  if (empty($selectedHashes)) {
383  $messageQueue->enqueue(new ‪FlashMessage(
384  'Please select any change by activating their respective checkboxes.',
385  'No database changes selected',
386  ContextualFeedbackSeverity::WARNING
387  ));
388  } else {
389  $sqlReader = $container->get(SqlReader::class);
390  $sqlStatements = $sqlReader->getCreateTableStatementArray($sqlReader->getTablesDefinitionString());
391  $statementHashesToPerform = array_flip($selectedHashes);
392  $results = $this->schemaMigrator->migrate($sqlStatements, $statementHashesToPerform);
393  // Create error flash messages if any
394  foreach ($results as $errorMessage) {
395  $messageQueue->enqueue(new ‪FlashMessage(
396  'Error: ' . $errorMessage,
397  'Database update failed',
398  ContextualFeedbackSeverity::ERROR
399  ));
400  }
401  $messageQueue->enqueue(new ‪FlashMessage(
402  'Executed database updates',
403  'Executed database updates'
404  ));
405  }
406  return new ‪JsonResponse([
407  'success' => true,
408  'status' => $messageQueue,
409  ]);
410  }
411 
415  public function ‪clearTablesStatsAction(ServerRequestInterface $request): ResponseInterface
416  {
417  $view = $this->‪initializeView($request);
418  $formProtection = $this->formProtectionFactory->createFromRequest($request);
419  $view->assignMultiple([
420  'clearTablesClearToken' => $formProtection->generateToken('installTool', 'clearTablesClear'),
421  ]);
422  return new ‪JsonResponse([
423  'success' => true,
424  'stats' => $this->clearTableService->getTableStatistics(),
425  'html' => $view->render('Maintenance/ClearTables'),
426  'buttons' => [
427  [
428  'btnClass' => 'btn-default t3js-clearTables-stats',
429  'text' => 'Scan again',
430  ],
431  ],
432  ]);
433  }
434 
440  public function ‪clearTablesClearAction(ServerRequestInterface $request): ResponseInterface
441  {
442  $table = $request->getParsedBody()['install']['table'];
443  if (empty($table)) {
444  throw new \RuntimeException(
445  'No table name given',
446  1501944076
447  );
448  }
449  $this->clearTableService->clearSelectedTable($table);
450  $messageQueue = new ‪FlashMessageQueue('install');
451  $messageQueue->enqueue(
452  new ‪FlashMessage('The table ' . $table . ' has been cleared.', 'Table cleared')
453  );
454  return new ‪JsonResponse([
455  'success' => true,
456  'status' => $messageQueue,
457  ]);
458  }
462  public function ‪createAdminGetDataAction(ServerRequestInterface $request): ResponseInterface
463  {
464  $view = $this->‪initializeView($request);
465  $formProtection = $this->formProtectionFactory->createFromRequest($request);
466  $view->assignMultiple([
467  'createAdminToken' => $formProtection->generateToken('installTool', 'createAdmin'),
468  'passwordPolicyRequirements' => $this->passwordPolicyValidator->getRequirements(),
469  ]);
470  return new ‪JsonResponse([
471  'success' => true,
472  'html' => $view->render('Maintenance/CreateAdmin'),
473  'buttons' => [
474  [
475  'btnClass' => 'btn-default t3js-createAdmin-create',
476  'text' => 'Create administrator user',
477  ],
478  ],
479  ]);
480  }
481 
485  public function ‪createAdminAction(ServerRequestInterface $request): ResponseInterface
486  {
487  $userCreated = false;
488  $username = preg_replace('/\\s/i', '', $request->getParsedBody()['install']['userName']);
489  $password = $request->getParsedBody()['install']['userPassword'];
490  $passwordCheck = $request->getParsedBody()['install']['userPasswordCheck'];
491  $email = $request->getParsedBody()['install']['userEmail'] ?? '';
492  $realName = $request->getParsedBody()['install']['realName'] ?? '';
493  $isSystemMaintainer = ((bool)$request->getParsedBody()['install']['userSystemMaintainer'] == '1') ? true : false;
494 
495  $messages = new ‪FlashMessageQueue('install');
496  $contextData = new ‪ContextData(newUsername: $username);
497 
498  if ($username === '') {
499  $messages->enqueue(new ‪FlashMessage(
500  'No username given.',
501  'Administrator user not created',
502  ContextualFeedbackSeverity::ERROR
503  ));
504  } elseif ($password !== $passwordCheck) {
505  $messages->enqueue(new ‪FlashMessage(
506  'Passwords do not match.',
507  'Administrator user not created',
508  ContextualFeedbackSeverity::ERROR
509  ));
510  } elseif (!$this->passwordPolicyValidator->isValidPassword($password, $contextData)) {
511  $messages->enqueue(new ‪FlashMessage(
512  'The password does not meet the password policy requirements.',
513  'Administrator user not created',
514  ContextualFeedbackSeverity::ERROR
515  ));
516  } else {
517  $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
518  $userExists = $connectionPool->getConnectionForTable('be_users')
519  ->count(
520  'uid',
521  'be_users',
522  ['username' => $username]
523  );
524  if ($userExists) {
525  $messages->enqueue(new ‪FlashMessage(
526  'A user with username "' . $username . '" exists already.',
527  'Administrator user not created',
528  ContextualFeedbackSeverity::ERROR
529  ));
530  } else {
531  $hashInstance = $this->passwordHashFactory->getDefaultHashInstance('BE');
532  $hashedPassword = $hashInstance->getHashedPassword($password);
533  $adminUserFields = [
534  'username' => $username,
535  'password' => $hashedPassword,
536  'admin' => 1,
537  'realName' => $realName,
538  'tstamp' => ‪$GLOBALS['EXEC_TIME'],
539  'crdate' => ‪$GLOBALS['EXEC_TIME'],
540  ];
541  if (GeneralUtility::validEmail($email)) {
542  $adminUserFields['email'] = $email;
543  }
544  $connectionPool->getConnectionForTable('be_users')->insert('be_users', $adminUserFields);
545  $userCreated = true;
546 
547  if ($isSystemMaintainer) {
548  // Get the new admin user uid just created
549  $newAdminUserUid = (int)$connectionPool->getConnectionForTable('be_users')->lastInsertId();
550 
551  // Get the list of the existing systemMaintainer
552  $existingSystemMaintainersList = ‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['systemMaintainers'] ?? [];
553 
554  // Add the new admin user to the existing systemMaintainer list
555  $newSystemMaintainersList = $existingSystemMaintainersList;
556  $newSystemMaintainersList[] = $newAdminUserUid;
557 
558  // Update the system/settings.php file with the new list
559  $this->configurationManager->setLocalConfigurationValuesByPathValuePairs(
560  ['SYS/systemMaintainers' => $newSystemMaintainersList]
561  );
562  }
563 
564  $messages->enqueue(new ‪FlashMessage(
565  'An administrator with username "' . $username . '" has been created successfully.',
566  'Administrator created'
567  ));
568  }
569  }
570  return new ‪JsonResponse([
571  'success' => true,
572  'status' => $messages,
573  'userCreated' => $userCreated,
574  ]);
575  }
576 
582  public function ‪languagePacksGetDataAction(ServerRequestInterface $request): ResponseInterface
583  {
584  $view = $this->‪initializeView($request);
585  $formProtection = $this->formProtectionFactory->createFromRequest($request);
586  $isWritable = $this->configurationManager->canWriteConfiguration();
587  $view->assignMultiple([
588  'isWritable' => $isWritable,
589  'languagePacksActivateLanguageToken' => $formProtection->generateToken('installTool', 'languagePacksActivateLanguage'),
590  'languagePacksDeactivateLanguageToken' => $formProtection->generateToken('installTool', 'languagePacksDeactivateLanguage'),
591  'languagePacksUpdatePackToken' => $formProtection->generateToken('installTool', 'languagePacksUpdatePack'),
592  'languagePacksUpdateIsoTimesToken' => $formProtection->generateToken('installTool', 'languagePacksUpdateIsoTimes'),
593  ]);
594  // This action needs TYPO3_CONF_VARS for full GeneralUtility::getUrl() config
595  $container = $this->lateBootService->loadExtLocalconfDatabaseAndExtTables(false, true);
596  $languagePackService = $container->get(LanguagePackService::class);
597  $extensions = $languagePackService->getExtensionLanguagePackDetails();
598  $extensionList = array_map(function (array $extension) {
599  $extension['packs'] = array_values($extension['packs']);
600  return $extension;
601  }, array_values($extensions));
602  return new ‪JsonResponse([
603  'success' => true,
604  'languages' => $languagePackService->getLanguageDetails(),
605  'extensions' => $extensionList,
606  'activeLanguages' => $languagePackService->getActiveLanguages(),
607  'activeExtensions' => array_column($extensions, 'key'),
608  'html' => $view->render('Maintenance/LanguagePacks'),
609  ]);
610  }
611 
615  public function ‪languagePacksActivateLanguageAction(ServerRequestInterface $request): ResponseInterface
616  {
617  $messageQueue = new ‪FlashMessageQueue('install');
618  $languagePackService = GeneralUtility::makeInstance(LanguagePackService::class);
619  $availableLanguages = $languagePackService->getAvailableLanguages();
620  $activeLanguages = $languagePackService->getActiveLanguages();
621  $iso = $request->getParsedBody()['install']['iso'];
622 
623  if (!$this->configurationManager->canWriteConfiguration()) {
624  $messageQueue->enqueue(new ‪FlashMessage(
625  sprintf('The language %s was not activated as the configuration file is not writable.', $availableLanguages[$iso]),
626  'Language not activated',
627  ContextualFeedbackSeverity::ERROR
628  ));
629  } else {
630  $activateArray = [];
631  foreach ($availableLanguages as $availableIso => $name) {
632  if ($availableIso === $iso && !in_array($availableIso, $activeLanguages, true)) {
633  $activateArray[] = $iso;
634  $dependencies = $this->locales->getLocaleDependencies($availableIso);
635  if (!empty($dependencies)) {
636  foreach ($dependencies as $dependency) {
637  if (!in_array($dependency, $activeLanguages, true)) {
638  $activateArray[] = $dependency;
639  }
640  }
641  }
642  }
643  }
644  if (!empty($activateArray)) {
645  $activeLanguages = array_merge($activeLanguages, $activateArray);
646  sort($activeLanguages);
647  $this->configurationManager->setLocalConfigurationValueByPath(
648  'EXTCONF/lang',
649  ['availableLanguages' => $activeLanguages]
650  );
651  $activationArray = [];
652  foreach ($activateArray as $activateIso) {
653  $activationArray[] = $availableLanguages[$activateIso] . ' (' . $activateIso . ')';
654  }
655  $messageQueue->enqueue(new ‪FlashMessage(
656  'These languages have been activated: ' . implode(', ', $activationArray)
657  ));
658  } else {
659  $messageQueue->enqueue(new ‪FlashMessage(
660  'Language with ISO code "' . $iso . '" not found or already active.',
661  '',
662  ContextualFeedbackSeverity::ERROR
663  ));
664  }
665  }
666  return new ‪JsonResponse([
667  'success' => true,
668  'status' => $messageQueue,
669  ]);
670  }
671 
677  public function ‪languagePacksDeactivateLanguageAction(ServerRequestInterface $request): ResponseInterface
678  {
679  $messageQueue = new ‪FlashMessageQueue('install');
680  $languagePackService = GeneralUtility::makeInstance(LanguagePackService::class);
681  $availableLanguages = $languagePackService->getAvailableLanguages();
682  $activeLanguages = $languagePackService->getActiveLanguages();
683  $iso = $request->getParsedBody()['install']['iso'];
684 
685  if (!$this->configurationManager->canWriteConfiguration()) {
686  $messageQueue->enqueue(new ‪FlashMessage(
687  sprintf('The language %s was not deactivated as the configuration file is not writable.', $availableLanguages[$iso]),
688  'Language not deactivated',
689  ContextualFeedbackSeverity::ERROR
690  ));
691  } else {
692  if (empty($iso)) {
693  throw new \RuntimeException('No iso code given', 1520109807);
694  }
695  $otherActiveLanguageDependencies = [];
696  foreach ($activeLanguages as $activeLanguage) {
697  if ($activeLanguage === $iso) {
698  continue;
699  }
700  $dependencies = $this->locales->getLocaleDependencies($activeLanguage);
701  if (in_array($iso, $dependencies, true)) {
702  $otherActiveLanguageDependencies[] = $activeLanguage;
703  }
704  }
705  if (!empty($otherActiveLanguageDependencies)) {
706  // Error: Must disable dependencies first
707  $dependentArray = [];
708  foreach ($otherActiveLanguageDependencies as $dependency) {
709  $dependentArray[] = $availableLanguages[$dependency] . ' (' . $dependency . ')';
710  }
711  $messageQueue->enqueue(new ‪FlashMessage(
712  'Language "' . $availableLanguages[$iso] . ' (' . $iso . ')" can not be deactivated. These'
713  . ' other languages depend on it and need to be deactivated before:'
714  . implode(', ', $dependentArray),
715  '',
716  ContextualFeedbackSeverity::ERROR
717  ));
718  } else {
719  if (in_array($iso, $activeLanguages, true)) {
720  // Deactivate this language
721  $newActiveLanguages = [];
722  foreach ($activeLanguages as $activeLanguage) {
723  if ($activeLanguage === $iso) {
724  continue;
725  }
726  $newActiveLanguages[] = $activeLanguage;
727  }
728  $this->configurationManager->setLocalConfigurationValueByPath(
729  'EXTCONF/lang',
730  ['availableLanguages' => $newActiveLanguages]
731  );
732  $messageQueue->enqueue(new ‪FlashMessage(
733  'Language "' . $availableLanguages[$iso] . ' (' . $iso . ')" has been deactivated'
734  ));
735  } else {
736  $messageQueue->enqueue(new ‪FlashMessage(
737  'Language "' . $availableLanguages[$iso] . ' (' . $iso . ')" has not been deactivated',
738  '',
739  ContextualFeedbackSeverity::ERROR
740  ));
741  }
742  }
743  }
744  return new ‪JsonResponse([
745  'success' => true,
746  'status' => $messageQueue,
747  ]);
748  }
749 
755  public function ‪languagePacksUpdatePackAction(ServerRequestInterface $request): ResponseInterface
756  {
757  $container = $this->lateBootService->loadExtLocalconfDatabaseAndExtTables(false, true);
758  $iso = $request->getParsedBody()['install']['iso'];
759  $key = $request->getParsedBody()['install']['extension'];
760 
761  $languagePackService = $container->get(LanguagePackService::class);
762 
763  return new ‪JsonResponse([
764  'success' => true,
765  'packResult' => $languagePackService->languagePackDownload($key, $iso),
766  ]);
767  }
768 
772  public function ‪languagePacksUpdateIsoTimesAction(ServerRequestInterface $request): ResponseInterface
773  {
774  $isos = $request->getParsedBody()['install']['isos'];
775  $languagePackService = GeneralUtility::makeInstance(LanguagePackService::class);
776  $languagePackService->setLastUpdatedIsoCode($isos);
777 
778  // The cache manager is already instantiated in the install tool
779  // with some hacked settings to disable caching of extbase and fluid.
780  // We want a "fresh" object here to operate on a different cache setup.
781  // cacheManager implements SingletonInterface, so the only way to get a "fresh"
782  // instance is by circumventing makeInstance and using new directly!
783  $cacheManager = new ‪CacheManager();
784  $cacheManager->setCacheConfigurations(‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']);
785  $cacheManager->getCache('l10n')->flush();
786 
787  return new ‪JsonResponse(['success' => true]);
788  }
789 
793  public function ‪resetBackendUserUcAction(): ResponseInterface
794  {
795  GeneralUtility::makeInstance(ConnectionPool::class)
796  ->getQueryBuilderForTable('be_users')
797  ->update('be_users')
798  ->set('uc', '')
799  ->executeStatement();
800  $messageQueue = new ‪FlashMessageQueue('install');
801  $messageQueue->enqueue(new ‪FlashMessage(
802  'Preferences of all backend users have been reset',
803  'Reset preferences of all backend users'
804  ));
805  return new ‪JsonResponse([
806  'success' => true,
807  'status' => $messageQueue,
808  ]);
809  }
810 }
‪TYPO3\CMS\Core\Localization\LanguageServiceFactory
Definition: LanguageServiceFactory.php:25
‪TYPO3\CMS\Core\Crypto\PasswordHashing\PasswordHashFactory
Definition: PasswordHashFactory.php:27
‪TYPO3\CMS\Core\Database\Schema\Exception\StatementException
Definition: StatementException.php:24
‪TYPO3\CMS\Install\Controller\MaintenanceController\clearTypo3tempFilesAction
‪clearTypo3tempFilesAction(ServerRequestInterface $request)
Definition: MaintenanceController.php:137
‪TYPO3\CMS\Install\Controller\MaintenanceController\__construct
‪__construct(private readonly LateBootService $lateBootService, private readonly ClearCacheService $clearCacheService, private readonly ClearTableService $clearTableService, private readonly ConfigurationManager $configurationManager, private readonly PasswordHashFactory $passwordHashFactory, private readonly Locales $locales, private readonly LanguageServiceFactory $languageServiceFactory, private readonly FormProtectionFactory $formProtectionFactory, private readonly SchemaMigrator $schemaMigrator,)
Definition: MaintenanceController.php:57
‪TYPO3\CMS\Install\Controller\MaintenanceController\clearTablesClearAction
‪clearTablesClearAction(ServerRequestInterface $request)
Definition: MaintenanceController.php:440
‪TYPO3\CMS\Core\Core\Environment\isComposerMode
‪static isComposerMode()
Definition: Environment.php:137
‪TYPO3\CMS\Install\Controller\MaintenanceController\createAdminGetDataAction
‪createAdminGetDataAction(ServerRequestInterface $request)
Definition: MaintenanceController.php:462
‪TYPO3\CMS\Core\Core\ClassLoadingInformation\dumpClassLoadingInformation
‪static dumpClassLoadingInformation()
Definition: ClassLoadingInformation.php:89
‪TYPO3\CMS\Install\Service\Typo3tempFileService
Definition: Typo3tempFileService.php:32
‪TYPO3\CMS\Core\Core\ClassLoadingInformation
Definition: ClassLoadingInformation.php:35
‪TYPO3\CMS\Core\Localization\Locales
Definition: Locales.php:36
‪TYPO3\CMS\Install\Controller\MaintenanceController\languagePacksUpdatePackAction
‪languagePacksUpdatePackAction(ServerRequestInterface $request)
Definition: MaintenanceController.php:755
‪TYPO3\CMS\Core\Database\Schema\SqlReader
Definition: SqlReader.php:31
‪TYPO3\CMS\Install\Controller\MaintenanceController\cardsAction
‪cardsAction(ServerRequestInterface $request)
Definition: MaintenanceController.php:80
‪TYPO3\CMS\Install\Controller\MaintenanceController\languagePacksDeactivateLanguageAction
‪languagePacksDeactivateLanguageAction(ServerRequestInterface $request)
Definition: MaintenanceController.php:677
‪TYPO3\CMS\Core\Database\Schema\SchemaMigrator
Definition: SchemaMigrator.php:38
‪TYPO3\CMS\Install\Service\ClearTableService
Definition: ClearTableService.php:30
‪TYPO3\CMS\Install\Controller\MaintenanceController\languagePacksUpdateIsoTimesAction
‪languagePacksUpdateIsoTimesAction(ServerRequestInterface $request)
Definition: MaintenanceController.php:772
‪TYPO3\CMS\Core\Type\ContextualFeedbackSeverity
‪ContextualFeedbackSeverity
Definition: ContextualFeedbackSeverity.php:25
‪TYPO3\CMS\Install\Controller\MaintenanceController\languagePacksGetDataAction
‪languagePacksGetDataAction(ServerRequestInterface $request)
Definition: MaintenanceController.php:582
‪TYPO3\CMS\Install\Controller
Definition: AbstractController.php:18
‪TYPO3\CMS\Core\PasswordPolicy\NEW_USER_PASSWORD
‪@ NEW_USER_PASSWORD
Definition: PasswordPolicyAction.php:27
‪TYPO3\CMS\Core\PasswordPolicy\PasswordPolicyValidator
Definition: PasswordPolicyValidator.php:27
‪TYPO3\CMS\Install\Controller\MaintenanceController\clearTablesStatsAction
‪clearTablesStatsAction(ServerRequestInterface $request)
Definition: MaintenanceController.php:415
‪TYPO3\CMS\Core\Cache\CacheManager
Definition: CacheManager.php:36
‪TYPO3\CMS\Install\Controller\MaintenanceController\databaseAnalyzerExecuteAction
‪databaseAnalyzerExecuteAction(ServerRequestInterface $request)
Definition: MaintenanceController.php:377
‪TYPO3\CMS\Install\Service\LateBootService
Definition: LateBootService.php:27
‪TYPO3\CMS\Core\Service\OpcodeCacheService
Definition: OpcodeCacheService.php:27
‪TYPO3\CMS\Install\Controller\AbstractController\initializeView
‪initializeView(ServerRequestInterface $request)
Definition: AbstractController.php:39
‪TYPO3\CMS\Install\Service\LanguagePackService
Definition: LanguagePackService.php:43
‪TYPO3\CMS\Core\Messaging\FlashMessage
Definition: FlashMessage.php:27
‪TYPO3\CMS\Core\FormProtection\FormProtectionFactory
Definition: FormProtectionFactory.php:43
‪TYPO3\CMS\Install\Controller\MaintenanceController\clearTypo3tempFilesStatsAction
‪clearTypo3tempFilesStatsAction(ServerRequestInterface $request)
Definition: MaintenanceController.php:109
‪TYPO3\CMS\Core\Http\JsonResponse
Definition: JsonResponse.php:28
‪TYPO3\CMS\Install\Controller\MaintenanceController\createAdminAction
‪createAdminAction(ServerRequestInterface $request)
Definition: MaintenanceController.php:485
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Core\Core\Environment
Definition: Environment.php:41
‪TYPO3\CMS\Install\Controller\MaintenanceController\resetBackendUserUcAction
‪resetBackendUserUcAction()
Definition: MaintenanceController.php:793
‪TYPO3\CMS\Install\Controller\MaintenanceController
Definition: MaintenanceController.php:54
‪TYPO3\CMS\Install\Controller\AbstractController
Definition: AbstractController.php:35
‪TYPO3\CMS\Core\PasswordPolicy\PasswordPolicyAction
‪PasswordPolicyAction
Definition: PasswordPolicyAction.php:24
‪TYPO3\CMS\Install\Controller\MaintenanceController\languagePacksActivateLanguageAction
‪languagePacksActivateLanguageAction(ServerRequestInterface $request)
Definition: MaintenanceController.php:615
‪TYPO3\CMS\Install\Controller\MaintenanceController\cacheClearAllAction
‪cacheClearAllAction()
Definition: MaintenanceController.php:92
‪TYPO3\CMS\Install\Controller\MaintenanceController\$passwordPolicyValidator
‪PasswordPolicyValidator $passwordPolicyValidator
Definition: MaintenanceController.php:55
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:46
‪TYPO3\CMS\Install\Controller\MaintenanceController\dumpAutoloadAction
‪dumpAutoloadAction()
Definition: MaintenanceController.php:175
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Core\Messaging\FlashMessageQueue
Definition: FlashMessageQueue.php:29
‪TYPO3\CMS\Install\Service\ClearCacheService
Definition: ClearCacheService.php:27
‪TYPO3\CMS\Install\Controller\MaintenanceController\databaseAnalyzerAnalyzeAction
‪databaseAnalyzerAnalyzeAction(ServerRequestInterface $request)
Definition: MaintenanceController.php:225
‪TYPO3\CMS\Install\Controller\MaintenanceController\databaseAnalyzerAction
‪databaseAnalyzerAction(ServerRequestInterface $request)
Definition: MaintenanceController.php:200
‪TYPO3\CMS\Core\PasswordPolicy\Validator\Dto\ContextData
Definition: ContextData.php:28