From ea7102744d44e59a0fccee812dc48efb4bc0e4c3 Mon Sep 17 00:00:00 2001
From: Christian Kuhn <lolli@schwarzbu.ch>
Date: Sun, 28 Nov 2021 03:40:17 +0100
Subject: [PATCH] [!!!][TASK] Remove WincacheBackend cache backend
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Resolves: #96115
Related: #94665
Releases: master
Change-Id: Id7702f2328a0ca848656caae8350d6facc65068a
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/72336
Tested-by: Stefan Bürk <stefan@buerk.tech>
Tested-by: Wouter Wolters <typo3@wouterwolters.nl>
Tested-by: Benni Mack <benni@typo3.org>
Reviewed-by: Stefan Bürk <stefan@buerk.tech>
Reviewed-by: Wouter Wolters <typo3@wouterwolters.nl>
Reviewed-by: Benni Mack <benni@typo3.org>
---
 .../Classes/Cache/Backend/WincacheBackend.php | 263 -----------------
 ...g-96107-DeprecatedFunctionalityRemoved.rst |   1 +
 .../Cache/Backend/WincacheBackendTest.php     | 279 ------------------
 3 files changed, 1 insertion(+), 542 deletions(-)
 delete mode 100644 typo3/sysext/core/Classes/Cache/Backend/WincacheBackend.php
 delete mode 100644 typo3/sysext/core/Tests/UnitDeprecated/Cache/Backend/WincacheBackendTest.php

