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