From f1bf354cfc9dd973cc7c658be40c0dddab7b9b3d Mon Sep 17 00:00:00 2001
From: Benjamin Franzke <bfr@qbus.de>
Date: Fri, 19 Jul 2019 06:47:46 +0200
Subject: [PATCH] [TASK] Use dependency injection in middlewares
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Use constructor injection for middleware dependencies, moving away
from GeneralUtility::makeInstance based Singleton lookup.
Dependencies which are already configured to be optionally
injectable via constructor arguments (e.g. for unit tests) are
changed to be required constructor arguments. Since the introduction of
symfony dependency injection the fallback to GeneralUtility::makeInstance
is no longer used – therefore it is dropped.

Releases: master
Resolves: #88800
Change-Id: I6dbec2f91fc78c1b06dd179323fb7a4810c13baa
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/61322
Tested-by: TYPO3com <noreply@typo3.com>
Tested-by: Susanne Moog <look@susi.dev>
Tested-by: Daniel Goerz <daniel.goerz@posteo.de>
Reviewed-by: Susanne Moog <look@susi.dev>
Reviewed-by: Daniel Goerz <daniel.goerz@posteo.de>
---
 .../Classes/Middleware/SqlLogging.php         | 12 +++++-
 .../Middleware/BackendUserAuthenticator.php   | 19 ++++++---
 .../Classes/Middleware/SiteResolver.php       | 13 ++++++-
 .../Unit/Middleware/SiteResolverTest.php      |  4 +-
 typo3/sysext/core/Classes/ServiceProvider.php |  6 +++
 .../core/Classes/TimeTracker/TimeTracker.php  |  8 ++++
 .../Middleware/BackendUserAuthenticator.php   | 19 ++++++---
 .../Middleware/FrontendUserAuthenticator.php  | 17 ++++++--
 .../Middleware/PageArgumentValidator.php      | 26 ++++++-------
 .../PrepareTypoScriptFrontendRendering.php    |  7 ++--
 .../ShortcutAndMountPointRedirect.php         |  4 +-
 .../Classes/Middleware/SiteResolver.php       |  9 +----
 .../Middleware/StaticRouteResolver.php        | 25 +++++++++---
 .../Middleware/TimeTrackerInitialization.php  | 26 ++++++++-----
 .../TypoScriptFrontendInitialization.php      | 24 ++++++++----
 .../Middleware/PageArgumentValidatorTest.php  | 26 ++++++-------
 .../Classes/Middleware/Maintenance.php        | 39 +++++++++++--------
 .../install/Classes/ServiceProvider.php       |  3 ++
 18 files changed, 189 insertions(+), 98 deletions(-)

diff --git a/typo3/sysext/adminpanel/Classes/Middleware/SqlLogging.php b/typo3/sysext/adminpanel/Classes/Middleware/SqlLogging.php
index f2909f0870c9..a80bffb53b50 100644
--- a/typo3/sysext/adminpanel/Classes/Middleware/SqlLogging.php
+++ b/typo3/sysext/adminpanel/Classes/Middleware/SqlLogging.php
@@ -32,6 +32,15 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
  */
 class SqlLogging implements MiddlewareInterface
 {
+    /**
+     * @var ConnectionPool
+     */
+    protected $connectionPool;
+
+    public function __construct(ConnectionPool $connectionPool)
+    {
+        $this->connectionPool = $connectionPool;
+    }
 
     /**
      * Enable SQL Logging as early as possible to catch all queries if the admin panel is active
@@ -42,8 +51,7 @@ class SqlLogging implements MiddlewareInterface
     public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
     {
         if (StateUtility::isActivatedForUser() && StateUtility::isOpen()) {
-            $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
-            $connection = $connectionPool->getConnectionByName(ConnectionPool::DEFAULT_CONNECTION_NAME);
+            $connection = $this->connectionPool->getConnectionByName(ConnectionPool::DEFAULT_CONNECTION_NAME);
             $connection->getConfiguration()->setSQLLogger(GeneralUtility::makeInstance(DoctrineSqlLogger::class));
         }
         return $handler->handle($request);
diff --git a/typo3/sysext/backend/Classes/Middleware/BackendUserAuthenticator.php b/typo3/sysext/backend/Classes/Middleware/BackendUserAuthenticator.php
index 685e604e9273..754109429d94 100644
--- a/typo3/sysext/backend/Classes/Middleware/BackendUserAuthenticator.php
+++ b/typo3/sysext/backend/Classes/Middleware/BackendUserAuthenticator.php
@@ -49,6 +49,16 @@ class BackendUserAuthenticator implements MiddlewareInterface
         '/ajax/core/requirejs',
     ];
 
+    /**
+     * @var Context
+     */
+    protected $context;
+
+    public function __construct(Context $context)
+    {
+        $this->context = $context;
+    }
+
     /**
      * Calls the bootstrap process to set up $GLOBALS['BE_USER'] AND $GLOBALS['LANG']
      *
@@ -65,7 +75,7 @@ class BackendUserAuthenticator implements MiddlewareInterface
         Bootstrap::initializeBackendAuthentication($this->isLoggedInBackendUserRequired($pathToRoute));
         Bootstrap::initializeLanguageObject();
         // Register the backend user as aspect
-        $this->setBackendUserAspect(GeneralUtility::makeInstance(Context::class), $GLOBALS['BE_USER']);
+        $this->setBackendUserAspect($GLOBALS['BE_USER']);
 
         return $handler->handle($request);
     }
@@ -85,12 +95,11 @@ class BackendUserAuthenticator implements MiddlewareInterface
     /**
      * Register the backend user as aspect
      *
-     * @param Context $context
      * @param BackendUserAuthentication $user
      */
-    protected function setBackendUserAspect(Context $context, BackendUserAuthentication $user)
+    protected function setBackendUserAspect(BackendUserAuthentication $user)
     {
-        $context->setAspect('backend.user', GeneralUtility::makeInstance(UserAspect::class, $user));
-        $context->setAspect('workspace', GeneralUtility::makeInstance(WorkspaceAspect::class, $user->workspace));
+        $this->context->setAspect('backend.user', GeneralUtility::makeInstance(UserAspect::class, $user));
+        $this->context->setAspect('workspace', GeneralUtility::makeInstance(WorkspaceAspect::class, $user->workspace));
     }
 }
