From a92d9430c0e1daeb25d8129c74ca18ee2ed9cb92 Mon Sep 17 00:00:00 2001
From: Helmut Hummel <typo3@helhum.io>
Date: Thu, 17 Jun 2021 12:53:04 +0200
Subject: [PATCH] [TASK] Deprecate usage of cache and DB connection early in
 bootstrap

This change allows TYPO3 to detect and trigger a deprecation of
the Cache Manager and database connection not only during loading of
ext_localconf.php, but as well during building of TCA and
loading of ext_tables.php.

Code executed in these places has two purposes:

1. Provide/ adapt configuration
2. Register extension APIs (icons, modules, etc.)

Both purposes will eventually migrated to DI configuration, which currently
already is executed in a "stateless" environment.

To prepare extension authors that this change will happen, before we will be able
to migrate all current use cases to be registered in DI configuration,
usage of DB connection and cache manager is deprecated at these early
boot extension points.

Releases: master
Resolves: #94979
Change-Id: If03910ddd10c06662e1c9f5bea179ff12d64c989
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/69509
Tested-by: Benjamin Franzke <bfr@qbus.de>
Tested-by: core-ci <typo3@b13.com>
Tested-by: Benni Mack <benni@typo3.org>
Reviewed-by: Benjamin Franzke <bfr@qbus.de>
Reviewed-by: Benni Mack <benni@typo3.org>
---
 .../sysext/core/Classes/Core/BootService.php  |  2 +
 typo3/sysext/core/Classes/Core/Bootstrap.php  |  4 ++
 typo3/sysext/core/Classes/ServiceProvider.php | 17 ++++++++
 ...atabaseConnectionsDuringTYPO3Bootstrap.rst | 43 +++++++++++++++++++
 4 files changed, 66 insertions(+)
 create mode 100644 typo3/sysext/core/Documentation/Changelog/master/Deprecation-94979-UsingCacheManagerOrDatabaseConnectionsDuringTYPO3Bootstrap.rst

diff --git a/typo3/sysext/core/Classes/Core/BootService.php b/typo3/sysext/core/Classes/Core/BootService.php
index 8feb91b353c7..5bdf93fd97cc 100644
--- a/typo3/sysext/core/Classes/Core/BootService.php
+++ b/typo3/sysext/core/Classes/Core/BootService.php
@@ -123,6 +123,7 @@ class BootService
         $beUserBackup = $GLOBALS['BE_USER'] ?? null;
 
         $container->get('boot.state')->done = false;
+        $container->get('boot.state')->complete = false;
         $assetsCache = $container->get('cache.assets');
         PageRenderer::setCache($assetsCache);
         $eventDispatcher = $container->get(EventDispatcherInterface::class);
@@ -133,6 +134,7 @@ class BootService
         $container->get('boot.state')->done = true;
         Bootstrap::loadBaseTca($allowCaching);
         Bootstrap::loadExtTables($allowCaching);