diff --git a/typo3/sysext/core/Classes/Cache/Backend/WincacheBackend.php b/typo3/sysext/core/Classes/Cache/Backend/WincacheBackend.php
deleted file mode 100644
index 025c105c0000..000000000000
--- a/typo3/sysext/core/Classes/Cache/Backend/WincacheBackend.php
+++ /dev/null
@@ -1,263 +0,0 @@
-<?php
-
-/*
- * 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 TYPO3\CMS\Core\Cache\Backend;
-
-use TYPO3\CMS\Core\Cache\Exception;
-use TYPO3\CMS\Core\Cache\Exception\InvalidDataException;
-use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface;
-
-/**
- * A caching backend which stores cache entries by using wincache.
- *
- * This backend uses the following types of keys:
- * - tag_xxx
- * xxx is tag name, value is array of associated identifiers identifier. This
- * is "forward" tag index. It is mainly used for obtaining content by tag
- * (get identifier by tag -> get content by identifier)
- * - ident_xxx
- * xxx is identifier, value is array of associated tags. This is "reverse" tag
- * index. It provides quick access for all tags associated with this identifier
- * and used when removing the identifier
- *
- * Each key is prepended with a prefix. By default prefix consists from two parts
- * separated by underscore character and ends in yet another underscore character:
- * - "TYPO3"
- * - MD5 of script path and filename and SAPI name
- * This prefix makes sure that keys from the different installations do not
- * conflict.
- *
- * @deprecated since v11, will be removed in v12. A substitution with similar characteristics is the ApcuBackend.
- */
-class WincacheBackend extends AbstractBackend implements TaggableBackendInterface
-{
-    /**
-     * A prefix to separate stored data from other data possible stored in the wincache
-     *
-     * @var string
-     */
-    protected $identifierPrefix;
-
-    /**
-     * Constructs this backend
-     *
-     * @param string $context Unused, for backward compatibility only
-     * @param array $options Configuration options
-     * @throws Exception If wincache PHP extension is not loaded
-     */
-    public function __construct($context, array $options = [])
-    {
-        if (!extension_loaded('wincache')) {
-            throw new Exception('The PHP extension "wincache" must be installed and loaded in order to use the wincache backend.', 1343331520);
-        }
-        trigger_error(__CLASS__ . ' will be removed in TYPO3 v12, use ApcuBackend as substitution with similar characteristics.', E_USER_DEPRECATED);
-        parent::__construct($context, $options);
-    }
-
-    /**
-     * Saves data in the cache
-     *
-     * @param string $entryIdentifier An identifier for this specific cache entry
-     * @param string $data The data to be stored
-     * @param array $tags Tags to associate with this cache entry
-     * @param int $lifetime Lifetime of this cache entry in seconds. If NULL is specified, the default lifetime is used. "0" means unlimited lifetime.
-     * @throws Exception if no cache frontend has been set
-     * @throws \InvalidArgumentException if the identifier is not valid
-     * @throws InvalidDataException if $data is not a string
-     */
-    public function set($entryIdentifier, $data, array $tags = [], $lifetime = null)
-    {
-        if (!$this->cache instanceof FrontendInterface) {
-            throw new Exception('No cache frontend has been set yet via setCache().', 1343331521);
-        }
-        if (!is_string($data)) {
-            throw new InvalidDataException('The specified data is of type "' . gettype($data) . '" but a string is expected.', 1343331522);
-        }
-        $tags[] = '%WCBE%' . $this->cache->getIdentifier();
-        $expiration = $lifetime ?? $this->defaultLifetime;
-        $success = wincache_ucache_set($this->identifierPrefix . $entryIdentifier, $data, $expiration);
-        if ($success === true) {
-            $this->removeIdentifierFromAllTags($entryIdentifier);
-            $this->addIdentifierToTags($entryIdentifier, $tags);
-        } else {
-            throw new Exception('Could not set value.', 1343331523);
-        }
-    }
-
-    /**
-     * Loads data from the cache
-     *
-     * @param string $entryIdentifier An identifier which describes the cache entry to load
-     * @return mixed The cache entry's content as a string or FALSE if the cache entry could not be loaded
-     */
-    public function get($entryIdentifier)
-    {
-        $success = false;
-        $value = wincache_ucache_get($this->identifierPrefix . $entryIdentifier, $success);
-        return $success ? $value : $success;
-    }
-
-    /**
-     * Checks if a cache entry with the specified identifier exists
-     *
-     * @param string $entryIdentifier An identifier specifying the cache entry
-     * @return bool TRUE if such an entry exists, FALSE if not
-     */
-    public function has($entryIdentifier)
-    {
-        return wincache_ucache_exists($this->identifierPrefix . $entryIdentifier);
-    }
-
-    /**
-     * Removes all cache entries matching the specified identifier.
-     * Usually this only affects one entry but if - for what reason ever -
-     * old entries for the identifier still exist, they are removed as well.
-     *
-     * @param string $entryIdentifier Specifies the cache entry to remove
-     * @return bool TRUE if (at least) an entry could be removed or FALSE if no entry was found
-     */
-    public function remove($entryIdentifier)
-    {
-        $this->removeIdentifierFromAllTags($entryIdentifier);
-        return wincache_ucache_delete($this->identifierPrefix . $entryIdentifier);
-    }
-
-    /**
-     * Finds and returns all cache entry identifiers which are tagged by the
-     * specified tag.
-     *
-     * @param string $tag The tag to search for
-     * @return array An array with identifiers of all matching entries. An empty array if no entries matched
-     */
-    public function findIdentifiersByTag($tag)
-    {
-        $success = false;
-        $identifiers = wincache_ucache_get($this->identifierPrefix . 'tag_' . $tag, $success);
-        if ($success === false) {
-            return [];
-        }
-        return (array)$identifiers;
-    }
-
-    /**
-     * Finds all tags for the given identifier. This function uses reverse tag
-     * index to search for tags.
-     *
-     * @param string $identifier Identifier to find tags by
-     * @return array Array with tags
-     */
-    protected function findTagsByIdentifier($identifier)
-    {
-        $success = false;
-        $tags = wincache_ucache_get($this->identifierPrefix . 'ident_' . $identifier, $success);
-        return $success ? (array)$tags : [];
-    }
-
-    /**
-     * Removes all cache entries of this cache
-     *
-     * @throws Exception
-     */
-    public function flush()
-    {
-        if (!$this->cache instanceof FrontendInterface) {
-            throw new Exception('Yet no cache frontend has been set via setCache().', 1343331524);
-        }
-        $this->flushByTag('%WCBE%' . $this->cache->getIdentifier());
-    }
-
-    /**
-     * Removes all cache entries of this cache which are tagged by the specified
-     * tag.
-     *
-     * @param string $tag The tag the entries must have
-     */
-    public function flushByTag($tag)
-    {
-        $identifiers = $this->findIdentifiersByTag($tag);
-        foreach ($identifiers as $identifier) {
-            $this->remove($identifier);
-        }
-    }
-
-    /**
-     * Associates the identifier with the given tags
-     *
-     * @param string $entryIdentifier
-     * @param array $tags
-     */
-    protected function addIdentifierToTags($entryIdentifier, array $tags)
-    {
-        // Get identifier-to-tag index to look for updates
-        $existingTags = $this->findTagsByIdentifier($entryIdentifier);
-        $existingTagsUpdated = false;
-
-        foreach ($tags as $tag) {
-            // Update tag-to-identifier index
-            $identifiers = $this->findIdentifiersByTag($tag);
-            if (!in_array($entryIdentifier, $identifiers, true)) {
-                $identifiers[] = $entryIdentifier;
-                wincache_ucache_set($this->identifierPrefix . 'tag_' . $tag, $identifiers);
-            }
-            // Test if identifier-to-tag index needs update
-            if (!in_array($tag, $existingTags, true)) {
-                $existingTags[] = $tag;
-                $existingTagsUpdated = true;
-            }
-        }
-
-        // Update identifier-to-tag index if needed
-        if ($existingTagsUpdated) {
-            wincache_ucache_set($this->identifierPrefix . 'ident_' . $entryIdentifier, $existingTags);
-        }
-    }
-
-    /**
-     * Removes association of the identifier with the given tags
-     *
-     * @param string $entryIdentifier
-     */
-    protected function removeIdentifierFromAllTags($entryIdentifier)
-    {
-        // Get tags for this identifier
-        $tags = $this->findTagsByIdentifier($entryIdentifier);
-        // Deassociate tags with this identifier
-        foreach ($tags as $tag) {
-            $identifiers = $this->findIdentifiersByTag($tag);
-            // Formally array_search() below should never return false due to
-            // the behavior of findTagsByIdentifier(). But if reverse index is
-            // corrupted, we still can get 'false' from array_search(). This is
-            // not a problem because we are removing this identifier from
-            // anywhere.
-            if (($key = array_search($entryIdentifier, $identifiers)) !== false) {
-                unset($identifiers[$key]);
-                if (!empty($identifiers)) {
-                    wincache_ucache_set($this->identifierPrefix . 'tag_' . $tag, $identifiers);
-                } else {
-                    wincache_ucache_delete($this->identifierPrefix . 'tag_' . $tag);
-                }
-            }
-        }
-        // Clear reverse tag index for this identifier
-        wincache_ucache_delete($this->identifierPrefix . 'ident_' . $entryIdentifier);
-    }
-
-    /**
-     * Does nothing, as wincache does GC itself
-     */
-    public function collectGarbage()
-    {
-    }
-}
diff --git a/typo3/sysext/core/Documentation/Changelog/12.0/Breaking-96107-DeprecatedFunctionalityRemoved.rst b/typo3/sysext/core/Documentation/Changelog/12.0/Breaking-96107-DeprecatedFunctionalityRemoved.rst
index ba0d0212d4d7..c01c5ada6689 100644
--- a/typo3/sysext/core/Documentation/Changelog/12.0/Breaking-96107-DeprecatedFunctionalityRemoved.rst
+++ b/typo3/sysext/core/Documentation/Changelog/12.0/Breaking-96107-DeprecatedFunctionalityRemoved.rst
@@ -12,6 +12,7 @@ Description
 The following PHP classes that have previously been marked as deprecated for v11 and were now removed:
 
 - :php:`\TYPO3\CMS\Core\Cache\Backend\PdoBackend`