diff --git a/typo3/sysext/backend/Classes/Middleware/SiteResolver.php b/typo3/sysext/backend/Classes/Middleware/SiteResolver.php
index 9d601f9b2ec5..a062db118538 100644
--- a/typo3/sysext/backend/Classes/Middleware/SiteResolver.php
+++ b/typo3/sysext/backend/Classes/Middleware/SiteResolver.php
@@ -21,7 +21,6 @@ use Psr\Http\Server\MiddlewareInterface;
 use Psr\Http\Server\RequestHandlerInterface;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Core\Routing\SiteMatcher;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Utility\MathUtility;
 
 /**
@@ -34,6 +33,16 @@ use TYPO3\CMS\Core\Utility\MathUtility;
  */
 class SiteResolver implements MiddlewareInterface
 {
+    /**
+     * @var SiteMatcher
+     */
+    protected $siteMatcher;
+
+    public function __construct(SiteMatcher $siteMatcher)
+    {
+        $this->siteMatcher = $siteMatcher;
+    }
+
     /**
      * Resolve the site information by checking the page ID ("id" parameter) which is typically used in BE modules
      * of type "web".
@@ -52,7 +61,7 @@ class SiteResolver implements MiddlewareInterface
             if ($pageId > 0) {
                 $rootLine = BackendUtility::BEgetRootLine($pageId);
             }
-            $site = GeneralUtility::makeInstance(SiteMatcher::class)->matchByPageId($pageId, $rootLine);
+            $site = $this->siteMatcher->matchByPageId($pageId, $rootLine);
             $request = $request->withAttribute('site', $site);
         }
         return $handler->handle($request);
diff --git a/typo3/sysext/backend/Tests/Unit/Middleware/SiteResolverTest.php b/typo3/sysext/backend/Tests/Unit/Middleware/SiteResolverTest.php
index 5aa5347a0f1d..f3d09eed9d71 100644
--- a/typo3/sysext/backend/Tests/Unit/Middleware/SiteResolverTest.php
+++ b/typo3/sysext/backend/Tests/Unit/Middleware/SiteResolverTest.php
@@ -22,6 +22,7 @@ use Psr\Http\Server\RequestHandlerInterface;
 use TYPO3\CMS\Backend\Middleware\SiteResolver;
 use TYPO3\CMS\Core\Http\JsonResponse;
 use TYPO3\CMS\Core\Http\ServerRequest;
+use TYPO3\CMS\Core\Routing\SiteMatcher;
 use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
 
 class SiteResolverTest extends UnitTestCase
@@ -34,7 +35,8 @@ class SiteResolverTest extends UnitTestCase
     {
         $incomingUrl = 'http://localhost:8080/typo3/index.php?route=/file/FilelistList/&token=d7d864db2b26c1d0f0537718b16890f336f4af2b&id=9831:/styleguide/';
 
-        $subject = new SiteResolver();
+        $siteMatcherProphecy = $this->prophesize(SiteMatcher::class);
+        $subject = new SiteResolver($siteMatcherProphecy->reveal());
 
         $incomingRequest = new ServerRequest($incomingUrl, 'GET');
         $incomingRequest = $incomingRequest->withQueryParams(['id' => '9831:/styleguide/']);
diff --git a/typo3/sysext/core/Classes/ServiceProvider.php b/typo3/sysext/core/Classes/ServiceProvider.php
index 24a4d70a011c..ccea16aba622 100644
--- a/typo3/sysext/core/Classes/ServiceProvider.php
+++ b/typo3/sysext/core/Classes/ServiceProvider.php
@@ -38,6 +38,7 @@ class ServiceProvider extends AbstractServiceProvider
             EventDispatcher\ListenerProvider::class => [ static::class, 'getEventListenerProvider' ],
             Http\MiddlewareStackResolver::class => [ static::class, 'getMiddlewareStackResolver' ],
             Service\DependencyOrderingService::class => [ static::class, 'getDependencyOrderingService' ],
+            Crypto\PasswordHashing\PasswordHashFactory::class => [ static::class, 'getPasswordHashFactory' ],
             'middlewares' => [ static::class, 'getMiddlewares' ],
         ];
     }
@@ -91,6 +92,11 @@ class ServiceProvider extends AbstractServiceProvider
         return new Context\Context;
     }
 
+    public static function getPasswordHashFactory(ContainerInterface $container): Crypto\PasswordHashing\PasswordHashFactory
+    {
+        return new Crypto\PasswordHashing\PasswordHashFactory;
+    }
+
     public static function getMiddlewareStackResolver(ContainerInterface $container): Http\MiddlewareStackResolver
     {
         return new Http\MiddlewareStackResolver(
diff --git a/typo3/sysext/core/Classes/TimeTracker/TimeTracker.php b/typo3/sysext/core/Classes/TimeTracker/TimeTracker.php
index a5d0bd609d58..c2b989aef379 100644
--- a/typo3/sysext/core/Classes/TimeTracker/TimeTracker.php
+++ b/typo3/sysext/core/Classes/TimeTracker/TimeTracker.php
@@ -147,6 +147,14 @@ class TimeTracker implements SingletonInterface
         $this->isEnabled = $isEnabled;
     }
 
+    /**
+     * @param bool $isEnabled
+     */
+    public function setEnabled(bool $isEnabled = true)
+    {
+        $this->isEnabled = $isEnabled;
+    }
+
     /**
      * Sets the starting time
      *
diff --git a/typo3/sysext/frontend/Classes/Middleware/BackendUserAuthenticator.php b/typo3/sysext/frontend/Classes/Middleware/BackendUserAuthenticator.php
index b9b1fdf2082d..6f10a852a062 100644
--- a/typo3/sysext/frontend/Classes/Middleware/BackendUserAuthenticator.php
+++ b/typo3/sysext/frontend/Classes/Middleware/BackendUserAuthenticator.php
@@ -39,6 +39,16 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
  */
 class BackendUserAuthenticator implements MiddlewareInterface
 {
+    /**
+     * @var Context
+     */
+    protected $context;
+
+    public function __construct(Context $context)
+    {
+        $this->context = $context;
+    }
+
     /**
      * Creates a backend user authentication object, tries to authenticate a user
      *
@@ -63,7 +73,7 @@ class BackendUserAuthenticator implements MiddlewareInterface
             Bootstrap::initializeLanguageObject();
             Bootstrap::initializeBackendRouter();
             Bootstrap::loadExtTables();
-            $this->setBackendUserAspect(GeneralUtility::makeInstance(Context::class), $GLOBALS['BE_USER']);
+            $this->setBackendUserAspect($GLOBALS['BE_USER']);
         }
 
         return $handler->handle($request);
@@ -116,12 +126,11 @@ class BackendUserAuthenticator implements MiddlewareInterface
     /**
      * Register the backend user as aspect
      *
-     * @param Context $context
      * @param BackendUserAuthentication|null $user
      */
-    protected function setBackendUserAspect(Context $context, BackendUserAuthentication $user)
+    protected function setBackendUserAspect(BackendUserAuthentication $user)
     {
-        $context->setAspect('backend.user', GeneralUtility::makeInstance(UserAspect::class, $user));
-        $context->setAspect('workspace', GeneralUtility::makeInstance(WorkspaceAspect::class, $user->workspace));
+        $this->context->setAspect('backend.user', GeneralUtility::makeInstance(UserAspect::class, $user));
+        $this->context->setAspect('workspace', GeneralUtility::makeInstance(WorkspaceAspect::class, $user->workspace));
     }
 }
diff --git a/typo3/sysext/frontend/Classes/Middleware/FrontendUserAuthenticator.php b/typo3/sysext/frontend/Classes/Middleware/FrontendUserAuthenticator.php
index 09a7ee440b30..86234b90568e 100644
--- a/typo3/sysext/frontend/Classes/Middleware/FrontendUserAuthenticator.php
+++ b/typo3/sysext/frontend/Classes/Middleware/FrontendUserAuthenticator.php
@@ -30,6 +30,16 @@ use TYPO3\CMS\Frontend\Authentication\FrontendUserAuthentication;
  */
 class FrontendUserAuthenticator implements MiddlewareInterface
 {
+    /**
+     * @var Context
+     */
+    protected $context;
+
+    public function __construct(Context $context)
+    {
+        $this->context = $context;
+    }
+
     /**
      * Creates a frontend user authentication object, tries to authenticate a user and stores
      * it in the current request as attribute.
@@ -59,7 +69,7 @@ class FrontendUserAuthenticator implements MiddlewareInterface
         $frontendUser->unpack_uc();
 
         // Register the frontend user as aspect and within the session
-        $this->setFrontendUserAspect(GeneralUtility::makeInstance(Context::class), $frontendUser);
+        $this->setFrontendUserAspect($frontendUser);
         $request = $request->withAttribute('frontend.user', $frontendUser);
 
         $response = $handler->handle($request);
@@ -112,11 +122,10 @@ class FrontendUserAuthenticator implements MiddlewareInterface
     /**
      * Register the frontend user as aspect
      *
-     * @param Context $context
      * @param AbstractUserAuthentication $user
      */
-    protected function setFrontendUserAspect(Context $context, AbstractUserAuthentication $user)
+    protected function setFrontendUserAspect(AbstractUserAuthentication $user)
     {
-        $context->setAspect('frontend.user', GeneralUtility::makeInstance(UserAspect::class, $user));
+        $this->context->setAspect('frontend.user', GeneralUtility::makeInstance(UserAspect::class, $user));
     }
 }
diff --git a/typo3/sysext/frontend/Classes/Middleware/PageArgumentValidator.php b/typo3/sysext/frontend/Classes/Middleware/PageArgumentValidator.php
index 6bf951d4e886..4b6d2aa45685 100644
--- a/typo3/sysext/frontend/Classes/Middleware/PageArgumentValidator.php
+++ b/typo3/sysext/frontend/Classes/Middleware/PageArgumentValidator.php
@@ -46,14 +46,22 @@ class PageArgumentValidator implements MiddlewareInterface, LoggerAwareInterface
      */
     protected $cacheHashCalculator;
 
+    /**
+     * @var TimeTracker
+     */
+    protected $timeTracker;
+
     /**
      * @var bool will be used to set $TSFE->no_cache later-on
      */
     protected $disableCache = false;
 
-    public function __construct()
-    {
-        $this->cacheHashCalculator = GeneralUtility::makeInstance(CacheHashCalculator::class);
+    public function __construct(
+        CacheHashCalculator $cacheHashCalculator,
+        TimeTracker $timeTracker
+    ) {
+        $this->cacheHashCalculator = $cacheHashCalculator;
+        $this->timeTracker = $timeTracker;
     }
 
     /**
@@ -158,7 +166,7 @@ class PageArgumentValidator implements MiddlewareInterface, LoggerAwareInterface
         }
         // Caching is disabled now (but no 404)
         $this->disableCache = true;
-        $this->getTimeTracker()->setTSlogMessage('The incoming cHash "' . $cHash . '" and calculated cHash "' . $calculatedCacheHash . '" did not match, so caching was disabled. The fieldlist used was "' . implode(',', array_keys($relevantParameters)) . '"', 2);
+        $this->timeTracker->setTSlogMessage('The incoming cHash "' . $cHash . '" and calculated cHash "' . $calculatedCacheHash . '" did not match, so caching was disabled. The fieldlist used was "' . implode(',', array_keys($relevantParameters)) . '"', 2);
         return true;
     }
 
@@ -182,15 +190,7 @@ class PageArgumentValidator implements MiddlewareInterface, LoggerAwareInterface
         }
         // Caching is disabled now (but no 404)
         $this->disableCache = true;
-        $this->getTimeTracker()->setTSlogMessage('TSFE->reqCHash(): No &cHash parameter was sent for GET vars though required so caching is disabled', 2);
+        $this->timeTracker->setTSlogMessage('TSFE->reqCHash(): No &cHash parameter was sent for GET vars though required so caching is disabled', 2);
         return true;
     }
-
-    /**
-     * @return TimeTracker
-     */
-    protected function getTimeTracker(): TimeTracker
-    {
-        return GeneralUtility::makeInstance(TimeTracker::class);
-    }
 }
diff --git a/typo3/sysext/frontend/Classes/Middleware/PrepareTypoScriptFrontendRendering.php b/typo3/sysext/frontend/Classes/Middleware/PrepareTypoScriptFrontendRendering.php
index 915efa5a2a43..3338875e5533 100644
--- a/typo3/sysext/frontend/Classes/Middleware/PrepareTypoScriptFrontendRendering.php
+++ b/typo3/sysext/frontend/Classes/Middleware/PrepareTypoScriptFrontendRendering.php
@@ -21,7 +21,6 @@ use Psr\Http\Message\ServerRequestInterface;
 use Psr\Http\Server\MiddlewareInterface;
 use Psr\Http\Server\RequestHandlerInterface;
 use TYPO3\CMS\Core\TimeTracker\TimeTracker;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
 
 /**
@@ -43,10 +42,10 @@ class PrepareTypoScriptFrontendRendering implements MiddlewareInterface
      */
     protected $timeTracker;
 
-    public function __construct(TypoScriptFrontendController $controller = null, TimeTracker $timeTracker = null)
+    public function __construct(TypoScriptFrontendController $controller, TimeTracker $timeTracker)
     {
-        $this->controller = $controller ?: $GLOBALS['TSFE'];
-        $this->timeTracker = $timeTracker ?: GeneralUtility::makeInstance(TimeTracker::class);
+        $this->controller = $controller;
+        $this->timeTracker = $timeTracker;
     }
 
     /**
diff --git a/typo3/sysext/frontend/Classes/Middleware/ShortcutAndMountPointRedirect.php b/typo3/sysext/frontend/Classes/Middleware/ShortcutAndMountPointRedirect.php
index 2835283f0cc7..a8cd817ca009 100644
--- a/typo3/sysext/frontend/Classes/Middleware/ShortcutAndMountPointRedirect.php
+++ b/typo3/sysext/frontend/Classes/Middleware/ShortcutAndMountPointRedirect.php
@@ -37,9 +37,9 @@ class ShortcutAndMountPointRedirect implements MiddlewareInterface
      */
     private $controller;
 
-    public function __construct(TypoScriptFrontendController $controller = null)
+    public function __construct(TypoScriptFrontendController $controller)
     {
-        $this->controller = $controller ?: $GLOBALS['TSFE'];
+        $this->controller = $controller;
     }
 
     public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
diff --git a/typo3/sysext/frontend/Classes/Middleware/SiteResolver.php b/typo3/sysext/frontend/Classes/Middleware/SiteResolver.php
index dc5e5de53afb..3fd37fe1f8c7 100644
--- a/typo3/sysext/frontend/Classes/Middleware/SiteResolver.php
+++ b/typo3/sysext/frontend/Classes/Middleware/SiteResolver.php
@@ -23,8 +23,6 @@ use TYPO3\CMS\Core\Localization\Locales;
 use TYPO3\CMS\Core\Routing\SiteMatcher;
 use TYPO3\CMS\Core\Routing\SiteRouteResult;
 use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
-use TYPO3\CMS\Core\Site\SiteFinder;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
 
 /**
  * Identifies if a site is configured for the request, based on "id" and "L" GET/POST parameters, or the requested
@@ -40,12 +38,9 @@ class SiteResolver implements MiddlewareInterface
      */
     protected $matcher;
 
-    public function __construct(SiteMatcher $matcher = null)
+    public function __construct(SiteMatcher $matcher)
     {
-        $this->matcher = $matcher ?? GeneralUtility::makeInstance(
-            SiteMatcher::class,
-            GeneralUtility::makeInstance(SiteFinder::class)
-        );
+        $this->matcher = $matcher;
     }
 
     /**
diff --git a/typo3/sysext/frontend/Classes/Middleware/StaticRouteResolver.php b/typo3/sysext/frontend/Classes/Middleware/StaticRouteResolver.php
index be1048c45727..80cb9fcde50c 100644
--- a/typo3/sysext/frontend/Classes/Middleware/StaticRouteResolver.php
+++ b/typo3/sysext/frontend/Classes/Middleware/StaticRouteResolver.php
@@ -27,13 +27,30 @@ use TYPO3\CMS\Core\Resource\File;
 use TYPO3\CMS\Core\Routing\InvalidRouteArgumentsException;
 use TYPO3\CMS\Core\Routing\RouterInterface;
 use TYPO3\CMS\Core\Site\Entity\Site;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
 
 /**
  * Resolves static routes - can return configured content directly or load content from file / urls
  */
 class StaticRouteResolver implements MiddlewareInterface
 {
+    /**
+     * @var RequestFactory
+     */
+    protected $requestFactory;
+
+    /**
+     * @var LinkService
+     */
+    protected $linkService;
+
+    public function __construct(
+        RequestFactory $requestFactory,
+        LinkService $linkService
+    ) {
+        $this->requestFactory = $requestFactory;
+        $this->linkService = $linkService;
+    }
+
     /**
      * Checks if there is a valid site with route configuration.
      *
@@ -83,8 +100,7 @@ class StaticRouteResolver implements MiddlewareInterface
      */
     protected function getFromUri(string $uri): array
     {
-        $requestFactory = GeneralUtility::makeInstance(RequestFactory::class);
-        $response = $requestFactory->request($uri);
+        $response = $this->requestFactory->request($uri);
         $contentType = 'text/plain; charset=utf-8';
         $content = '';
         if ($response->getStatusCode() === 200) {
@@ -129,8 +145,7 @@ class StaticRouteResolver implements MiddlewareInterface
                 $contentType = 'text/plain; charset=utf-8';
                 break;
             case 'uri':
-                $linkService = GeneralUtility::makeInstance(LinkService::class);
-                $urlParams = $linkService->resolve($routeConfig['source']);
+                $urlParams = $this->linkService->resolve($routeConfig['source']);
                 if ($urlParams['type'] === 'url' || $urlParams['type'] === 'page') {
                     $uri = $urlParams['url'] ?? $this->getPageUri($request, $site, $urlParams);
                     [$content, $contentType] = $this->getFromUri($uri);
diff --git a/typo3/sysext/frontend/Classes/Middleware/TimeTrackerInitialization.php b/typo3/sysext/frontend/Classes/Middleware/TimeTrackerInitialization.php
index 79abaff2ca0f..f28c8004ce08 100644
--- a/typo3/sysext/frontend/Classes/Middleware/TimeTrackerInitialization.php
+++ b/typo3/sysext/frontend/Classes/Middleware/TimeTrackerInitialization.php
@@ -20,7 +20,6 @@ use Psr\Http\Message\ServerRequestInterface;
 use Psr\Http\Server\MiddlewareInterface;
 use Psr\Http\Server\RequestHandlerInterface;
 use TYPO3\CMS\Core\TimeTracker\TimeTracker;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
 
 /**
@@ -30,6 +29,16 @@ use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
  */
 class TimeTrackerInitialization implements MiddlewareInterface
 {
+    /**
+     * @var TimeTracker
+     */
+    protected $timeTracker;
+
+    public function __construct(TimeTracker $timeTracker)
+    {
+        $this->timeTracker = $timeTracker;
+    }
+
     /**
      * Starting time tracking (by setting up a singleton object)
      *
@@ -40,21 +49,18 @@ class TimeTrackerInitialization implements MiddlewareInterface
     public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
     {
         $timeTrackingEnabled = $this->isBackendUserCookieSet($request);
-        $timeTracker = GeneralUtility::makeInstance(
-            TimeTracker::class,
-            $timeTrackingEnabled
-        );
-        $timeTracker->start(microtime(true));
-        $timeTracker->push('');
+        $this->timeTracker->setEnabled($timeTrackingEnabled);
+        $this->timeTracker->start(microtime(true));
+        $this->timeTracker->push('');
 
         $response = $handler->handle($request);
 
         // Finish time tracking
-        $timeTracker->pull();
-        $timeTracker->finish();
+        $this->timeTracker->pull();
+        $this->timeTracker->finish();
 
         if ($this->isDebugModeEnabled()) {
-            return $response->withHeader('X-TYPO3-Parsetime', $timeTracker->getParseTime() . 'ms');
+            return $response->withHeader('X-TYPO3-Parsetime', $this->timeTracker->getParseTime() . 'ms');
         }
         return $response;
     }
diff --git a/typo3/sysext/frontend/Classes/Middleware/TypoScriptFrontendInitialization.php b/typo3/sysext/frontend/Classes/Middleware/TypoScriptFrontendInitialization.php
index 44b746e5ecda..311162444714 100644
--- a/typo3/sysext/frontend/Classes/Middleware/TypoScriptFrontendInitialization.php
+++ b/typo3/sysext/frontend/Classes/Middleware/TypoScriptFrontendInitialization.php
@@ -43,6 +43,16 @@ use TYPO3\CMS\Frontend\Page\PageAccessFailureReasons;
  */
 class TypoScriptFrontendInitialization implements MiddlewareInterface
 {
+    /**
+     * @var Context
+     */
+    protected $context;
+
+    public function __construct(Context $context)
+    {
+        $this->context = $context;
+    }
+
     /**
      * Creates an instance of TSFE and sets it as a global variable.
      *
@@ -65,12 +75,11 @@ class TypoScriptFrontendInitialization implements MiddlewareInterface
                 ['code' => PageAccessFailureReasons::INVALID_PAGE_ARGUMENTS]
             );
         }
-        $context = GeneralUtility::makeInstance(Context::class);
-        $context->setAspect('frontend.preview', GeneralUtility::makeInstance(PreviewAspect::class));
+        $this->context->setAspect('frontend.preview', GeneralUtility::makeInstance(PreviewAspect::class));
 
         $controller = GeneralUtility::makeInstance(
             TypoScriptFrontendController::class,
-            $context,
+            $this->context,
             $site,
             $request->getAttribute('language', $site->getDefaultLanguage()),
             $pageArguments,
@@ -90,7 +99,7 @@ class TypoScriptFrontendInitialization implements MiddlewareInterface
         if ($controller->isBackendUserLoggedIn() && !$GLOBALS['BE_USER']->doesUserHaveAccess($controller->page, Permission::PAGE_SHOW)) {
             unset($GLOBALS['BE_USER']);
             // Register an empty backend user as aspect
-            $this->setBackendUserAspect($context, null);
+            $this->setBackendUserAspect(null);
             $controller->determineId();
         }
 
@@ -102,12 +111,11 @@ class TypoScriptFrontendInitialization implements MiddlewareInterface
     /**
      * Register the backend user as aspect
      *
-     * @param Context $context
      * @param BackendUserAuthentication|null $user
      */
-    protected function setBackendUserAspect(Context $context, ?BackendUserAuthentication $user): void
+    protected function setBackendUserAspect(BackendUserAuthentication $user): void
     {
-        $context->setAspect('backend.user', GeneralUtility::makeInstance(UserAspect::class, $user));
-        $context->setAspect('workspace', GeneralUtility::makeInstance(WorkspaceAspect::class, $user ? $user->workspace : 0));
+        $this->context->setAspect('backend.user', GeneralUtility::makeInstance(UserAspect::class, $user));
+        $this->context->setAspect('workspace', GeneralUtility::makeInstance(WorkspaceAspect::class, $user ? $user->workspace : 0));
     }
 }
diff --git a/typo3/sysext/frontend/Tests/Unit/Middleware/PageArgumentValidatorTest.php b/typo3/sysext/frontend/Tests/Unit/Middleware/PageArgumentValidatorTest.php
index 698a216a1173..dfed704116a9 100644
--- a/typo3/sysext/frontend/Tests/Unit/Middleware/PageArgumentValidatorTest.php
+++ b/typo3/sysext/frontend/Tests/Unit/Middleware/PageArgumentValidatorTest.php
@@ -24,24 +24,23 @@ use TYPO3\CMS\Core\Http\Response;
 use TYPO3\CMS\Core\Http\ServerRequest;
 use TYPO3\CMS\Core\Routing\PageArguments;
 use TYPO3\CMS\Core\TimeTracker\TimeTracker;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
 use TYPO3\CMS\Frontend\Middleware\PageArgumentValidator;
 use TYPO3\CMS\Frontend\Middleware\PageResolver;
+use TYPO3\CMS\Frontend\Page\CacheHashCalculator;
 use TYPO3\TestingFramework\Core\AccessibleObjectInterface;
 use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
 
 class PageArgumentValidatorTest extends UnitTestCase
 {
     /**
-     * @var bool Reset singletons created by subject
+     * @var CacheHashCaluclator
      */
-    protected $resetSingletonInstances = true;
+    protected $cacheHashCalculator;
 
     /**
-     * @var TypoScriptFrontendController|AccessibleObjectInterface
+     * @var TimeTracker
      */
-    protected $controller;
+    protected $timeTrackerStub;
 
     /**
      * @var RequestHandlerInterface
@@ -56,9 +55,8 @@ class PageArgumentValidatorTest extends UnitTestCase
     protected function setUp(): void
     {
         parent::setUp();
-        $timeTrackerStub = new TimeTracker(false);
-        GeneralUtility::setSingletonInstance(TimeTracker::class, $timeTrackerStub);
-        $this->controller = $this->getAccessibleMock(TypoScriptFrontendController::class, ['dummy'], [], '', false);
+        $this->timeTrackerStub = new TimeTracker(false);
+        $this->cacheHashCalculator = new CacheHashCalculator;
 
         // A request handler which only runs through
         $this->responseOutputHandler = new class implements RequestHandlerInterface {
@@ -82,7 +80,7 @@ class PageArgumentValidatorTest extends UnitTestCase
         $request = new ServerRequest($incomingUrl, 'GET');
         $request = $request->withAttribute('routing', $pageArguments);
 
-        $subject = new PageArgumentValidator($this->controller);
+        $subject = new PageArgumentValidator($this->cacheHashCalculator, $this->timeTrackerStub);
         $subject->setLogger(new NullLogger());
 
         $response = $subject->process($request, $this->responseOutputHandler);
@@ -102,7 +100,7 @@ class PageArgumentValidatorTest extends UnitTestCase
         $request = new ServerRequest($incomingUrl, 'GET');
         $request = $request->withAttribute('routing', $pageArguments);
 
-        $subject = new PageArgumentValidator($this->controller);
+        $subject = new PageArgumentValidator($this->cacheHashCalculator, $this->timeTrackerStub);
         $response = $subject->process($request, $this->responseOutputHandler);
         static::assertEquals(404, $response->getStatusCode());
     }
@@ -115,7 +113,7 @@ class PageArgumentValidatorTest extends UnitTestCase
         $incomingUrl = 'https://king.com/lotus-flower/en/mr-magpie/bloom/';
         $request = new ServerRequest($incomingUrl, 'GET');
 
-        $subject = new PageArgumentValidator($this->controller);
+        $subject = new PageArgumentValidator($this->cacheHashCalculator, $this->timeTrackerStub);
         $response = $subject->process($request, $this->responseOutputHandler);
         static::assertEquals(404, $response->getStatusCode());
     }
@@ -132,7 +130,7 @@ class PageArgumentValidatorTest extends UnitTestCase
         $request = new ServerRequest($incomingUrl, 'GET');
         $request = $request->withAttribute('routing', $pageArguments);
 
-        $subject = new PageArgumentValidator($this->controller);
+        $subject = new PageArgumentValidator($this->cacheHashCalculator, $this->timeTrackerStub);
         $response = $subject->process($request, $this->responseOutputHandler);
         static::assertEquals(200, $response->getStatusCode());
     }
@@ -149,7 +147,7 @@ class PageArgumentValidatorTest extends UnitTestCase
         $request = new ServerRequest($incomingUrl, 'GET');
         $request = $request->withAttribute('routing', $pageArguments);
 
-        $subject = new PageArgumentValidator($this->controller);
+        $subject = new PageArgumentValidator($this->cacheHashCalculator, $this->timeTrackerStub);
         $response = $subject->process($request, $this->responseOutputHandler);
         static::assertEquals(404, $response->getStatusCode());
     }
diff --git a/typo3/sysext/install/Classes/Middleware/Maintenance.php b/typo3/sysext/install/Classes/Middleware/Maintenance.php
index 451cf827eeaa..b4a081d3eab4 100644
--- a/typo3/sysext/install/Classes/Middleware/Maintenance.php
+++ b/typo3/sysext/install/Classes/Middleware/Maintenance.php
@@ -29,9 +29,8 @@ use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Core\Http\JsonResponse;
 use TYPO3\CMS\Core\Messaging\FlashMessage;
 use TYPO3\CMS\Core\Messaging\FlashMessageQueue;
+use TYPO3\CMS\Core\Package\FailsafePackageManager;
 use TYPO3\CMS\Core\Package\PackageInterface;
-use TYPO3\CMS\Core\Package\PackageManager;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Install\Authentication\AuthenticationService;
 use TYPO3\CMS\Install\Controller\AbstractController;
 use TYPO3\CMS\Install\Controller\EnvironmentController;
@@ -51,11 +50,21 @@ use TYPO3\CMS\Install\Service\SessionService;
  */
 class Maintenance implements MiddlewareInterface
 {
+    /**
+     * @var FailsafePackageManager
+     */
+    protected $packageManager;
+
     /**
      * @var ConfigurationManager
      */
     protected $configurationManager;
 
+    /**
+     * @var PasswordHashFactory
+     */
+    protected $passwordHashFactory;
+
     /**
      * @var ContainerInterface
      */
@@ -74,12 +83,15 @@ class Maintenance implements MiddlewareInterface
         'environment' => EnvironmentController::class,
     ];
 
-    /**
-     * @param ConfigurationManager $configurationManager
-     */
-    public function __construct(ConfigurationManager $configurationManager, ContainerInterface $container)
-    {
+    public function __construct(
+        FailsafePackageManager $packageManager,
+        ConfigurationManager $configurationManager,
+        PasswordHashFactory $passwordHashFactory,
+        ContainerInterface $container
+    ) {
+        $this->packageManager = $packageManager;
         $this->configurationManager = $configurationManager;
+        $this->passwordHashFactory = $passwordHashFactory;
         $this->container = $container;
     }
 
@@ -152,7 +164,7 @@ class Maintenance implements MiddlewareInterface
                         new FlashMessage('Please enter the install tool password', '', FlashMessage::ERROR)
                     );
                 } else {
-                    $hashInstance = GeneralUtility::makeInstance(PasswordHashFactory::class)->getDefaultHashInstance('BE');
+                    $hashInstance = $this->passwordHashFactory->getDefaultHashInstance('BE');
                     $hashedPassword = $hashInstance->getHashedPassword($password);
                     $messageQueue = (new FlashMessageQueue('install'))->enqueue(
                         new FlashMessage(
@@ -328,18 +340,13 @@ class Maintenance implements MiddlewareInterface
     protected function recreatePackageStatesFileIfMissing(): void
     {
         if (!file_exists(Environment::getLegacyConfigPath() . '/PackageStates.php')) {
-            // We need a FailsafePackageManager at this moment, however this is given
-            // As Bootstrap is registering the FailsafePackageManager object as a singleton instance
-            // of the main PackageManager class. See \TYPO3\CMS\Core\Core\Bootstrap::init()
-            /** @var \TYPO3\CMS\Core\Package\FailsafePackageManager $packageManager */
-            $packageManager = GeneralUtility::makeInstance(PackageManager::class);
-            $packages = $packageManager->getAvailablePackages();
+            $packages = $this->packageManager->getAvailablePackages();
             foreach ($packages as $package) {
                 if ($package instanceof PackageInterface && $package->isPartOfMinimalUsableSystem()) {
-                    $packageManager->activatePackage($package->getPackageKey());
+                    $this->packageManager->activatePackage($package->getPackageKey());
                 }
             }
-            $packageManager->forceSortAndSavePackageStates();
+            $this->packageManager->forceSortAndSavePackageStates();
         }
     }
 }
diff --git a/typo3/sysext/install/Classes/ServiceProvider.php b/typo3/sysext/install/Classes/ServiceProvider.php
index c42e51fb739d..e9689df4c4df 100644
--- a/typo3/sysext/install/Classes/ServiceProvider.php
+++ b/typo3/sysext/install/Classes/ServiceProvider.php
@@ -18,6 +18,7 @@ namespace TYPO3\CMS\Install;
 use Psr\Container\ContainerInterface;
 use TYPO3\CMS\Core\Configuration\ConfigurationManager;
 use TYPO3\CMS\Core\Context\Context;
+use TYPO3\CMS\Core\Crypto\PasswordHashing\PasswordHashFactory;
 use TYPO3\CMS\Core\DependencyInjection\ContainerBuilder;
 use TYPO3\CMS\Core\Http\MiddlewareDispatcher;
 use TYPO3\CMS\Core\Package\AbstractServiceProvider;
@@ -84,7 +85,9 @@ class ServiceProvider extends AbstractServiceProvider
     public static function getMaintenanceMiddleware(ContainerInterface $container): Middleware\Maintenance
     {
         return new Middleware\Maintenance(
+            $container->get(PackageManager::class),
             $container->get(ConfigurationManager::class),
+            $container->get(PasswordHashFactory::class),
             $container
         );
     }
-- 
GitLab