+        $container->get('boot.state')->complete = true;
 
         if ($resetContainer) {
             $this->makeCurrent(null, $backup);
diff --git a/typo3/sysext/core/Classes/Core/Bootstrap.php b/typo3/sysext/core/Classes/Core/Bootstrap.php
index 2bc0592b2aa6..7e988f73116c 100644
--- a/typo3/sysext/core/Classes/Core/Bootstrap.php
+++ b/typo3/sysext/core/Classes/Core/Bootstrap.php
@@ -114,6 +114,8 @@ class Bootstrap
 
         $bootState = new \stdClass();
         $bootState->done = false;
+        // After a deprecation grace period, only one of those flag will remain, likely ->done
+        $bootState->complete = false;
         $bootState->cacheDisabled = $disableCaching;
 
         $builder = new ContainerBuilder([
@@ -145,6 +147,7 @@ class Bootstrap
 
         if ($failsafe) {
             $bootState->done = true;
+            $bootState->complete = true;
             return $container;
         }
 
@@ -155,6 +158,7 @@ class Bootstrap
         $bootState->done = true;
         static::loadBaseTca(true, $coreCache);
         static::checkEncryptionKey();
+        $bootState->complete = true;
 
         return $container;
     }
diff --git a/typo3/sysext/core/Classes/ServiceProvider.php b/typo3/sysext/core/Classes/ServiceProvider.php
index 193ecb6b4ce5..23f6af4796ee 100644
--- a/typo3/sysext/core/Classes/ServiceProvider.php
+++ b/typo3/sysext/core/Classes/ServiceProvider.php
@@ -44,6 +44,7 @@ class ServiceProvider extends AbstractServiceProvider
         return [
             SymfonyEventDispatcher::class => [ static::class, 'getSymfonyEventDispatcher' ],
             Cache\CacheManager::class => [ static::class, 'getCacheManager' ],
+            Database\ConnectionPool::class => [ static::class, 'getConnectionPool' ],
             Charset\CharsetConverter::class => [ static::class, 'getCharsetConverter' ],
             Configuration\SiteConfiguration::class => [ static::class, 'getSiteConfiguration' ],
             Command\ListCommand::class => [ static::class, 'getListCommand' ],
@@ -109,6 +110,11 @@ class ServiceProvider extends AbstractServiceProvider
         if (!$container->get('boot.state')->done) {
             throw new \LogicException(Cache\CacheManager::class . ' can not be injected/instantiated during ext_localconf.php loading. Use lazy loading instead.', 1549446998);
         }
+        if (!$container->get('boot.state')->complete) {
+            trigger_error(Cache\CacheManager::class . ' can not be injected/instantiated during ext_localconf.php/TCA/ext_tables.php loading. Use lazy loading instead.', E_USER_DEPRECATED);
+            // @todo: Deprecation will be turned into the following LogicException after the deprecation grace period, likely ->complete will then be merged with ->done.
+            //throw new \LogicException(Cache\CacheManager::class . ' can not be injected/instantiated during ext_localconf.php/TCA/ext_tables.php loading. Use lazy loading instead.', 1623925235);
+        }
 
         $cacheConfigurations = $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations'] ?? [];
         $disableCaching = $container->get('boot.state')->cacheDisabled;
@@ -128,6 +134,17 @@ class ServiceProvider extends AbstractServiceProvider
         return $cacheManager;
     }
 
+    public static function getConnectionPool(ContainerInterface $container): Database\ConnectionPool
+    {
+        if (!$container->get('boot.state')->complete) {
+            trigger_error(Database\ConnectionPool::class . ' can not be injected/instantiated during ext_localconf.php/TCA/ext_tables.php loading. Use lazy loading instead.', E_USER_DEPRECATED);
+            // @todo: Deprecation will be turned into the following LogicException after the deprecation grace period, likely ->complete will then be merged with ->done.
+            //throw new \LogicException(Database\ConnectionPool::class . ' can not be injected/instantiated during ext_localconf.php/TCA/ext_tables.php loading. Use lazy loading instead.', 1623914347);
+        }
+
+        return self::new($container, Database\ConnectionPool::class);
+    }
+
     public static function getCharsetConverter(ContainerInterface $container): Charset\CharsetConverter
     {
         return self::new($container, Charset\CharsetConverter::class);
diff --git a/typo3/sysext/core/Documentation/Changelog/master/Deprecation-94979-UsingCacheManagerOrDatabaseConnectionsDuringTYPO3Bootstrap.rst b/typo3/sysext/core/Documentation/Changelog/master/Deprecation-94979-UsingCacheManagerOrDatabaseConnectionsDuringTYPO3Bootstrap.rst
new file mode 100644
index 000000000000..ba92770b256f
--- /dev/null
+++ b/typo3/sysext/core/Documentation/Changelog/master/Deprecation-94979-UsingCacheManagerOrDatabaseConnectionsDuringTYPO3Bootstrap.rst
@@ -0,0 +1,43 @@
+.. include:: ../../Includes.txt
+
+=======================================================================================
+Deprecation: #94979 - Using CacheManager or Database Connections during TYPO3 bootstrap
+=======================================================================================
+
+See :issue:`94979`
+
+Description
+===========
+
+TYPO3 now triggers a deprecation if extension authors
+or site admins have code in their `ext_localconf.php`,
+`Configuration/TCA/*` configuration files or `ext_tables.php`.
+
+This is important for extension authors as TYPO3 will become
+stricter in the future in terms of booting up TYPO3's Core Configuration, making typical requests much faster, as all
+configuration can be cached away. When using TYPO3 in
+a build environment, this will also lead to possibilities to
+pre-warmup caches during the build phase of a new deployment.
+
+
+Impact
+======
+
+Accessing the database and utilizing the Cache Manager in
+these files will trigger a deprecation message.
+
+
+Affected Installations
+======================
+
+TYPO3 installations with extensions using Cache Manager
+or Database Connections.
+
+
+Migration
+=========
+
+Use proper places to initialize extensions, and only when
+needed to reduce the general time to boot up TYPO3's configuration.
+
+.. index:: PHP-API, NotScanned, ext:core
\ No newline at end of file
-- 
GitLab