+- :php:`\TYPO3\CMS\Core\Cache\Backend\WincacheBackend`
 - :php:`\TYPO3\CMS\Core\Database\QueryGenerator`
 - :php:`\TYPO3\CMS\Core\Database\QueryView`
 
diff --git a/typo3/sysext/core/Tests/UnitDeprecated/Cache/Backend/WincacheBackendTest.php b/typo3/sysext/core/Tests/UnitDeprecated/Cache/Backend/WincacheBackendTest.php
deleted file mode 100644
index 828a6119e447..000000000000
--- a/typo3/sysext/core/Tests/UnitDeprecated/Cache/Backend/WincacheBackendTest.php
+++ /dev/null
@@ -1,279 +0,0 @@
-<?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 TYPO3\CMS\Core\Tests\UnitDeprecated\Cache\Backend;
-
-use TYPO3\CMS\Core\Cache\Backend\WincacheBackend;
-use TYPO3\CMS\Core\Cache\Exception;
-use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface;
-use TYPO3\CMS\Core\Utility\StringUtility;
-use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
-
-/**
- * Testcase for the WinCache cache backend
- *
- * @requires extension wincache
- */
-class WincacheBackendTest extends UnitTestCase
-{
-    /**
-     * @test
-     */
-    public function setThrowsExceptionIfNoFrontEndHasBeenSet(): void
-    {
-        $this->expectException(Exception::class);
-        // @todo Add exception code with wincache extension
-
-        $backend = new WincacheBackend('Testing');
-        $data = 'Some data';
-        $identifier = StringUtility::getUniqueId('MyIdentifier');
-        $backend->set($identifier, $data);
-    }
-
-    /**
-     * @test
-     */
-    public function itIsPossibleToSetAndCheckExistenceInCache(): void
-    {
-        $backend = $this->setUpBackend();
-        $data = 'Some data';
-        $identifier = StringUtility::getUniqueId('MyIdentifier');
-        $backend->set($identifier, $data);
-        $inCache = $backend->has($identifier);
-        self::assertTrue($inCache, 'WinCache backend failed to set and check entry');
-    }
-
-    /**
-     * @test
-     */
-    public function itIsPossibleToSetAndGetEntry(): void
-    {
-        $backend = $this->setUpBackend();
-        $data = 'Some data';
-        $identifier = StringUtility::getUniqueId('MyIdentifier');
-        $backend->set($identifier, $data);
-        $fetchedData = $backend->get($identifier);
-        self::assertEquals($data, $fetchedData, 'Wincache backend failed to set and retrieve data');
-    }
-
-    /**
-     * @test
-     */
-    public function itIsPossibleToRemoveEntryFromCache(): void
-    {
-        $backend = $this->setUpBackend();
-        $data = 'Some data';
-        $identifier = StringUtility::getUniqueId('MyIdentifier');
-        $backend->set($identifier, $data);
-        $backend->remove($identifier);
-        $inCache = $backend->has($identifier);
-        self::assertFalse($inCache, 'Failed to set and remove data from WinCache backend');
-    }
-
-    /**
-     * @test
-     */
-    public function itIsPossibleToOverwriteAnEntryInTheCache(): void
-    {
-        $backend = $this->setUpBackend();
-        $data = 'Some data';
-        $identifier = StringUtility::getUniqueId('MyIdentifier');
-        $backend->set($identifier, $data);
-        $otherData = 'some other data';
-        $backend->set($identifier, $otherData);
-        $fetchedData = $backend->get($identifier);
-        self::assertEquals($otherData, $fetchedData, 'WinCache backend failed to overwrite and retrieve data');
-    }
-
-    /**
-     * @test
-     */
-    public function findIdentifiersByTagFindsSetEntries(): void
-    {
-        $backend = $this->setUpBackend();
-        $data = 'Some data';
-        $identifier = StringUtility::getUniqueId('MyIdentifier');
-        $backend->set($identifier, $data, ['UnitTestTag%tag1', 'UnitTestTag%tag2']);
-        $retrieved = $backend->findIdentifiersByTag('UnitTestTag%tag1');
-        self::assertEquals($identifier, $retrieved[0], 'Could not retrieve expected entry by tag.');
-        $retrieved = $backend->findIdentifiersByTag('UnitTestTag%tag2');
-        self::assertEquals($identifier, $retrieved[0], 'Could not retrieve expected entry by tag.');
-    }
-
-    /**
-     * @test
-     */
-    public function setRemovesTagsFromPreviousSet(): void
-    {
-        $backend = $this->setUpBackend();
-        $data = 'Some data';
-        $identifier = StringUtility::getUniqueId('MyIdentifier');
-        $backend->set($identifier, $data, ['UnitTestTag%tag1', 'UnitTestTag%tagX']);
-        $backend->set($identifier, $data, ['UnitTestTag%tag3']);
-        $retrieved = $backend->findIdentifiersByTag('UnitTestTag%tagX');
-        self::assertEquals([], $retrieved, 'Found entry which should no longer exist.');
-    }
-
-    /**
-     * @test
-     */
-    public function hasReturnsFalseIfTheEntryDoesntExist(): void
-    {
-        $backend = $this->setUpBackend();
-        $identifier = StringUtility::getUniqueId('NonExistingIdentifier');
-        $inCache = $backend->has($identifier);
-        self::assertFalse($inCache, '"has" did not return FALSE when checking on non existing identifier');
-    }
-
-    /**
-     * @test
-     */
-    public function removeReturnsFalseIfTheEntryDoesntExist(): void
-    {
-        $backend = $this->setUpBackend();
-        $identifier = StringUtility::getUniqueId('NonExistingIdentifier');
-        $inCache = $backend->remove($identifier);
-        self::assertFalse($inCache, '"remove" did not return FALSE when checking on non existing identifier');
-    }
-
-    /**
-     * @test
-     */
-    public function flushByTagRemovesCacheEntriesWithSpecifiedTag(): void
-    {
-        $backend = $this->setUpBackend();
-        $data = 'some data' . microtime();
-        $backend->set('BackendWincacheTest1', $data, ['UnitTestTag%test', 'UnitTestTag%boring']);
-        $backend->set('BackendWincacheTest2', $data, ['UnitTestTag%test', 'UnitTestTag%special']);
-        $backend->set('BackendWincacheTest3', $data, ['UnitTestTag%test']);
-        $backend->flushByTag('UnitTestTag%special');
-        self::assertTrue($backend->has('BackendWincacheTest1'), 'BackendWincacheTest1');
-        self::assertFalse($backend->has('BackendWincacheTest2'), 'BackendWincacheTest2');
-        self::assertTrue($backend->has('BackendWincacheTest3'), 'BackendWincacheTest3');
-    }
-
-    /**
-     * @test
-     */
-    public function flushByTagsRemovesCacheEntriesWithSpecifiedTags(): void
-    {
-        $backend = $this->setUpBackend();
-        $data = 'some data' . microtime();
-        $backend->set('BackendWincacheTest1', $data, ['UnitTestTag%test', 'UnitTestTag%boring']);
-        $backend->set('BackendWincacheTest2', $data, ['UnitTestTag%test', 'UnitTestTag%special']);
-        $backend->set('BackendWincacheTest3', $data, ['UnitTestTag%test']);
-        $backend->flushByTag('UnitTestTag%special', 'UnitTestTag%boring');
-        self::assertTrue($backend->has('BackendWincacheTest1'), 'BackendWincacheTest1');
-        self::assertFalse($backend->has('BackendWincacheTest2'), 'BackendWincacheTest2');
-        self::assertTrue($backend->has('BackendWincacheTest3'), 'BackendWincacheTest3');
-    }
-
-    /**
-     * @test
-     */
-    public function flushRemovesAllCacheEntries(): void
-    {
-        $backend = $this->setUpBackend();
-        $data = 'some data' . microtime();
-        $backend->set('BackendWincacheTest1', $data);
-        $backend->set('BackendWincacheTest2', $data);
-        $backend->set('BackendWincacheTest3', $data);
-        $backend->flush();
-        self::assertFalse($backend->has('BackendWincacheTest1'), 'BackendWincacheTest1');
-        self::assertFalse($backend->has('BackendWincacheTest2'), 'BackendWincacheTest2');
-        self::assertFalse($backend->has('BackendWincacheTest3'), 'BackendWincacheTest3');
-    }
-
-    /**
-     * @test
-     */
-    public function flushRemovesOnlyOwnEntries(): void
-    {
-        /** @var \PHPUnit\Framework\MockObject\MockObject|\TYPO3\CMS\Core\Cache\Frontend\FrontendInterface $thisCache */
-        $thisCache = $this->createMock(FrontendInterface::class);
-        $thisCache->method('getIdentifier')->willReturn('thisCache');
-        $thisBackend = new WincacheBackend('Testing');
-        $thisBackend->setCache($thisCache);
-
-        /** @var \PHPUnit\Framework\MockObject\MockObject|\TYPO3\CMS\Core\Cache\Frontend\FrontendInterface $thatCache */
-        $thatCache = $this->createMock(FrontendInterface::class);
-        $thatCache->method('getIdentifier')->willReturn('thatCache');
-        $thatBackend = new WincacheBackend('Testing');
-        $thatBackend->setCache($thatCache);
-        $thisBackend->set('thisEntry', 'Hello');
-        $thatBackend->set('thatEntry', 'World!');
-        $thatBackend->flush();
-        self::assertEquals('Hello', $thisBackend->get('thisEntry'));
-        self::assertFalse($thatBackend->has('thatEntry'));
-    }
-
-    /**
-     * Check if we can store ~5 MB of data
-     *
-     * @test
-     */
-    public function largeDataIsStored(): void
-    {
-        $backend = $this->setUpBackend();
-        $data = str_repeat('abcde', 1024 * 1024);
-        $identifier = StringUtility::getUniqueId('tooLargeData');
-        $backend->set($identifier, $data);
-        self::assertTrue($backend->has($identifier));
-        self::assertEquals($backend->get($identifier), $data);
-    }
-
-    /**
-     * @test
-     */
-    public function setTagsOnlyOnceToIdentifier(): void
-    {
-        $identifier = StringUtility::getUniqueId('MyIdentifier');
-        $tags = ['UnitTestTag%test', 'UnitTestTag%boring'];
-
-        $backend = $this->setUpBackend(true);
-        $backend->_call('addIdentifierToTags', $identifier, $tags);
-        self::assertSame(
-            $tags,
-            $backend->_call('findTagsByIdentifier', $identifier)
-        );
-
-        $backend->_call('addIdentifierToTags', $identifier, $tags);
-        self::assertSame(
-            $tags,
-            $backend->_call('findTagsByIdentifier', $identifier)
-        );
-    }
-
-    /**
-     * Sets up the WinCache backend used for testing
-     *
-     * @param bool $accessible TRUE if backend should be encapsulated in accessible proxy otherwise FALSE.
-     * @return \TYPO3\TestingFramework\Core\AccessibleObjectInterface|WincacheBackend
-     */
-    protected function setUpBackend(bool $accessible = false)
-    {
-        /** @var \PHPUnit\Framework\MockObject\MockObject|\TYPO3\CMS\Core\Cache\Frontend\FrontendInterface $cache */
-        $cache = $this->createMock(FrontendInterface::class);
-        if ($accessible) {
-            $backend = $this->getAccessibleMock(WincacheBackend::class, ['dummy'], ['Testing']);
-        } else {
-            $backend = new WincacheBackend('Testing');
-        }
-        $backend->setCache($cache);
-        return $backend;
-    }
-}
-- 
GitLab