From 3e6b817ab00f47b431bb99ff975dbb02aaae9a02 Mon Sep 17 00:00:00 2001
From: Christian Kuhn <lolli@schwarzbu.ch>
Date: Fri, 26 Jan 2024 12:53:30 +0100
Subject: [PATCH] [TASK] Move 'extension download' upgrade wizard to EM

The install tool has just a few dependencies to
ext:extensionmanager. Most notably, it ships the
AbstractDownloadExtensionUpdate upgrade wizard,
which is used when core extracts stuff to dedicated
extensions that are removed from monorepo.

The v12 upgrade wizard for 'fe_login_mode' uses this.

These upgrade wizards are tailored for non-composer-mode
only, just like the extensionmanager, which essentially
does nothing in composer mode.

To loosen the dependency from ext:install to
ext:extensionmanager, the patch moves the abstract, a
model class for this case, plus the fe_login_mode
implementation to ext:extensionmanager.

Class aliases are established, so a casual deprecation
is enough in this case. A few extensions rely on the
class, typically those that try to extend the upgrade
range of core by forward porting wizards older than
two major core versions. Those shoud continue to work
with v13, and will have to adapt the class namespace
of the abstract with v14 latest.

Moving the fe_login_mode wizard around does not make the
wizard show up again in case the wizard has been marked
'done' during v12 upgrade already, since usually the
according DB field does not exist anymore. We don't need
special handling for this case.

Resolves: #102943
Releases: main
Change-Id: Idb5e6c90900ffad7f9c3c383fff58a05c6728aa9
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/82659
Tested-by: Andreas Kienast <a.fernandez@scripting-base.de>
Tested-by: core-ci <typo3@b13.com>
Tested-by: Nikita Hovratov <nikita.h@live.de>
Reviewed-by: Andreas Kienast <a.fernandez@scripting-base.de>
Reviewed-by: Nikita Hovratov <nikita.h@live.de>
---
 composer.json                                 |  3 +-
 composer.lock                                 |  4 +-
 ...ensionUpdateMovedToExtextensionmanager.rst | 50 ++++++++++++++
 .../AbstractDownloadExtensionUpdate.php       | 65 ++++++++++++-------
 .../Classes/Updates/ExtensionModel.php        | 13 ++--
 .../Updates/FeLoginModeExtractionUpdate.php   | 33 ++++------
 .../Migrations/Code/ClassAliasMap.php         | 21 ++++++
 .../Migrations/Code/LegacyClassesForIde.php   | 32 +++++++++
 .../FeLoginModeExtractionUpdateTest.php       |  8 +--
 .../Updates/Fixtures/FeLoginModeNotUsed.csv   |  0
 .../Updates/Fixtures/FeLoginModeUsed.csv      |  0
 typo3/sysext/extensionmanager/composer.json   |  5 ++
 .../ExtensionScanner/Php/ClassNameMatcher.php | 10 +++
 13 files changed, 186 insertions(+), 58 deletions(-)
 create mode 100644 typo3/sysext/core/Documentation/Changelog/13.0/Deprecation-102943-AbstractDownloadExtensionUpdateMovedToExtextensionmanager.rst
 rename typo3/sysext/{install => extensionmanager}/Classes/Updates/AbstractDownloadExtensionUpdate.php (66%)
 rename typo3/sysext/{install => extensionmanager}/Classes/Updates/ExtensionModel.php (77%)
 rename typo3/sysext/{install => extensionmanager}/Classes/Updates/FeLoginModeExtractionUpdate.php (86%)
 create mode 100644 typo3/sysext/extensionmanager/Migrations/Code/ClassAliasMap.php
 create mode 100644 typo3/sysext/extensionmanager/Migrations/Code/LegacyClassesForIde.php
 rename typo3/sysext/{install => extensionmanager}/Tests/Functional/Updates/FeLoginModeExtractionUpdateTest.php (88%)
 rename typo3/sysext/{install => extensionmanager}/Tests/Functional/Updates/Fixtures/FeLoginModeNotUsed.csv (100%)
 rename typo3/sysext/{install => extensionmanager}/Tests/Functional/Updates/Fixtures/FeLoginModeUsed.csv (100%)

