From e42412a8e7ceb29eae1a0c3728a20b6942d6501a Mon Sep 17 00:00:00 2001
From: Benjamin Franzke <bfr@qbus.de>
Date: Sat, 18 Apr 2020 14:40:55 +0200
Subject: [PATCH] [BUGFIX] Avoid using the symfony container to clear its own
 caches

With the introduction of a custom DI cache in #90418, the container
was used to lookup its own cache and the cache identifier. This
results in bugs if the container cache is stale:
Loading from the cache and flushing the cache will work, but code that
runs after the cache has been flushed (ext_localconf loading) will still
use the a stale container (configuration), as the instance has been
created too early (to be able to clear itself).

Therefore we do now avoid instantiating the symfony container before the
container cache has been cleared.

A positive side effect of this change is that the container cache is
warmed up after the flush.

Releases: master
Resolves: #91114
Related: #90418
Change-Id: I5f10474ab3fab2d17cfdca6cd514b0a95f10bbbc
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/64234
Tested-by: Jonas Eberle <flightvision@googlemail.com>
Tested-by: TYPO3com <noreply@typo3.com>
Tested-by: Helmut Hummel <typo3@helhum.io>
Tested-by: Benjamin Franzke <bfr@qbus.de>
Reviewed-by: Susanne Moog <look@susi.dev>
Reviewed-by: Helmut Hummel <typo3@helhum.io>
Reviewed-by: Benjamin Franzke <bfr@qbus.de>
---
 .../Cache/ContainerBackend.php                |  5 ++++
 .../Classes/Service/ClearCacheService.php     | 25 ++++++++++++++-----
 .../install/Classes/ServiceProvider.php       |  3 ++-
 3 files changed, 26 insertions(+), 7 deletions(-)

diff --git a/typo3/sysext/core/Classes/DependencyInjection/Cache/ContainerBackend.php b/typo3/sysext/core/Classes/DependencyInjection/Cache/ContainerBackend.php
index b0feb97d2af1..0f5b1ea762e0 100644
--- a/typo3/sysext/core/Classes/DependencyInjection/Cache/ContainerBackend.php
+++ b/typo3/sysext/core/Classes/DependencyInjection/Cache/ContainerBackend.php
@@ -35,4 +35,9 @@ class ContainerBackend extends SimpleFileBackend
         parent::flush();
         parent::set($entryIdentifier, $data, $tags, $lifetime);
     }
+
+    public function forceFlush(): void
+    {
+        parent::flush();
+    }
 }
diff --git a/typo3/sysext/install/Classes/Service/ClearCacheService.php b/typo3/sysext/install/Classes/Service/ClearCacheService.php
index 9eba056caadc..a306b63e30a5 100644
--- a/typo3/sysext/install/Classes/Service/ClearCacheService.php
+++ b/typo3/sysext/install/Classes/Service/ClearCacheService.php
@@ -16,7 +16,9 @@
 namespace TYPO3\CMS\Install\Service;
 
 use TYPO3\CMS\Core\Cache\CacheManager;
+use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface;
 use TYPO3\CMS\Core\Database\ConnectionPool;
+use TYPO3\CMS\Core\DependencyInjection\Cache\ContainerBackend;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 
 /**
@@ -34,9 +36,17 @@ class ClearCacheService
      */
     private $lateBootService;
 
-    public function __construct(LateBootService $lateBootService)
-    {
+    /**
+     * @var FrontendInterface
+     */
+    private $dependencyInjectionCache;
+
+    public function __construct(
+        LateBootService $lateBootService,
+        FrontendInterface $dependencyInjectionCache
+    ) {
         $this->lateBootService = $lateBootService;
+        $this->dependencyInjectionCache = $dependencyInjectionCache;
     }
 
     /**
@@ -44,7 +54,7 @@ class ClearCacheService
      * Goal is to reliably get rid of cache entries, even if some broken
      * extension is loaded that would kill the backend 'clear cache' action.
      *
-     * Therefor this method "knows" implementation details of the cache
+     * Therefore this method "knows" implementation details of the cache
      * framework and uses them to clear all file based cache (typo3temp/Cache)
      * and database caches (tables prefixed with cf_) manually.
      *
@@ -66,9 +76,12 @@ class ClearCacheService
         $this->flushCaches($baseCaches);
 
         // Remove DI container cache (this might be removed in preference of functionality to rebuild this cache)
-        // We need to remove using the remove method because the DI cache backend disables the flush method
-        $container = $this->lateBootService->getContainer();
-        $container->get('cache.di')->remove(get_class($container));
+        if ($this->dependencyInjectionCache->getBackend() instanceof ContainerBackend) {
+            /** @var ContainerBackend $diCacheBackend */
+            $diCacheBackend = $this->dependencyInjectionCache->getBackend();
+            // We need to remove using the forceFlush method because the DI cache backend disables the flush method
+            $diCacheBackend->forceFlush();
+        }
 
         // From this point on, the code may fatal, if some broken extension is loaded.
         $this->lateBootService->loadExtLocalconfDatabaseAndExtTables();
diff --git a/typo3/sysext/install/Classes/ServiceProvider.php b/typo3/sysext/install/Classes/ServiceProvider.php
index 5226c5ffbf36..714c5671e736 100644
--- a/typo3/sysext/install/Classes/ServiceProvider.php
+++ b/typo3/sysext/install/Classes/ServiceProvider.php
@@ -107,7 +107,8 @@ class ServiceProvider extends AbstractServiceProvider
     public static function getClearCacheService(ContainerInterface $container): Service\ClearCacheService
     {
         return new Service\ClearCacheService(
-            $container->get(Service\LateBootService::class)
+            $container->get(Service\LateBootService::class),
+            $container->get('cache.di')
         );
     }
 
-- 
GitLab