From 412af370ee94e923a15c65ee408418b8249b53cf Mon Sep 17 00:00:00 2001
From: Oliver Bartsch <bo@cedev.de>
Date: Tue, 17 Jan 2023 12:36:11 +0100
Subject: [PATCH] [TASK] Cleanup UpgradeWizardService

To simplify working with the UpgradeWizardService,
the patch cleans up the following:

* Extract database related tasks into an own service
* Fetch UpgradeWizardService via container

Resolves: #99570
Releases: main
Change-Id: Ia18aa19cea8743890a4e85629b7e720ee73a7220
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/77416
Reviewed-by: Oliver Bartsch <bo@cedev.de>
Reviewed-by: Benni Mack <benni@typo3.org>
Reviewed-by: Benjamin Franzke <bfr@qbus.de>
Tested-by: Benni Mack <benni@typo3.org>
Tested-by: core-ci <typo3@b13.com>
Tested-by: Benjamin Franzke <bfr@qbus.de>
Tested-by: Oliver Bartsch <bo@cedev.de>
---
 .../Command/UpgradeWizardListCommand.php      |  23 +--
 .../Command/UpgradeWizardRunCommand.php       |  24 ++-
 .../Classes/Controller/UpgradeController.php  |  37 ++---
 .../Service/DatabaseUpgradeWizardsService.php | 141 ++++++++++++++++++
 .../Classes/Service/UpgradeWizardsService.php | 115 --------------
 .../install/Classes/ServiceProvider.php       |  11 +-
 .../Updates/DatabaseUpdatedPrerequisite.php   |  16 +-
 .../install/Configuration/Services.yaml       |   3 +
 8 files changed, 191 insertions(+), 179 deletions(-)
 create mode 100644 typo3/sysext/install/Classes/Service/DatabaseUpgradeWizardsService.php