diff --git a/composer.json b/composer.json
index 00e5e1f25f2f..707ceb13b3d2 100644
--- a/composer.json
+++ b/composer.json
@@ -137,7 +137,8 @@
 	"extra": {
 		"typo3/class-alias-loader": {
 			"class-alias-maps": [
-				"typo3/sysext/backend/Migrations/Code/ClassAliasMap.php"
+				"typo3/sysext/backend/Migrations/Code/ClassAliasMap.php",
+				"typo3/sysext/extensionmanager/Migrations/Code/ClassAliasMap.php"
 			],
 			"always-add-alias-loader": true
 		},
diff --git a/composer.lock b/composer.lock
index a51586ce9456..5f24fbc5b000 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "a574a9d6f86bc9c30da3d9af9eeffe33",
+    "content-hash": "d2f4c33a42ca5c2a983a60aa53c2c8fb",
     "packages": [
         {
             "name": "bacon/bacon-qr-code",
@@ -272,7 +272,7 @@
                 "phpstan/phpstan": "1.10.56",
                 "phpstan/phpstan-phpunit": "1.3.15",
                 "phpstan/phpstan-strict-rules": "^1.5",
-                "phpunit/phpunit": "10.4.2",
+                "phpunit/phpunit": "10.5.9",
                 "psalm/plugin-phpunit": "0.18.4",
                 "slevomat/coding-standard": "8.13.1",
                 "squizlabs/php_codesniffer": "3.8.1",
diff --git a/typo3/sysext/core/Documentation/Changelog/13.0/Deprecation-102943-AbstractDownloadExtensionUpdateMovedToExtextensionmanager.rst b/typo3/sysext/core/Documentation/Changelog/13.0/Deprecation-102943-AbstractDownloadExtensionUpdateMovedToExtextensionmanager.rst
new file mode 100644
index 000000000000..259e1da95d05
--- /dev/null
+++ b/typo3/sysext/core/Documentation/Changelog/13.0/Deprecation-102943-AbstractDownloadExtensionUpdateMovedToExtextensionmanager.rst
@@ -0,0 +1,50 @@
+.. include:: /Includes.rst.txt
+
+.. _deprecation-102943-1706271208:
+
+====================================================================================
+Deprecation: #102943 - AbstractDownloadExtensionUpdate moved to ext:extensionmanager
+====================================================================================
+
+See :issue:`102943`
+
+Description
+===========
+
+The following upgrade wizard related classes have been moved from EXT:install
+to EXT:extensionmanager:
+
+* :php:`TYPO3\CMS\Install\Updates\AbstractDownloadExtensionUpdate`, new name
+  :php:`TYPO3\CMS\Extensionmanager\Updates\AbstractDownloadExtensionUpdate`
+* :php:`TYPO3\CMS\Install\Updates\ExtensionModel`, new name
+  :php:`TYPO3\CMS\Extensionmanager\Updates\ExtensionModel`
+
+Class aliases have been established for TYPO3 v13, which will be removed with
+TYPO3 v14.
+
+Impact
+======
+
+Extensions that extend :php:`AbstractDownloadExtensionUpdate` and
+then most likely use :php:`ExtensionModel` as well, should update the namespace.
+
+
+Affected installations
+======================
+
+Few instances should be affected: There are a couple of extensions that try to
+extend the upgrade range from two major core versions, and ship older
+upgrade wizards. Apart from that, the abstract is most likely rarely used.
+Consuming extensions should adapt the namespace, the old class names will stop
+working with TYPO3 v14.
+
+The extension scanner will find usages as strong match.
+
+
+Migration
+=========
+
+Adapt the namespaces in extension classes that extend :php:`AbstractDownloadExtensionUpdate`
+from :php:`Install` to :php:`Extensionmanager`.
+
+.. index:: PHP-API, FullyScanned, ext:extensionmanager
diff --git a/typo3/sysext/install/Classes/Updates/AbstractDownloadExtensionUpdate.php b/typo3/sysext/extensionmanager/Classes/Updates/AbstractDownloadExtensionUpdate.php
similarity index 66%
rename from typo3/sysext/install/Classes/Updates/AbstractDownloadExtensionUpdate.php
rename to typo3/sysext/extensionmanager/Classes/Updates/AbstractDownloadExtensionUpdate.php
index 5620671ec444..a61517fb1d84 100644
--- a/typo3/sysext/install/Classes/Updates/AbstractDownloadExtensionUpdate.php
+++ b/typo3/sysext/extensionmanager/Classes/Updates/AbstractDownloadExtensionUpdate.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 /*
  * This file is part of the TYPO3 CMS project.
  *
@@ -13,32 +15,53 @@
  * The TYPO3 project - inspiring people to share!
  */
 
-namespace TYPO3\CMS\Install\Updates;
+namespace TYPO3\CMS\Extensionmanager\Updates;
 
 use Symfony\Component\Console\Output\OutputInterface;
 use TYPO3\CMS\Core\Core\Environment;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException;
 use TYPO3\CMS\Extensionmanager\Remote\DownloadFailedException;
 use TYPO3\CMS\Extensionmanager\Remote\RemoteRegistry;
 use TYPO3\CMS\Extensionmanager\Remote\VerificationFailedException;
 use TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility;
 use TYPO3\CMS\Extensionmanager\Utility\InstallUtility;
 use TYPO3\CMS\Extensionmanager\Utility\ListUtility;
+use TYPO3\CMS\Install\Updates\ChattyInterface;
+use TYPO3\CMS\Install\Updates\ConfirmableInterface;
+use TYPO3\CMS\Install\Updates\UpgradeWizardInterface;
 
 /**
  * Download extension from TER
  */
 abstract class AbstractDownloadExtensionUpdate implements UpgradeWizardInterface, ConfirmableInterface, ChattyInterface
 {
-    /**
-     * @var OutputInterface
-     */
-    protected $output;
+    protected OutputInterface $output;
+    protected ExtensionModel $extension;
 
-    /**
-     * @var \TYPO3\CMS\Install\Updates\ExtensionModel
-     */
-    protected $extension;
+    protected FileHandlingUtility $fileHandlingUtility;
+    protected ListUtility $listUtility;
+    protected InstallUtility $installUtility;
+    protected RemoteRegistry $remoteRegistry;
+
+    public function injectFileHandlingUtility(FileHandlingUtility $fileHandlingUtility): void
+    {
+        $this->fileHandlingUtility = $fileHandlingUtility;
+    }
+
+    public function injectListUtility(ListUtility $listUtility): void
+    {
+        $this->listUtility = $listUtility;
+    }
+
+    public function injectInstallUtility(InstallUtility $installUtility): void
+    {
+        $this->installUtility = $installUtility;
+    }
+
+    public function injectRemoteRegistry(RemoteRegistry $remoteRegistry): void
+    {
+        $this->remoteRegistry = $remoteRegistry;
+    }
 
     public function setOutput(OutputInterface $output): void
     {
@@ -59,30 +82,27 @@ abstract class AbstractDownloadExtensionUpdate implements UpgradeWizardInterface
      * (e.g. installing in extList, respecting priority, etc.)
      *
      * @return bool whether the installation worked or not
-     * @throws \TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException
+     * @throws ExtensionManagerException
      */
     protected function installExtension(ExtensionModel $extension): bool
     {
         $updateSuccessful = true;
 
-        $extensionListUtility = GeneralUtility::makeInstance(ListUtility::class);
-        $availableExtensions = $extensionListUtility->getAvailableExtensions();
+        $availableExtensions = $this->listUtility->getAvailableExtensions();
 
         $extensionKey = $extension->getKey();
         $isExtensionAvailable = !empty($availableExtensions[$extensionKey]);
         $isComposerMode = Environment::isComposerMode();
 
         if (!$isComposerMode && !$isExtensionAvailable) {
-            $extensionFileHandlingUtility = GeneralUtility::makeInstance(FileHandlingUtility::class);
-            $remoteRegistry = GeneralUtility::makeInstance(RemoteRegistry::class);
-            if ($remoteRegistry->hasDefaultRemote()) {
-                $terRemote = $remoteRegistry->getDefaultRemote();
+            if ($this->remoteRegistry->hasDefaultRemote()) {
+                $terRemote = $this->remoteRegistry->getDefaultRemote();
                 try {
-                    $terRemote->downloadExtension($extensionKey, $extension->getVersionString(), $extensionFileHandlingUtility);
-                } catch (DownloadFailedException $e) {
+                    $terRemote->downloadExtension($extensionKey, $extension->getVersionString(), $this->fileHandlingUtility);
+                } catch (DownloadFailedException) {
                     $updateSuccessful = false;
                     $this->output->writeln('<error>The extension ' . $extensionKey . ' could not be downloaded.</error>');
-                } catch (VerificationFailedException $e) {
+                } catch (VerificationFailedException) {
                     $updateSuccessful = false;
                     $this->output->writeln('<error>The extension ' . $extensionKey . ' could not be extracted.</error>');
                 }
@@ -93,7 +113,7 @@ abstract class AbstractDownloadExtensionUpdate implements UpgradeWizardInterface
                 );
             }
             // The listUtility now needs to have the regenerated list of packages
-            $extensionListUtility->reloadAvailableExtensions();
+            $this->listUtility->reloadAvailableExtensions();
         }
 
         if ($isComposerMode && !$isExtensionAvailable) {
@@ -107,8 +127,7 @@ abstract class AbstractDownloadExtensionUpdate implements UpgradeWizardInterface
         }
 
         if ($updateSuccessful) {
-            $extensionInstallUtility = GeneralUtility::makeInstance(InstallUtility::class);
-            $extensionInstallUtility->install($extensionKey);
+            $this->installUtility->install($extensionKey);
         }
 
         return $updateSuccessful;
diff --git a/typo3/sysext/install/Classes/Updates/ExtensionModel.php b/typo3/sysext/extensionmanager/Classes/Updates/ExtensionModel.php
similarity index 77%
rename from typo3/sysext/install/Classes/Updates/ExtensionModel.php
rename to typo3/sysext/extensionmanager/Classes/Updates/ExtensionModel.php
index 4149ccdce77a..3501f730120a 100644
--- a/typo3/sysext/install/Classes/Updates/ExtensionModel.php
+++ b/typo3/sysext/extensionmanager/Classes/Updates/ExtensionModel.php
@@ -15,21 +15,22 @@ declare(strict_types=1);
  * The TYPO3 project - inspiring people to share!
  */
 
-namespace TYPO3\CMS\Install\Updates;
+namespace TYPO3\CMS\Extensionmanager\Updates;
 
 /**
  * Model for extensions installed by upgrade wizards
  *
  * @internal
+ * @todo: Declare 'final readonly' in v14 when ext:install class alias is gone.
  */
 class ExtensionModel
 {
     public function __construct(
-        protected readonly string $key,
-        protected readonly string $title,
-        protected readonly string $versionString,
-        protected readonly string $composerName,
-        protected readonly string $description
+        protected string $key,
+        protected string $title,
+        protected string $versionString,
+        protected string $composerName,
+        protected string $description
     ) {}
 
     public function getDescription(): string
diff --git a/typo3/sysext/install/Classes/Updates/FeLoginModeExtractionUpdate.php b/typo3/sysext/extensionmanager/Classes/Updates/FeLoginModeExtractionUpdate.php
similarity index 86%
rename from typo3/sysext/install/Classes/Updates/FeLoginModeExtractionUpdate.php
rename to typo3/sysext/extensionmanager/Classes/Updates/FeLoginModeExtractionUpdate.php
index 8e54afe2ff3e..f4fd318c1cc7 100644
--- a/typo3/sysext/install/Classes/Updates/FeLoginModeExtractionUpdate.php
+++ b/typo3/sysext/extensionmanager/Classes/Updates/FeLoginModeExtractionUpdate.php
@@ -15,12 +15,12 @@ declare(strict_types=1);
  * The TYPO3 project - inspiring people to share!
  */
 
-namespace TYPO3\CMS\Install\Updates;
+namespace TYPO3\CMS\Extensionmanager\Updates;
 
 use TYPO3\CMS\Core\Database\ConnectionPool;
 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Install\Attribute\UpgradeWizard;
+use TYPO3\CMS\Install\Updates\Confirmation;
 
 /**
  * Installs and downloads EXT:fe_login_mode
@@ -29,14 +29,12 @@ use TYPO3\CMS\Install\Attribute\UpgradeWizard;
  * @internal This class is only meant to be used within EXT:install and is not part of the TYPO3 Core API.
  */
 #[UpgradeWizard('feLoginModeExtension')]
-class FeLoginModeExtractionUpdate extends AbstractDownloadExtensionUpdate
+final class FeLoginModeExtractionUpdate extends AbstractDownloadExtensionUpdate
 {
     private const TABLE_NAME = 'pages';
     private const FIELD_NAME = 'fe_login_mode';
 
-    protected Confirmation $confirmation;
-
-    public function __construct()
+    public function __construct(private readonly ConnectionPool $connectionPool)
     {
         $this->extension = new ExtensionModel(
             'fe_login_mode',
@@ -45,12 +43,6 @@ class FeLoginModeExtractionUpdate extends AbstractDownloadExtensionUpdate
             'o-ba/fe-login-mode',
             'This extension provides the frontend user login mode functionality, used in previous TYPO3 versions to reduce the amount of cache variants for complex user and group setups.'
         );
-
-        $this->confirmation = new Confirmation(
-            'Are you sure?',
-            'You should install EXT:fe_login_mode only if you really need it. ' . $this->extension->getDescription(),
-            false
-        );
     }
 
     /**
@@ -58,7 +50,11 @@ class FeLoginModeExtractionUpdate extends AbstractDownloadExtensionUpdate
      */
     public function getConfirmation(): Confirmation
     {
-        return $this->confirmation;
+        return new Confirmation(
+            'Are you sure?',
+            'You should install EXT:fe_login_mode only if you really need it. ' . $this->extension->getDescription(),
+            false
+        );
     }
 
     /**
@@ -106,11 +102,10 @@ class FeLoginModeExtractionUpdate extends AbstractDownloadExtensionUpdate
      */
     protected function columnExists(): bool
     {
-        $tableColumns = $this->getConnectionPool()
+        $tableColumns = $this->connectionPool
             ->getConnectionForTable(self::TABLE_NAME)
             ->createSchemaManager()
             ->listTableColumns(self::TABLE_NAME);
-
         return isset($tableColumns[self::FIELD_NAME]);
     }
 
@@ -120,8 +115,7 @@ class FeLoginModeExtractionUpdate extends AbstractDownloadExtensionUpdate
      */
     protected function functionalityUsed(): bool
     {
-        $queryBuilder = $this->getConnectionPool()->getQueryBuilderForTable(self::TABLE_NAME);
-
+        $queryBuilder = $this->connectionPool->getQueryBuilderForTable(self::TABLE_NAME);
         return (bool)$queryBuilder
             ->count(self::FIELD_NAME)
             ->from(self::TABLE_NAME)
@@ -129,9 +123,4 @@ class FeLoginModeExtractionUpdate extends AbstractDownloadExtensionUpdate
             ->executeQuery()
             ->fetchOne();
     }
-
-    protected function getConnectionPool(): ConnectionPool
-    {
-        return GeneralUtility::makeInstance(ConnectionPool::class);
-    }
 }
diff --git a/typo3/sysext/extensionmanager/Migrations/Code/ClassAliasMap.php b/typo3/sysext/extensionmanager/Migrations/Code/ClassAliasMap.php
new file mode 100644
index 000000000000..930ba01c9f72
--- /dev/null
+++ b/typo3/sysext/extensionmanager/Migrations/Code/ClassAliasMap.php
@@ -0,0 +1,21 @@
+<?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!
+ */
+
+return [
+    'TYPO3\\CMS\\Install\\Updates\\AbstractDownloadExtensionUpdate' => \TYPO3\CMS\Extensionmanager\Updates\AbstractDownloadExtensionUpdate::class,
+    'TYPO3\\CMS\\Install\\Updates\\ExtensionModel' => \TYPO3\CMS\Extensionmanager\Updates\ExtensionModel::class,
+];
diff --git a/typo3/sysext/extensionmanager/Migrations/Code/LegacyClassesForIde.php b/typo3/sysext/extensionmanager/Migrations/Code/LegacyClassesForIde.php
new file mode 100644
index 000000000000..203288b9ec31
--- /dev/null
+++ b/typo3/sysext/extensionmanager/Migrations/Code/LegacyClassesForIde.php
@@ -0,0 +1,32 @@
+<?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 {
+    die('Access denied');
+}
+
+namespace TYPO3\CMS\Install\Updates {
+    /**
+     * @deprecated since TYPO3 v13, will be removed in TYPO3 v14
+     */
+    abstract class AbstractDownloadExtensionUpdate extends \TYPO3\CMS\Extensionmanager\Updates\AbstractDownloadExtensionUpdate {}
+
+    /**
+     * @deprecated since TYPO3 v13, will be removed in TYPO3 v14
+     */
+    class ExtensionModel extends \TYPO3\CMS\Extensionmanager\Updates\ExtensionModel {}
+}
diff --git a/typo3/sysext/install/Tests/Functional/Updates/FeLoginModeExtractionUpdateTest.php b/typo3/sysext/extensionmanager/Tests/Functional/Updates/FeLoginModeExtractionUpdateTest.php
similarity index 88%
rename from typo3/sysext/install/Tests/Functional/Updates/FeLoginModeExtractionUpdateTest.php
rename to typo3/sysext/extensionmanager/Tests/Functional/Updates/FeLoginModeExtractionUpdateTest.php
index da2e321b4a18..907b6eeb0ab2 100644
--- a/typo3/sysext/install/Tests/Functional/Updates/FeLoginModeExtractionUpdateTest.php
+++ b/typo3/sysext/extensionmanager/Tests/Functional/Updates/FeLoginModeExtractionUpdateTest.php
@@ -15,14 +15,14 @@ declare(strict_types=1);
  * The TYPO3 project - inspiring people to share!
  */
 
-namespace TYPO3\CMS\Install\Tests\Functional\Updates;
+namespace TYPO3\CMS\Extensionmanager\Tests\Functional\Updates;
 
 use Doctrine\DBAL\Schema\Column;
 use Doctrine\DBAL\Types\IntegerType;
 use TYPO3\CMS\Core\Database\ConnectionPool;
 use TYPO3\CMS\Core\Database\Schema\TableDiff;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3\CMS\Install\Updates\FeLoginModeExtractionUpdate;
+use TYPO3\CMS\Extensionmanager\Updates\FeLoginModeExtractionUpdate;
 use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase;
 
 final class FeLoginModeExtractionUpdateTest extends FunctionalTestCase
@@ -33,7 +33,7 @@ final class FeLoginModeExtractionUpdateTest extends FunctionalTestCase
     public function columnDoesNotExistTest(): void
     {
         // "updateNecessary" will return FALSE since the "fe_login_mode" column is no longer defined by TYPO3
-        self::assertFalse((new FeLoginModeExtractionUpdate())->updateNecessary());
+        self::assertFalse((new FeLoginModeExtractionUpdate($this->get(ConnectionPool::class)))->updateNecessary());
     }
 
     /**
@@ -67,7 +67,7 @@ final class FeLoginModeExtractionUpdateTest extends FunctionalTestCase
         }
 
         $this->importCSVDataSet(__DIR__ . '/Fixtures/' . $csvDataSet . '.csv');
-        self::assertEquals($updateNecessary, (new FeLoginModeExtractionUpdate())->updateNecessary());
+        self::assertEquals($updateNecessary, (new FeLoginModeExtractionUpdate($this->get(ConnectionPool::class)))->updateNecessary());
     }
 
     public static function functionalityUsedTestDataProvider(): \Generator
diff --git a/typo3/sysext/install/Tests/Functional/Updates/Fixtures/FeLoginModeNotUsed.csv b/typo3/sysext/extensionmanager/Tests/Functional/Updates/Fixtures/FeLoginModeNotUsed.csv
similarity index 100%
rename from typo3/sysext/install/Tests/Functional/Updates/Fixtures/FeLoginModeNotUsed.csv
rename to typo3/sysext/extensionmanager/Tests/Functional/Updates/Fixtures/FeLoginModeNotUsed.csv
diff --git a/typo3/sysext/install/Tests/Functional/Updates/Fixtures/FeLoginModeUsed.csv b/typo3/sysext/extensionmanager/Tests/Functional/Updates/Fixtures/FeLoginModeUsed.csv
similarity index 100%
rename from typo3/sysext/install/Tests/Functional/Updates/Fixtures/FeLoginModeUsed.csv
rename to typo3/sysext/extensionmanager/Tests/Functional/Updates/Fixtures/FeLoginModeUsed.csv
diff --git a/typo3/sysext/extensionmanager/composer.json b/typo3/sysext/extensionmanager/composer.json
index 2fae30717c5d..30c1e6940974 100644
--- a/typo3/sysext/extensionmanager/composer.json
+++ b/typo3/sysext/extensionmanager/composer.json
@@ -36,6 +36,11 @@
 				"partOfMinimalUsableSystem": true
 			},
 			"extension-key": "extensionmanager"
+		},
+		"typo3/class-alias-loader": {
+			"class-alias-maps": [
+				"Migrations/Code/ClassAliasMap.php"
+			]
 		}
 	},
 	"autoload": {
diff --git a/typo3/sysext/install/Configuration/ExtensionScanner/Php/ClassNameMatcher.php b/typo3/sysext/install/Configuration/ExtensionScanner/Php/ClassNameMatcher.php
index 7880a3f38182..844956144153 100644
--- a/typo3/sysext/install/Configuration/ExtensionScanner/Php/ClassNameMatcher.php
+++ b/typo3/sysext/install/Configuration/ExtensionScanner/Php/ClassNameMatcher.php
@@ -2478,4 +2478,14 @@ return [
             'Breaking-102900-MetaphoneSearchRemovedFromIndexed_search.rst',
         ],
     ],
+    'TYPO3\CMS\Install\Updates\AbstractDownloadExtensionUpdate' => [
+        'restFiles' => [
+            'Deprecation-102943-AbstractDownloadExtensionUpdateMovedToExtextensionmanager.rst',
+        ],
+    ],
+    'TYPO3\CMS\Install\Updates\ExtensionModel' => [
+        'restFiles' => [
+            'Deprecation-102943-AbstractDownloadExtensionUpdateMovedToExtextensionmanager.rst',
+        ],
+    ],
 ];
-- 
GitLab