[!!!][TASK] Drop support for deprecated cache usage in ext_localconf 31/59231/10
authorBenjamin Franzke <bfr@qbus.de>
Wed, 19 Dec 2018 09:44:58 +0000 (10:44 +0100)
committerGeorg Ringer <georg.ringer@gmail.com>
Tue, 15 Jan 2019 11:49:27 +0000 (12:49 +0100)
The initialization of the CacheManager has a design problem:

The *CacheManager* is used to create the core_cache. That core_cache
is used to read the (possibly) cached *CacheManager* configuration
(from ext_localconf.php), which is then used to (re)configure the
already-being-used *CacheManager* after ext_localconf.php has been
loaded. That means an extension can create a cache while it has
not been configured by a second extension. That behaviour was
deprecated in v9 and can therefore be dropped now.

We now create the core cache (and because of requirements
in core currently also the 'assets' cache) during early bootstrap
(independently from the CacheManager) and inject these early caches
into the CacheManager instance later on. The CacheManager instance is now
created during late bootstrap.
Looking forward to a Dependency Injection (DI) container, this change will
allow to move the CacheManager creation from bootstrap code into the DI
service providers (which will allow the CacheManager to be instantiated
on demand)

Releases: master
Resolves: #87245
Related: #86353
Change-Id: I984beabdbbd550c191de347fdc19166283452a88
Reviewed-on: https://review.typo3.org/59231
Tested-by: TYPO3com <noreply@typo3.com>
Reviewed-by: Benni Mack <benni@typo3.org>
Tested-by: Benni Mack <benni@typo3.org>
Reviewed-by: Wouter Wolters <typo3@wouterwolters.nl>
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
Reviewed-by: Georg Ringer <georg.ringer@gmail.com>
Tested-by: Georg Ringer <georg.ringer@gmail.com>
typo3/sysext/core/Classes/Cache/CacheManager.php
typo3/sysext/core/Classes/Core/Bootstrap.php
typo3/sysext/core/Documentation/Changelog/master/Breaking-87193-DeprecatedFunctionalityRemoved.rst

index 41f5a56..1d64271 100644 (file)
@@ -67,16 +67,6 @@ class CacheManager implements SingletonInterface
     protected $disableCaching = false;
 
     /**
-     * Used by Bootstrap to define whether the configuration has been set finally.
-     * Controls whether a deprecation warning is logged in getCache().
-     * This property will be removed in TYPO3 v10.0.
-     *
-     * @var bool
-     * @internal
-     */
-    protected $limbo = false;
-
-    /**
      * @param bool $disableCaching
      */
     public function __construct(bool $disableCaching = false)
@@ -113,15 +103,19 @@ class CacheManager implements SingletonInterface
      * Registers a cache so it can be retrieved at a later point.
      *
      * @param FrontendInterface $cache The cache frontend to be registered
+     * @param array $groups Cache groups to be associated to the cache
      * @throws DuplicateIdentifierException if a cache with the given identifier has already been registered.
      */
-    public function registerCache(FrontendInterface $cache)
+    public function registerCache(FrontendInterface $cache, array $groups = [])
     {
         $identifier = $cache->getIdentifier();
         if (isset($this->caches[$identifier])) {
             throw new DuplicateIdentifierException('A cache with identifier "' . $identifier . '" has already been registered.', 1203698223);
         }
         $this->caches[$identifier] = $cache;
+        foreach ($groups as $groupIdentifier) {
+            $this->cacheGroups[$groupIdentifier][] = $identifier;
+        }
     }
 
     /**
@@ -280,10 +274,6 @@ class CacheManager implements SingletonInterface
      */
     protected function createCache($identifier)
     {
-        // @deprecated will be removed with TYPO3 v10.0
-        if ($this->limbo) {
-            trigger_error('Usage of ' . self::class . '->createCache(\'' . $identifier . '\') in ext_localconf.php will not be supported in TYPO3 v10.0.', E_USER_DEPRECATED);
-        }
         if (isset($this->cacheConfigurations[$identifier]['frontend'])) {
             $frontend = $this->cacheConfigurations[$identifier]['frontend'];
         } else {
@@ -340,18 +330,4 @@ class CacheManager implements SingletonInterface
 
         $this->registerCache($frontendInstance);
     }
-
-    /**
-     * Sets the limbo state
-     *
-     * If limbo is enable, then getCache() will log a deprecation warning.
-     * This method will be removed in TYPO3 v10.0.
-     *
-     * @param bool $limbo
-     * @internal
-     */
-    public function setLimbo(bool $limbo)
-    {
-        $this->limbo = $limbo;
-    }
 }