diff --git a/typo3/sysext/install/Classes/Command/UpgradeWizardListCommand.php b/typo3/sysext/install/Classes/Command/UpgradeWizardListCommand.php
index 78c67c506305..46b1b3f40ab1 100644
--- a/typo3/sysext/install/Classes/Command/UpgradeWizardListCommand.php
+++ b/typo3/sysext/install/Classes/Command/UpgradeWizardListCommand.php
@@ -37,15 +37,7 @@ use TYPO3\CMS\Install\Updates\UpgradeWizardInterface;
  */
 class UpgradeWizardListCommand extends Command
 {
-    /**
-     * @var LateBootService
-     */
-    private $lateBootService;
-
-    /**
-     * @var UpgradeWizardsService
-     */
-    private $upgradeWizardsService;
+    private UpgradeWizardsService $upgradeWizardsService;
 
     /**
      * @var OutputInterface|\Symfony\Component\Console\Style\StyleInterface
@@ -57,13 +49,8 @@ class UpgradeWizardListCommand extends Command
      */
     private $input;
 
-    public function __construct(
-        string $name,
-        LateBootService $lateBootService,
-        UpgradeWizardsService $upgradeWizardsService
-    ) {
-        $this->lateBootService = $lateBootService;
-        $this->upgradeWizardsService = $upgradeWizardsService;
+    public function __construct(string $name, private readonly LateBootService $lateBootService)
+    {
         parent::__construct($name);
     }
 
@@ -72,7 +59,9 @@ class UpgradeWizardListCommand extends Command
      */
     protected function bootstrap(): void
     {
-        $this->lateBootService->loadExtLocalconfDatabaseAndExtTables(false);
+        $this->upgradeWizardsService = $this->lateBootService
+            ->loadExtLocalconfDatabaseAndExtTables(false)
+            ->get(UpgradeWizardsService::class);
         Bootstrap::initializeBackendUser(CommandLineUserAuthentication::class);
         Bootstrap::initializeBackendAuthentication();
     }
diff --git a/typo3/sysext/install/Classes/Command/UpgradeWizardRunCommand.php b/typo3/sysext/install/Classes/Command/UpgradeWizardRunCommand.php
index 2754a1f86c66..bad921f19202 100644
--- a/typo3/sysext/install/Classes/Command/UpgradeWizardRunCommand.php
+++ b/typo3/sysext/install/Classes/Command/UpgradeWizardRunCommand.php
@@ -27,6 +27,7 @@ use Symfony\Component\Console\Style\SymfonyStyle;
 use TYPO3\CMS\Core\Authentication\CommandLineUserAuthentication;
 use TYPO3\CMS\Core\Core\Bootstrap;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Install\Service\DatabaseUpgradeWizardsService;
 use TYPO3\CMS\Install\Service\LateBootService;
 use TYPO3\CMS\Install\Service\UpgradeWizardsService;
 use TYPO3\CMS\Install\Updates\ChattyInterface;
@@ -42,15 +43,7 @@ use TYPO3\CMS\Install\Updates\UpgradeWizardInterface;
  */
 class UpgradeWizardRunCommand extends Command
 {
-    /**
-     * @var LateBootService
-     */
-    private $lateBootService;
-
-    /**
-     * @var UpgradeWizardsService
-     */
-    private $upgradeWizardsService;
+    private UpgradeWizardsService $upgradeWizardsService;
 
     /**
      * @var OutputInterface|\Symfony\Component\Console\Style\StyleInterface
@@ -64,11 +57,9 @@ class UpgradeWizardRunCommand extends Command
 
     public function __construct(
         string $name,
-        LateBootService $lateBootService,
-        UpgradeWizardsService $upgradeWizardsService
+        private readonly LateBootService $lateBootService,
+        private readonly DatabaseUpgradeWizardsService $databaseUpgradeWizardsService
     ) {
-        $this->lateBootService = $lateBootService;
-        $this->upgradeWizardsService = $upgradeWizardsService;
         parent::__construct($name);
     }
 
@@ -78,10 +69,13 @@ class UpgradeWizardRunCommand extends Command
      */
     protected function bootstrap(): void
     {
-        $this->lateBootService->loadExtLocalconfDatabaseAndExtTables(false);
+        $this->upgradeWizardsService = $this->lateBootService
+            ->loadExtLocalconfDatabaseAndExtTables(false)
+            ->get(UpgradeWizardsService::class);
         Bootstrap::initializeBackendUser(CommandLineUserAuthentication::class);
         Bootstrap::initializeBackendAuthentication();
-        $this->upgradeWizardsService->isDatabaseCharsetUtf8() ?: $this->upgradeWizardsService->setDatabaseCharsetUtf8();
+        $this->databaseUpgradeWizardsService->isDatabaseCharsetUtf8()
+            ?: $this->databaseUpgradeWizardsService->setDatabaseCharsetUtf8();
     }
 
     /**
diff --git a/typo3/sysext/install/Classes/Controller/UpgradeController.php b/typo3/sysext/install/Classes/Controller/UpgradeController.php
index 0e9cc6a5e23d..5a5e569e5d5d 100644
--- a/typo3/sysext/install/Classes/Controller/UpgradeController.php
+++ b/typo3/sysext/install/Classes/Controller/UpgradeController.php
@@ -69,6 +69,7 @@ use TYPO3\CMS\Install\ExtensionScanner\Php\MatcherFactory;
 use TYPO3\CMS\Install\Service\ClearCacheService;
 use TYPO3\CMS\Install\Service\CoreUpdateService;
 use TYPO3\CMS\Install\Service\CoreVersionService;
+use TYPO3\CMS\Install\Service\DatabaseUpgradeWizardsService;
 use TYPO3\CMS\Install\Service\LateBootService;
 use TYPO3\CMS\Install\Service\LoadTcaService;
 use TYPO3\CMS\Install\Service\UpgradeWizardsService;
@@ -93,7 +94,7 @@ class UpgradeController extends AbstractController
     public function __construct(
         protected readonly PackageManager $packageManager,
         private readonly LateBootService $lateBootService,
-        private readonly UpgradeWizardsService $upgradeWizardsService,
+        private readonly DatabaseUpgradeWizardsService $databaseUpgradeWizardsService,
         private readonly FormProtectionFactory $formProtectionFactory
     ) {
     }
@@ -978,7 +979,7 @@ class UpgradeController extends AbstractController
         $adds = [];
         $needsUpdate = false;
         try {
-            $adds = $this->upgradeWizardsService->getBlockingDatabaseAdds();
+            $adds = $this->databaseUpgradeWizardsService->getBlockingDatabaseAdds();
             $this->lateBootService->resetGlobalContainer();
             if (!empty($adds)) {
                 $needsUpdate = true;
@@ -1000,7 +1001,7 @@ class UpgradeController extends AbstractController
     {
         // ext_localconf, db and ext_tables must be loaded for the updates :(
         $this->lateBootService->loadExtLocalconfDatabaseAndExtTables(false);
-        $errors = $this->upgradeWizardsService->addMissingTablesAndFields();
+        $errors = $this->databaseUpgradeWizardsService->addMissingTablesAndFields();
         $this->lateBootService->resetGlobalContainer();
         $messages = new FlashMessageQueue('install');
         // Discard empty values which indicate success
@@ -1034,7 +1035,7 @@ class UpgradeController extends AbstractController
      */
     public function upgradeWizardsBlockingDatabaseCharsetFixAction(): ResponseInterface
     {
-        $this->upgradeWizardsService->setDatabaseCharsetUtf8();
+        $this->databaseUpgradeWizardsService->setDatabaseCharsetUtf8();
         $messages = new FlashMessageQueue('install');
         $messages->enqueue(new FlashMessage(
             '',
@@ -1054,7 +1055,7 @@ class UpgradeController extends AbstractController
      */
     public function upgradeWizardsBlockingDatabaseCharsetTestAction(): ResponseInterface
     {
-        $result = !$this->upgradeWizardsService->isDatabaseCharsetUtf8();
+        $result = !$this->databaseUpgradeWizardsService->isDatabaseCharsetUtf8();
         return new JsonResponse([
             'success' => true,
             'needsUpdate' => $result,
@@ -1066,9 +1067,10 @@ class UpgradeController extends AbstractController
      */
     public function upgradeWizardsDoneUpgradesAction(): ResponseInterface
     {
-        $this->lateBootService->loadExtLocalconfDatabaseAndExtTables(false);
-        $wizardsDone = $this->upgradeWizardsService->listOfWizardsDone();
-        $rowUpdatersDone = $this->upgradeWizardsService->listOfRowUpdatersDone();
+        $container = $this->lateBootService->loadExtLocalconfDatabaseAndExtTables(false);
+        $upgradeWizardsService = $container->get(UpgradeWizardsService::class);
+        $wizardsDone = $upgradeWizardsService->listOfWizardsDone();
+        $rowUpdatersDone = $upgradeWizardsService->listOfRowUpdatersDone();
         $this->lateBootService->resetGlobalContainer();
         $messages = new FlashMessageQueue('install');
         if (empty($wizardsDone) && empty($rowUpdatersDone)) {
@@ -1091,9 +1093,9 @@ class UpgradeController extends AbstractController
     public function upgradeWizardsExecuteAction(ServerRequestInterface $request): ResponseInterface
     {
         // ext_localconf, db and ext_tables must be loaded for the updates :(
-        $this->lateBootService->loadExtLocalconfDatabaseAndExtTables(false);
+        $container = $this->lateBootService->loadExtLocalconfDatabaseAndExtTables(false);
         $identifier = $request->getParsedBody()['install']['identifier'];
-        $messages = $this->upgradeWizardsService->executeWizard($identifier);
+        $messages = $container->get(UpgradeWizardsService::class)->executeWizard($identifier);
         $this->lateBootService->resetGlobalContainer();
         return new JsonResponse([
             'success' => true,
@@ -1107,9 +1109,9 @@ class UpgradeController extends AbstractController
     public function upgradeWizardsInputAction(ServerRequestInterface $request): ResponseInterface
     {
         // ext_localconf, db and ext_tables must be loaded for the updates :(
-        $this->lateBootService->loadExtLocalconfDatabaseAndExtTables(false);
+        $container = $this->lateBootService->loadExtLocalconfDatabaseAndExtTables(false);
         $identifier = $request->getParsedBody()['install']['identifier'];
-        $result = $this->upgradeWizardsService->getWizardUserInput($identifier);
+        $result = $container->get(UpgradeWizardsService::class)->getWizardUserInput($identifier);
         $this->lateBootService->resetGlobalContainer();
         return new JsonResponse([
             'success' => true,
@@ -1124,8 +1126,8 @@ class UpgradeController extends AbstractController
     public function upgradeWizardsListAction(): ResponseInterface
     {
         // ext_localconf, db and ext_tables must be loaded for the updates :(
-        $this->lateBootService->loadExtLocalconfDatabaseAndExtTables(false);
-        $wizards = $this->upgradeWizardsService->getUpgradeWizardsList();
+        $container = $this->lateBootService->loadExtLocalconfDatabaseAndExtTables(false);
+        $wizards = $container->get(UpgradeWizardsService::class)->getUpgradeWizardsList();
         $this->lateBootService->resetGlobalContainer();
         return new JsonResponse([
             'success' => true,
@@ -1139,10 +1141,11 @@ class UpgradeController extends AbstractController
      */
     public function upgradeWizardsMarkUndoneAction(ServerRequestInterface $request): ResponseInterface
     {
-        $this->lateBootService->loadExtLocalconfDatabaseAndExtTables(false);
+        $container = $this->lateBootService->loadExtLocalconfDatabaseAndExtTables(false);
+        $upgradeWizardsService = $container->get(UpgradeWizardsService::class);
         $wizardToBeMarkedAsUndoneIdentifier = $request->getParsedBody()['install']['identifier'];
-        $wizardToBeMarkedAsUndone = $this->upgradeWizardsService->getWizardInformationByIdentifier($wizardToBeMarkedAsUndoneIdentifier);
-        $result = $this->upgradeWizardsService->markWizardUndone($wizardToBeMarkedAsUndoneIdentifier);
+        $wizardToBeMarkedAsUndone = $upgradeWizardsService->getWizardInformationByIdentifier($wizardToBeMarkedAsUndoneIdentifier);
+        $result = $upgradeWizardsService->markWizardUndone($wizardToBeMarkedAsUndoneIdentifier);
         $this->lateBootService->resetGlobalContainer();
         $messages = new FlashMessageQueue('install');
         if ($result) {
diff --git a/typo3/sysext/install/Classes/Service/DatabaseUpgradeWizardsService.php b/typo3/sysext/install/Classes/Service/DatabaseUpgradeWizardsService.php
new file mode 100644
index 000000000000..4a8b857c7539
--- /dev/null
+++ b/typo3/sysext/install/Classes/Service/DatabaseUpgradeWizardsService.php
@@ -0,0 +1,141 @@
+<?php
+
+declare(strict_types=1);
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+namespace TYPO3\CMS\Install\Service;
+
+use Doctrine\DBAL\Platforms\MySQLPlatform;
+use Doctrine\DBAL\Schema\Column;
+use Doctrine\DBAL\Schema\Table;
+use TYPO3\CMS\Core\Database\ConnectionPool;
+use TYPO3\CMS\Core\Database\Schema\SchemaMigrator;
+use TYPO3\CMS\Core\Database\Schema\SqlReader;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+
+/**
+ * Service class executing database tasks for upgrade wizards
+ * @internal This class is only meant to be used within EXT:install and is not part of the TYPO3 Core API.
+ */
+class DatabaseUpgradeWizardsService
+{
+    /**
+     * Get a list of tables, single columns and indexes to add.
+     *
+     * @return array Array with possible keys "tables", "columns", "indexes"
+     */
+    public function getBlockingDatabaseAdds(): array
+    {
+        $sqlReader = GeneralUtility::makeInstance(SqlReader::class);
+        $databaseDefinitions = $sqlReader->getCreateTableStatementArray($sqlReader->getTablesDefinitionString());
+
+        $schemaMigrator = GeneralUtility::makeInstance(SchemaMigrator::class);
+        $databaseDifferences = $schemaMigrator->getSchemaDiffs($databaseDefinitions);
+
+        $adds = [];
+        foreach ($databaseDifferences as $schemaDiff) {
+            foreach ($schemaDiff->newTables as $newTable) {
+                /** @var Table $newTable */
+                if (!is_array($adds['tables'] ?? false)) {
+                    $adds['tables'] = [];
+                }
+                $adds['tables'][] = [
+                    'table' => $newTable->getName(),
+                ];
+            }
+            foreach ($schemaDiff->changedTables as $changedTable) {
+                foreach ($changedTable->addedColumns as $addedColumn) {
+                    /** @var Column $addedColumn */
+                    if (!is_array($adds['columns'] ?? false)) {
+                        $adds['columns'] = [];
+                    }
+                    $adds['columns'][] = [
+                        'table' => $changedTable->name,
+                        'field' => $addedColumn->getName(),
+                    ];
+                }
+                foreach ($changedTable->addedIndexes as $addedIndex) {
+                    /** $var Index $addedIndex */
+                    if (!is_array($adds['indexes'] ?? false)) {
+                        $adds['indexes'] = [];
+                    }
+                    $adds['indexes'][] = [
+                        'table' => $changedTable->name,
+                        'index' => $addedIndex->getName(),
+                    ];
+                }
+            }
+        }
+
+        return $adds;
+    }
+
+    /**
+     * Add missing tables, indexes and fields to DB.
+     */
+    public function addMissingTablesAndFields(): array
+    {
+        $sqlReader = GeneralUtility::makeInstance(SqlReader::class);
+        $databaseDefinitions = $sqlReader->getCreateTableStatementArray($sqlReader->getTablesDefinitionString());
+        $schemaMigrator = GeneralUtility::makeInstance(SchemaMigrator::class);
+        return $schemaMigrator->install($databaseDefinitions, true);
+    }
+
+    /**
+     * True if DB main charset on mysql is utf8
+     *
+     * @return bool True if charset is ok
+     */
+    public function isDatabaseCharsetUtf8(): bool
+    {
+        $connection = GeneralUtility::makeInstance(ConnectionPool::class)
+            ->getConnectionByName(ConnectionPool::DEFAULT_CONNECTION_NAME);
+
+        $isDefaultConnectionMysql = ($connection->getDatabasePlatform() instanceof MySQLPlatform);
+
+        if (!$isDefaultConnectionMysql) {
+            // Not tested on non mysql
+            $charsetOk = true;
+        } else {
+            $queryBuilder = $connection->createQueryBuilder();
+            $charset = (string)$queryBuilder->select('DEFAULT_CHARACTER_SET_NAME')
+                ->from('information_schema.SCHEMATA')
+                ->where(
+                    $queryBuilder->expr()->eq(
+                        'SCHEMA_NAME',
+                        $queryBuilder->createNamedParameter($connection->getDatabase())
+                    )
+                )
+                ->setMaxResults(1)
+                ->executeQuery()
+                ->fetchOne();
+            // check if database charset is utf-8, also allows utf8mb4
+            $charsetOk = str_starts_with($charset, 'utf8');
+        }
+        return $charsetOk;
+    }
+
+    /**
+     * Set default connection MySQL database charset to utf8.
+     * Should be called only *if* default database connection is actually MySQL
+     */
+    public function setDatabaseCharsetUtf8()
+    {
+        $connection = GeneralUtility::makeInstance(ConnectionPool::class)
+            ->getConnectionByName(ConnectionPool::DEFAULT_CONNECTION_NAME);
+        $sql = 'ALTER DATABASE ' . $connection->quoteIdentifier($connection->getDatabase()) . ' CHARACTER SET utf8';
+        $connection->exec($sql);
+    }
+}
diff --git a/typo3/sysext/install/Classes/Service/UpgradeWizardsService.php b/typo3/sysext/install/Classes/Service/UpgradeWizardsService.php
index 7e0dc1a15008..eba3b2ed48de 100644
--- a/typo3/sysext/install/Classes/Service/UpgradeWizardsService.php
+++ b/typo3/sysext/install/Classes/Service/UpgradeWizardsService.php
@@ -17,15 +17,8 @@ declare(strict_types=1);
 
 namespace TYPO3\CMS\Install\Service;
 
-use Doctrine\DBAL\Platforms\MySQLPlatform;
-use Doctrine\DBAL\Schema\Column;
-use Doctrine\DBAL\Schema\Table;
 use Symfony\Component\Console\Output\Output;
 use Symfony\Component\Console\Output\StreamOutput;
-use TYPO3\CMS\Core\Database\Connection;
-use TYPO3\CMS\Core\Database\ConnectionPool;
-use TYPO3\CMS\Core\Database\Schema\SchemaMigrator;
-use TYPO3\CMS\Core\Database\Schema\SqlReader;
 use TYPO3\CMS\Core\Messaging\FlashMessage;
 use TYPO3\CMS\Core\Messaging\FlashMessageQueue;
 use TYPO3\CMS\Core\Registry;
@@ -147,114 +140,6 @@ class UpgradeWizardsService
         return $aWizardHasBeenMarkedUndone;
     }
 
-    /**
-     * Get a list of tables, single columns and indexes to add.
-     *
-     * @return array Array with possible keys "tables", "columns", "indexes"
-     */
-    public function getBlockingDatabaseAdds(): array
-    {
-        $sqlReader = GeneralUtility::makeInstance(SqlReader::class);
-        $databaseDefinitions = $sqlReader->getCreateTableStatementArray($sqlReader->getTablesDefinitionString());
-
-        $schemaMigrator = GeneralUtility::makeInstance(SchemaMigrator::class);
-        $databaseDifferences = $schemaMigrator->getSchemaDiffs($databaseDefinitions);
-
-        $adds = [];
-        foreach ($databaseDifferences as $schemaDiff) {
-            foreach ($schemaDiff->newTables as $newTable) {
-                /** @var Table $newTable */
-                if (!is_array($adds['tables'] ?? false)) {
-                    $adds['tables'] = [];
-                }
-                $adds['tables'][] = [
-                    'table' => $newTable->getName(),
-                ];
-            }
-            foreach ($schemaDiff->changedTables as $changedTable) {
-                foreach ($changedTable->addedColumns as $addedColumn) {
-                    /** @var Column $addedColumn */
-                    if (!is_array($adds['columns'] ?? false)) {
-                        $adds['columns'] = [];
-                    }
-                    $adds['columns'][] = [
-                        'table' => $changedTable->name,
-                        'field' => $addedColumn->getName(),
-                    ];
-                }
-                foreach ($changedTable->addedIndexes as $addedIndex) {
-                    /** $var Index $addedIndex */
-                    if (!is_array($adds['indexes'] ?? false)) {
-                        $adds['indexes'] = [];
-                    }
-                    $adds['indexes'][] = [
-                        'table' => $changedTable->name,
-                        'index' => $addedIndex->getName(),
-                    ];
-                }
-            }
-        }
-
-        return $adds;
-    }
-
-    /**
-     * Add missing tables, indexes and fields to DB.
-     */
-    public function addMissingTablesAndFields(): array
-    {
-        $sqlReader = GeneralUtility::makeInstance(SqlReader::class);
-        $databaseDefinitions = $sqlReader->getCreateTableStatementArray($sqlReader->getTablesDefinitionString());
-        $schemaMigrator = GeneralUtility::makeInstance(SchemaMigrator::class);
-        return $schemaMigrator->install($databaseDefinitions, true);
-    }
-
-    /**
-     * True if DB main charset on mysql is utf8
-     *
-     * @return bool True if charset is ok
-     */
-    public function isDatabaseCharsetUtf8(): bool
-    {
-        $connection = GeneralUtility::makeInstance(ConnectionPool::class)
-            ->getConnectionByName(ConnectionPool::DEFAULT_CONNECTION_NAME);
-
-        $isDefaultConnectionMysql = ($connection->getDatabasePlatform() instanceof MySQLPlatform);
-
-        if (!$isDefaultConnectionMysql) {
-            // Not tested on non mysql
-            $charsetOk = true;
-        } else {
-            $queryBuilder = $connection->createQueryBuilder();
-            $charset = (string)$queryBuilder->select('DEFAULT_CHARACTER_SET_NAME')
-                ->from('information_schema.SCHEMATA')
-                ->where(
-                    $queryBuilder->expr()->eq(
-                        'SCHEMA_NAME',
-                        $queryBuilder->createNamedParameter($connection->getDatabase())
-                    )
-                )
-                ->setMaxResults(1)
-                ->executeQuery()
-                ->fetchOne();
-            // check if database charset is utf-8, also allows utf8mb4
-            $charsetOk = str_starts_with($charset, 'utf8');
-        }
-        return $charsetOk;
-    }
-
-    /**
-     * Set default connection MySQL database charset to utf8.
-     * Should be called only *if* default database connection is actually MySQL
-     */
-    public function setDatabaseCharsetUtf8()
-    {
-        $connection = GeneralUtility::makeInstance(ConnectionPool::class)
-            ->getConnectionByName(ConnectionPool::DEFAULT_CONNECTION_NAME);
-        $sql = 'ALTER DATABASE ' . $connection->quoteIdentifier($connection->getDatabase()) . ' CHARACTER SET utf8';
-        $connection->exec($sql);
-    }
-
     /**
      * Get list of registered upgrade wizards not marked done.
      *
diff --git a/typo3/sysext/install/Classes/ServiceProvider.php b/typo3/sysext/install/Classes/ServiceProvider.php
index 5f74dc36d67e..2f0657bcd4b1 100644
--- a/typo3/sysext/install/Classes/ServiceProvider.php
+++ b/typo3/sysext/install/Classes/ServiceProvider.php
@@ -77,7 +77,7 @@ class ServiceProvider extends AbstractServiceProvider
             Service\SilentConfigurationUpgradeService::class => [ static::class, 'getSilentConfigurationUpgradeService' ],
             Service\SilentTemplateFileUpgradeService::class => [ static::class, 'getSilentTemplateFileUpgradeService' ],
             Service\WebServerConfigurationFileService::class => [ static::class, 'getWebServerConfigurationFileService' ],
-            Service\UpgradeWizardsService::class => [ static::class, 'getUpgradeWizardsService' ],
+            Service\DatabaseUpgradeWizardsService::class => [ static::class, 'getDatabaseUpgradeWizardsService' ],
             Service\SetupService::class => [ static::class, 'getSetupService' ],
             Service\SetupDatabaseService::class => [ static::class, 'getSetupDatabaseService' ],
             Middleware\Installer::class => [ static::class, 'getInstallerMiddleware' ],
@@ -190,9 +190,9 @@ class ServiceProvider extends AbstractServiceProvider
         return self::new($container, Service\WebServerConfigurationFileService::class);
     }
 
-    public static function getUpgradeWizardsService(ContainerInterface $container): Service\UpgradeWizardsService
+    public static function getDatabaseUpgradeWizardsService(ContainerInterface $container): Service\DatabaseUpgradeWizardsService
     {
-        return new Service\UpgradeWizardsService();
+        return new Service\DatabaseUpgradeWizardsService();
     }
 
     public static function getSetupService(ContainerInterface $container): Service\SetupService
@@ -309,7 +309,7 @@ class ServiceProvider extends AbstractServiceProvider
         return new Controller\UpgradeController(
             $container->get(PackageManager::class),
             $container->get(Service\LateBootService::class),
-            $container->get(Service\UpgradeWizardsService::class),
+            $container->get(Service\DatabaseUpgradeWizardsService::class),
             $container->get(FormProtectionFactory::class)
         );
     }
@@ -327,7 +327,7 @@ class ServiceProvider extends AbstractServiceProvider
         return new Command\UpgradeWizardRunCommand(
             'upgrade:run',
             $container->get(Service\LateBootService::class),
-            $container->get(Service\UpgradeWizardsService::class)
+            $container->get(Service\DatabaseUpgradeWizardsService::class)
         );
     }
 
@@ -336,7 +336,6 @@ class ServiceProvider extends AbstractServiceProvider
         return new Command\UpgradeWizardListCommand(
             'upgrade:list',
             $container->get(Service\LateBootService::class),
-            $container->get(Service\UpgradeWizardsService::class)
         );
     }
 
diff --git a/typo3/sysext/install/Classes/Updates/DatabaseUpdatedPrerequisite.php b/typo3/sysext/install/Classes/Updates/DatabaseUpdatedPrerequisite.php
index 142554e7b0bc..821ab93c07dd 100644
--- a/typo3/sysext/install/Classes/Updates/DatabaseUpdatedPrerequisite.php
+++ b/typo3/sysext/install/Classes/Updates/DatabaseUpdatedPrerequisite.php
@@ -18,7 +18,7 @@ declare(strict_types=1);
 namespace TYPO3\CMS\Install\Updates;
 
 use Symfony\Component\Console\Output\OutputInterface;
-use TYPO3\CMS\Install\Service\UpgradeWizardsService;
+use TYPO3\CMS\Install\Service\DatabaseUpgradeWizardsService;
 
 /**
  * Prerequisite for upgrade wizards to ensure the database is up-to-date
@@ -27,10 +27,8 @@ use TYPO3\CMS\Install\Service\UpgradeWizardsService;
  */
 class DatabaseUpdatedPrerequisite implements PrerequisiteInterface, ChattyInterface
 {
-    /**
-     * @var UpgradeWizardsService
-     */
-    protected $upgradeWizardsService;
+    protected DatabaseUpgradeWizardsService $databaseUpgradeWizardsService;
+
     /**
      * @var OutputInterface
      */
@@ -38,7 +36,7 @@ class DatabaseUpdatedPrerequisite implements PrerequisiteInterface, ChattyInterf
 
     public function __construct()
     {
-        $this->upgradeWizardsService = new UpgradeWizardsService();
+        $this->databaseUpgradeWizardsService = new DatabaseUpgradeWizardsService();
     }
 
     public function getTitle(): string
@@ -48,18 +46,18 @@ class DatabaseUpdatedPrerequisite implements PrerequisiteInterface, ChattyInterf
 
     public function ensure(): bool
     {
-        $adds = $this->upgradeWizardsService->getBlockingDatabaseAdds();
+        $adds = $this->databaseUpgradeWizardsService->getBlockingDatabaseAdds();
         $result = null;
         if (count($adds) > 0) {
             $this->output->writeln('Performing ' . count($adds) . ' database operations.');
-            $result = $this->upgradeWizardsService->addMissingTablesAndFields();
+            $result = $this->databaseUpgradeWizardsService->addMissingTablesAndFields();
         }
         return $result === null;
     }
 
     public function isFulfilled(): bool
     {
-        $adds = $this->upgradeWizardsService->getBlockingDatabaseAdds();
+        $adds = $this->databaseUpgradeWizardsService->getBlockingDatabaseAdds();
         return count($adds) === 0;
     }
 
diff --git a/typo3/sysext/install/Configuration/Services.yaml b/typo3/sysext/install/Configuration/Services.yaml
index 3993eda5ae09..f7c5103b8b99 100644
--- a/typo3/sysext/install/Configuration/Services.yaml
+++ b/typo3/sysext/install/Configuration/Services.yaml
@@ -32,3 +32,6 @@ services:
 
   TYPO3\CMS\Install\Updates\RowUpdater\SysRedirectRootPageMoveMigration:
     public: true
+
+  TYPO3\CMS\Install\Service\UpgradeWizardsService:
+    public: true
-- 
GitLab