index 4b11d4f..e1006a1 100644 (file)
@@ -19,8 +19,13 @@ use Doctrine\Common\Annotations\AnnotationReader;
 use Doctrine\Common\Annotations\AnnotationRegistry;
 use Psr\Container\ContainerInterface;
 use Psr\Container\NotFoundExceptionInterface;
+use TYPO3\CMS\Core\Cache\Backend\BackendInterface;
+use TYPO3\CMS\Core\Cache\Backend\NullBackend;
 use TYPO3\CMS\Core\Cache\CacheManager;
+use TYPO3\CMS\Core\Cache\Exception\InvalidBackendException;
+use TYPO3\CMS\Core\Cache\Exception\InvalidCacheException;
 use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface;
+use TYPO3\CMS\Core\Cache\Frontend\VariableFrontend;
 use TYPO3\CMS\Core\Configuration\ConfigurationManager;
 use TYPO3\CMS\Core\Imaging\IconRegistry;
 use TYPO3\CMS\Core\IO\PharStreamWrapperInterceptor;
@@ -77,11 +82,10 @@ class Bootstrap
         static::initializeErrorHandling();
         static::initializeIO();
 
+        $disableCaching = $failsafe ? true : false;
+
         $logManager = new LogManager($requestId);
-        $cacheManager = static::createCacheManager($failsafe ? true : false);
-        $coreCache = $cacheManager->getCache('cache_core');
-        $assetsCache = $cacheManager->getCache('assets');
-        $cacheManager->setLimbo(true);
+        $coreCache = static::createCache('cache_core', $disableCaching);
         $packageManager = static::createPackageManager(
             $failsafe ? FailsafePackageManager::class : PackageManager::class,
             $coreCache
@@ -91,7 +95,6 @@ class Bootstrap
         // They should be fetched through a container (later) but currently a PackageManager
         // singleton instance is required by PackageManager->activePackageDuringRuntime
         GeneralUtility::setSingletonInstance(LogManager::class, $logManager);
-        GeneralUtility::setSingletonInstance(CacheManager::class, $cacheManager);
         GeneralUtility::setSingletonInstance(PackageManager::class, $packageManager);
         ExtensionManagementUtility::setPackageManager($packageManager);
 
@@ -101,22 +104,30 @@ class Bootstrap
         $locales = Locales::initialize();
         static::setMemoryLimit();
 
+        $assetsCache = static::createCache('assets', $disableCaching);
         if (!$failsafe) {
             IconRegistry::setCache($assetsCache);
             PageRenderer::setCache($assetsCache);
             static::loadTypo3LoadedExtAndExtLocalconf(true, $coreCache);
-            static::setFinalCachingFrameworkCacheConfiguration($cacheManager);
             static::unsetReservedGlobalVariables();
             static::loadBaseTca(true, $coreCache);
             static::checkEncryptionKey();
         }
-        $cacheManager->setLimbo(false);
+
+        // Create the global CacheManager singleton instance and inject early cache instances.
+        // This can be removed once we have a system wide dependency injection container, where
+        // the CacheManager instance could be created on demand (early cache instances would
+        // be injected as dependency from $defaultContainerEntries)
+        $cacheManager = static::createCacheManager($disableCaching, [$coreCache, $assetsCache]);
+        GeneralUtility::setSingletonInstance(CacheManager::class, $cacheManager);
 
         $defaultContainerEntries = [
             ClassLoader::class => $classLoader,
             'request.id' => $requestId,
             ConfigurationManager::class => $configurationManager,
             LogManager::class => $logManager,
+            'cache.core' => $coreCache,
+            'cache.assets' => $assetsCache,
             CacheManager::class => $cacheManager,
             PackageManager::class => $packageManager,
             Locales::class => $locales,
@@ -339,17 +350,66 @@ class Bootstrap
     }
 
     /**
+     * Instantiates an early cache instance
+     *
+     * Creates a cache instances independently from the CacheManager.
+     * The is used to create the core cache during early bootstrap when the CacheManager
+     * is not yet available (i.e. configuration is not yet loaded).
+     *
+     * @param string $identifier
+     * @param bool $disableCaching
+     * @return FrontendInterface
+     * @internal
+     */
+    protected static function createCache(string $identifier, bool $disableCaching = false): FrontendInterface
+    {
+        $configuration = $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations'][$identifier] ?? [];
+
+        $frontend = $configuration['frontend'] ?? VariableFrontend::class;
+        $backend = $configuration['backend'] ?? Typo3DatabaseBackend::class;
+        $options = $configuration['options'] ?? [];
+
+        if ($disableCaching) {
+            $backend = NullBackend::class;
+            $options = [];
+        }
+
+        $backendInstance = new $backend('production', $options);
+        if (!$backendInstance instanceof BackendInterface) {
+            throw new InvalidBackendException('"' . $backend . '" is not a valid cache backend object.', 1545260108);
+        }
+        if (is_callable([$backendInstance, 'initializeObject'])) {
+            $backendInstance->initializeObject();
+        }
+
+        $frontendInstance = new $frontend($identifier, $backendInstance);
+        if (!$frontendInstance instanceof FrontendInterface) {
+            throw new InvalidCacheException('"' . $frontend . '" is not a valid cache frontend object.', 1545260109);
+        }
+        if (is_callable([$frontendInstance, 'initializeObject'])) {
+            $frontendInstance->initializeObject();
+        }
+
+        return $frontendInstance;
+    }
+
+    /**
      * Initialize caching framework, and re-initializes it (e.g. in the install tool) by recreating the instances
      * again despite the Singleton instance
      *
      * @param bool $disableCaching
+     * @param array $defaultCaches
      * @return CacheManager
      * @internal This is not a public API method, do not use in own extensions
      */
-    public static function createCacheManager(bool $disableCaching = false): CacheManager
+    public static function createCacheManager(bool $disableCaching = false, array $defaultCaches = []): CacheManager
     {
+        $cacheConfigurations = $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations'];
         $cacheManager = new CacheManager($disableCaching);
-        $cacheManager->setCacheConfigurations($GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']);
+        $cacheManager->setCacheConfigurations($cacheConfigurations);
+        foreach ($defaultCaches as $cache) {
+            $cacheManager->registerCache($cache, $cacheConfigurations[$cache->getIdentifier()]['groups'] ?? ['all']);
+        }
         return $cacheManager;
     }
 
@@ -457,21 +517,6 @@ class Bootstrap
     }
 
     /**
-     * Extensions may register new caches, so we set the
-     * global cache array to the manager again at this point
-     *
-     * @param CacheManager $cacheManager
-     * @internal This is not a public API method, do not use in own extensions
-     */
-    protected static function setFinalCachingFrameworkCacheConfiguration(CacheManager $cacheManager = null)
-    {
-        if ($cacheManager === null) {
-            $cacheManager = GeneralUtility::makeInstance(CacheManager::class);
-        }
-        $cacheManager->setCacheConfigurations($GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']);
-    }
-
-    /**
      * Unsetting reserved global variables:
      * Those are set in "ext:core/ext_tables.php" file:
      *
index 7be9621..7b65eb2 100644 (file)
@@ -1265,6 +1265,7 @@ The following features have been removed:
   Instead, they must contain a target (callable, class/method, function).
 * TCA auto migration from core v6 to core v7 compatible TCA
 * TCA :php:`type='group'` with :php:`internal_type='file'` and :php:`internal_type='file_reference`
+* Cache creation using :php:`\TYPO3\CMS\Cache\CacheManger` during :php:`ext_localconf.php` loading
 
 
 The following database tables have been removed: