diff --git a/core/core.services.yml b/core/core.services.yml index 3e2feb6..a666703 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -32,6 +32,15 @@ services: class: Drupal\Core\Cache\TimeZoneCacheContext tags: - { name: cache.context} + cache_tags: + class: Drupal\Core\Cache\CacheTagHandler + tags: + - { name: service_collector } + cache_tag_storage: + class: Drupal\Core\Cache\DatabaseCacheTagStorage + arguments: ['@database'] + tags: + - { name: cache_tags } cache.backend.chainedfast: class: Drupal\Core\Cache\ChainedFastBackendFactory arguments: ['@settings'] @@ -39,12 +48,16 @@ services: - [setContainer, ['@service_container']] cache.backend.database: class: Drupal\Core\Cache\DatabaseBackendFactory - arguments: ['@database'] + arguments: ['@database', '@cache_tag_storage'] cache.backend.apcu: class: Drupal\Core\Cache\ApcuBackendFactory arguments: ['@app.root'] + tags: + - { name: cache_tags } cache.backend.php: class: Drupal\Core\Cache\PhpBackendFactory + tags: + - { name: cache_tags } cache.bootstrap: class: Drupal\Core\Cache\CacheBackendInterface tags: @@ -98,6 +111,7 @@ services: class: Drupal\Core\Cache\CacheBackendInterface tags: - { name: cache.bin, default_backend: cache.backend.chainedfast } + - { name: cache_tags } factory_method: get factory_service: cache_factory arguments: [discovery] diff --git a/core/lib/Drupal/Core/Cache/ApcuBackendFactory.php b/core/lib/Drupal/Core/Cache/ApcuBackendFactory.php index ffe5993..dd77ed1 100644 --- a/core/lib/Drupal/Core/Cache/ApcuBackendFactory.php +++ b/core/lib/Drupal/Core/Cache/ApcuBackendFactory.php @@ -9,7 +9,7 @@ use \Drupal\Component\Utility\Crypt; -class ApcuBackendFactory implements CacheFactoryInterface { +class ApcuBackendFactory implements CacheFactoryInterface, CacheTagInvalidationInterface { /** * The site prefix string. @@ -41,4 +41,43 @@ public function get($bin) { return new ApcuBackend($bin, $this->sitePrefix); } + /** + * Deletes items with any of the specified tags. + * + * If the cache items are being deleted because they are no longer "fresh", + * you may consider using invalidateTags() instead. This allows callers to + * retrieve the invalid items by calling get() with $allow_invalid set to TRUE. + * In some cases an invalid item may be acceptable rather than having to + * rebuild the cache. + * + * @param array $tags + * Associative array of tags, in the same format that is passed to + * CacheBackendInterface::set(). + * + * @see \Drupal\Core\Cache\CacheBackendInterface::set() + * @see \Drupal\Core\Cache\CacheTagInvalidationInterface::invalidateTags() + * @see \Drupal\Core\Cache\CacheBackendInterface::delete() + * @see \Drupal\Core\Cache\CacheBackendInterface::deleteMultiple() + * @see \Drupal\Core\Cache\CacheBackendInterface::deleteAll() + */ + public function deleteTags(array $tags) { + // TODO: Implement deleteTags() method. + } + + /** + * Marks cache items with any of the specified tags as invalid. + * + * @param array $tags + * Associative array of tags, in the same format that is passed to + * CacheBackendInterface::set(). + * + * @see \Drupal\Core\Cache\CacheBackendInterface::set() + * @see \Drupal\Core\Cache\CacheTagInvalidationInterface::deleteTags() + * @see \Drupal\Core\Cache\CacheBackendInterface::invalidate() + * @see \Drupal\Core\Cache\CacheBackendInterface::invalidateMultiple() + * @see \Drupal\Core\Cache\CacheBackendInterface::invalidateAll() + */ + public function invalidateTags(array $tags) { + // TODO: Implement invalidateTags() method. + } } diff --git a/core/lib/Drupal/Core/Cache/Cache.php b/core/lib/Drupal/Core/Cache/Cache.php index ddf444e..b8e6cdc 100644 --- a/core/lib/Drupal/Core/Cache/Cache.php +++ b/core/lib/Drupal/Core/Cache/Cache.php @@ -96,41 +96,25 @@ public static function buildTags($prefix, array $suffixes) { /** * Deletes items from all bins with any of the specified tags. * - * Many sites have more than one active cache backend, and each backend may - * use a different strategy for storing tags against cache items, and - * deleting cache items associated with a given tag. - * - * When deleting a given list of tags, we iterate over each cache backend, and - * and call deleteTags() on each. - * * @param string[] $tags * The list of tags to delete cache items for. */ public static function deleteTags(array $tags) { + // @todo Move to service. static::validateTags($tags); - foreach (static::getBins() as $cache_backend) { - $cache_backend->deleteTags($tags); - } + \Drupal::service('cache_tags')->deleteTags($tags); } /** * Marks cache items from all bins with any of the specified tags as invalid. * - * Many sites have more than one active cache backend, and each backend my use - * a different strategy for storing tags against cache items, and invalidating - * cache items associated with a given tag. - * - * When invalidating a given list of tags, we iterate over each cache backend, - * and call invalidateTags() on each. - * * @param string[] $tags * The list of tags to invalidate cache items for. */ public static function invalidateTags(array $tags) { + // @todo Move to service. static::validateTags($tags); - foreach (static::getBins() as $cache_backend) { - $cache_backend->invalidateTags($tags); - } + \Drupal::service('cache_tags')->invalidateTags($tags); } /** diff --git a/core/lib/Drupal/Core/Cache/CacheBackendInterface.php b/core/lib/Drupal/Core/Cache/CacheBackendInterface.php index 39c8c26..fd1ae87 100644 --- a/core/lib/Drupal/Core/Cache/CacheBackendInterface.php +++ b/core/lib/Drupal/Core/Cache/CacheBackendInterface.php @@ -18,7 +18,7 @@ * * @ingroup cache */ -interface CacheBackendInterface { +interface CacheBackendInterface extends CacheTagInvalidationInterface { /** * Indicates that the item should never be removed unless explicitly deleted. @@ -161,27 +161,6 @@ public function delete($cid); public function deleteMultiple(array $cids); /** - * Deletes items with any of the specified tags. - * - * If the cache items are being deleted because they are no longer "fresh", - * you may consider using invalidateTags() instead. This allows callers to - * retrieve the invalid items by calling get() with $allow_invalid set to TRUE. - * In some cases an invalid item may be acceptable rather than having to - * rebuild the cache. - * - * @param array $tags - * Associative array of tags, in the same format that is passed to - * CacheBackendInterface::set(). - * - * @see \Drupal\Core\Cache\CacheBackendInterface::set() - * @see \Drupal\Core\Cache\CacheBackendInterface::invalidateTags() - * @see \Drupal\Core\Cache\CacheBackendInterface::delete() - * @see \Drupal\Core\Cache\CacheBackendInterface::deleteMultiple() - * @see \Drupal\Core\Cache\CacheBackendInterface::deleteAll() - */ - public function deleteTags(array $tags); - - /** * Deletes all cache items in a bin. * * @see \Drupal\Core\Cache\CacheBackendInterface::invalidateAll() @@ -224,21 +203,6 @@ public function invalidate($cid); public function invalidateMultiple(array $cids); /** - * Marks cache items with any of the specified tags as invalid. - * - * @param array $tags - * Associative array of tags, in the same format that is passed to - * CacheBackendInterface::set(). - * - * @see \Drupal\Core\Cache\CacheBackendInterface::set() - * @see \Drupal\Core\Cache\CacheBackendInterface::deleteTags() - * @see \Drupal\Core\Cache\CacheBackendInterface::invalidate() - * @see \Drupal\Core\Cache\CacheBackendInterface::invalidateMultiple() - * @see \Drupal\Core\Cache\CacheBackendInterface::invalidateAll() - */ - public function invalidateTags(array $tags); - - /** * Marks all cache items as invalid. * * Invalid items may be returned in later calls to get(), if the $allow_invalid diff --git a/core/lib/Drupal/Core/Cache/CacheTagHandler.php b/core/lib/Drupal/Core/Cache/CacheTagHandler.php new file mode 100644 index 0000000..d439954 --- /dev/null +++ b/core/lib/Drupal/Core/Cache/CacheTagHandler.php @@ -0,0 +1,38 @@ +invalidators as $invalidator) { + $invalidator->invalidateTags($tags); + } + } + + public function deleteTags(array $tags) { + foreach ($this->invalidators as $invalidator) { + $invalidator->deleteTags($tags); + } + } + + public function addHandler(CacheTagInvalidationInterface $service) { + $this->invalidators[] = $service; + } + +} diff --git a/core/lib/Drupal/Core/Cache/CacheTagHandlerInterface.php b/core/lib/Drupal/Core/Cache/CacheTagHandlerInterface.php new file mode 100644 index 0000000..288e04b --- /dev/null +++ b/core/lib/Drupal/Core/Cache/CacheTagHandlerInterface.php @@ -0,0 +1,31 @@ +bin = $bin; $this->connection = $connection; + $this->cacheTagStorage = $cacheTagStorage; } /** @@ -174,8 +184,8 @@ public function set($cid, $data, $expire = Cache::PERMANENT, array $tags = array * Actually set the cache. */ protected function doSet($cid, $data, $expire, $tags) { - $deleted_tags = &drupal_static('Drupal\Core\Cache\DatabaseBackend::deletedTags', array()); - $invalidated_tags = &drupal_static('Drupal\Core\Cache\DatabaseBackend::invalidatedTags', array()); + $deleted_tags = &drupal_static('Drupal\Core\Cache\DatabaseCacheTagStorage::deletedTags', array()); + $invalidated_tags = &drupal_static('Drupal\Core\Cache\DatabaseCacheTagStorage::invalidatedTags', array()); // Remove tags that were already deleted or invalidated during this request // from the static caches so that another deletion or invalidation can // occur. @@ -215,8 +225,8 @@ protected function doSet($cid, $data, $expire, $tags) { * {@inheritdoc} */ public function setMultiple(array $items) { - $deleted_tags = &drupal_static('Drupal\Core\Cache\DatabaseBackend::deletedTags', array()); - $invalidated_tags = &drupal_static('Drupal\Core\Cache\DatabaseBackend::invalidatedTags', array()); + $deleted_tags = &drupal_static('Drupal\Core\Cache\DatabaseCacheTagStorage::deletedTags', array()); + $invalidated_tags = &drupal_static('Drupal\Core\Cache\DatabaseCacheTagStorage::invalidatedTags', array()); // Use a transaction so that the database can write the changes in a single // commit. @@ -319,28 +329,7 @@ public function deleteMultiple(array $cids) { /** * Implements Drupal\Core\Cache\CacheBackendInterface::deleteTags(). */ - public function deleteTags(array $tags) { - $tag_cache = &drupal_static('Drupal\Core\Cache\CacheBackendInterface::tagCache', array()); - $deleted_tags = &drupal_static('Drupal\Core\Cache\DatabaseBackend::deletedTags', array()); - foreach ($tags as $tag) { - // Only delete tags once per request unless they are written again. - if (isset($deleted_tags[$tag])) { - continue; - } - $deleted_tags[$tag] = TRUE; - unset($tag_cache[$tag]); - try { - $this->connection->merge('cachetags') - ->insertFields(array('deletions' => 1)) - ->expression('deletions', 'deletions + 1') - ->key('tag', $tag) - ->execute(); - } - catch (\Exception $e) { - $this->catchException($e, 'cachetags'); - } - } - } + public function deleteTags(array $tags) {} /** * Implements Drupal\Core\Cache\CacheBackendInterface::deleteAll(). @@ -386,30 +375,9 @@ public function invalidateMultiple(array $cids) { } /** - * Implements Drupal\Core\Cache\CacheBackendInterface::invalidateTags(). + * Implements Drupal\Core\Cache\CacheTagHandlerInterface::invalidateTags(). */ - public function invalidateTags(array $tags) { - try { - $tag_cache = &drupal_static('Drupal\Core\Cache\CacheBackendInterface::tagCache', array()); - $invalidated_tags = &drupal_static('Drupal\Core\Cache\DatabaseBackend::invalidatedTags', array()); - foreach ($tags as $tag) { - // Only invalidate tags once per request unless they are written again. - if (isset($invalidated_tags[$tag])) { - continue; - } - $invalidated_tags[$tag] = TRUE; - unset($tag_cache[$tag]); - $this->connection->merge('cachetags') - ->insertFields(array('invalidations' => 1)) - ->expression('invalidations', 'invalidations + 1') - ->key('tag', $tag) - ->execute(); - } - } - catch (\Exception $e) { - $this->catchException($e, 'cachetags'); - } - } + public function invalidateTags(array $tags) {} /** * Implements Drupal\Core\Cache\CacheBackendInterface::invalidateAll(). @@ -452,7 +420,7 @@ public function garbageCollection() { * Sum of all invalidations. */ protected function checksumTags(array $tags) { - $tag_cache = &drupal_static('Drupal\Core\Cache\CacheBackendInterface::tagCache', array()); + $tag_cache = &drupal_static('Drupal\Core\Cache\DatabaseCacheTagStorage::tagCache', array()); $checksum = array( 'invalidations' => 0, @@ -516,14 +484,16 @@ protected function ensureBinExists() { /** * Act on an exception when cache might be stale. * - * If the {cachetags} table does not yet exist, that's fine but if the table + * If the table does not yet exist, that's fine, but if the table * exists and yet the query failed, then the cache is stale and the * exception needs to propagate. * * @param $e * The exception. * @param string|null $table_name - * The table name, defaults to $this->bin. Can be cachetags. + * The table name. Defaults to $this->bin. + * + * @throws \Exception */ protected function catchException(\Exception $e, $table_name = NULL) { if ($this->connection->schema()->tableExists($table_name ?: $this->bin)) { diff --git a/core/lib/Drupal/Core/Cache/DatabaseBackendFactory.php b/core/lib/Drupal/Core/Cache/DatabaseBackendFactory.php index 1d70164..2772bab 100644 --- a/core/lib/Drupal/Core/Cache/DatabaseBackendFactory.php +++ b/core/lib/Drupal/Core/Cache/DatabaseBackendFactory.php @@ -23,8 +23,9 @@ class DatabaseBackendFactory implements CacheFactoryInterface { * * @param \Drupal\Core\Database\Connection $connection */ - function __construct(Connection $connection) { + function __construct(Connection $connection, CacheTagInvalidationStorageInterface $cacheTagStorage) { $this->connection = $connection; + $this->cacheTagStorage = $cacheTagStorage; } /** @@ -37,7 +38,7 @@ function __construct(Connection $connection) { * The cache backend object for the specified cache bin. */ function get($bin) { - return new DatabaseBackend($this->connection, $bin); + return new DatabaseBackend($this->connection, $this->cacheTagStorage, $bin); } } diff --git a/core/lib/Drupal/Core/Cache/DatabaseCacheTagStorage.php b/core/lib/Drupal/Core/Cache/DatabaseCacheTagStorage.php new file mode 100644 index 0000000..0a9259c --- /dev/null +++ b/core/lib/Drupal/Core/Cache/DatabaseCacheTagStorage.php @@ -0,0 +1,123 @@ +connection = $connection; + } + + /** + * Stores cache tag invalidations. + * + * @param string[] $tags + * The list of tags for which to store invalidations. + */ + public function invalidateTags(array $tags) { + try { + $tag_cache = &drupal_static('Drupal\Core\Cache\DatabaseCacheTagStorage::tagCache', array()); + $invalidated_tags = &drupal_static('Drupal\Core\Cache\DatabaseCacheTagStorage::invalidatedTags', array()); + foreach ($tags as $tag) { + // Only invalidate tags once per request unless they are written again. + if (isset($invalidated_tags[$tag])) { + continue; + } + $invalidated_tags[$tag] = TRUE; + unset($tag_cache[$tag]); + $this->connection->merge('cachetags') + ->insertFields(array('invalidations' => 1)) + ->expression('invalidations', 'invalidations + 1') + ->key('tag', $tag) + ->execute(); + } + } + catch (\Exception $e) { + $this->catchException($e, 'cachetags'); + } + } + + /** + * Stores cache tag deletions. + * + * @param string[] $tags + * The list of tags for which to store deletions. + */ + public function deleteTags(array $tags) { + $tag_cache = &drupal_static('Drupal\Core\Cache\DatabaseCacheTagStorage::tagCache', array()); + $deleted_tags = &drupal_static('Drupal\Core\Cache\DatabaseCacheTagStorage::deletedTags', array()); + foreach ($tags as $tag) { + // Only delete tags once per request unless they are written again. + if (isset($deleted_tags[$tag])) { + continue; + } + $deleted_tags[$tag] = TRUE; + unset($tag_cache[$tag]); + try { + $this->connection->merge('cachetags') + ->insertFields(array('deletions' => 1)) + ->expression('deletions', 'deletions + 1') + ->key('tag', $tag) + ->execute(); + } + catch (\Exception $e) { + $this->catchException($e); + } + } + } + + /** + * {@inheritdoc} + */ + public function getTagInvalidations() { + + } + + /** + * {@inheritdoc} + */ + public function getTagDeletions() { + + } + + /** + * Act on an exception when cache might be stale. + * + * If the {cachetags} table does not yet exist, that's fine but if the table + * exists and yet the query failed, then the cache is stale and the + * exception needs to propagate. + * + * @param \Exception $e + * The exception. + * + * @throws \Exception + */ + protected function catchException(\Exception $e) { + if ($this->connection->schema()->tableExists('cachetags')) { + throw $e; + } + } +} diff --git a/core/lib/Drupal/Core/Cache/MemoryBackendFactory.php b/core/lib/Drupal/Core/Cache/MemoryBackendFactory.php index c9e288d..6783720 100644 --- a/core/lib/Drupal/Core/Cache/MemoryBackendFactory.php +++ b/core/lib/Drupal/Core/Cache/MemoryBackendFactory.php @@ -7,13 +7,40 @@ namespace Drupal\Core\Cache; -class MemoryBackendFactory implements CacheFactoryInterface { +class MemoryBackendFactory implements CacheFactoryInterface, CacheTagInvalidationInterface { + + /** + * Instantiated memory cache bins. + * + * @var \Drupal\Core\Cache\MemoryBackend[] + */ + protected $bins = array(); /** * {@inheritdoc} */ function get($bin) { - return new MemoryBackend($bin); + if (!isset($this->bins[$bin])) { + $this->bins[$bin] = new MemoryBackend($bin); + } + return $this->bins[$bin]; } + /** + * {@inheritdoc} + */ + public function deleteTags(array $tags) { + foreach ($this->bins as $bin) { + $bin->deleteTags($tags); + } + } + + /** + * {@inheritdoc} + */ + public function invalidateTags(array $tags) { + foreach ($this->bins as $bin) { + $bin->deleteTags($tags); + } + } } diff --git a/core/lib/Drupal/Core/Cache/NullBackend.php b/core/lib/Drupal/Core/Cache/NullBackend.php index d27bc13..fb898de 100644 --- a/core/lib/Drupal/Core/Cache/NullBackend.php +++ b/core/lib/Drupal/Core/Cache/NullBackend.php @@ -70,7 +70,7 @@ public function deleteMultiple(array $cids) {} public function deleteAll() {} /** - * Implements Drupal\Core\Cache\CacheBackendInterface::deleteTags(). + * Implements Drupal\Core\Cache\CacheTagInvalidationInterface::deleteTags(). */ public function deleteTags(array $tags) {} @@ -85,7 +85,7 @@ public function invalidate($cid) {} public function invalidateMultiple(array $cids) {} /** - * Implements Drupal\Core\Cache\CacheBackendInterface::invalidateTags(). + * Implements Drupal\Core\Cache\CacheTagInvalidationInterface::invalidateTags(). */ public function invalidateTags(array $tags) {} diff --git a/core/lib/Drupal/Core/Cache/NullBackendFactory.php b/core/lib/Drupal/Core/Cache/NullBackendFactory.php index 0101a8e..b1d9365 100644 --- a/core/lib/Drupal/Core/Cache/NullBackendFactory.php +++ b/core/lib/Drupal/Core/Cache/NullBackendFactory.php @@ -7,7 +7,7 @@ namespace Drupal\Core\Cache; -class NullBackendFactory implements CacheFactoryInterface { +class NullBackendFactory implements CacheFactoryInterface, CacheTagInvalidationInterface { /** * {@inheritdoc} @@ -16,4 +16,43 @@ function get($bin) { return new NullBackend($bin); } + /** + * Deletes items with any of the specified tags. + * + * If the cache items are being deleted because they are no longer "fresh", + * you may consider using invalidateTags() instead. This allows callers to + * retrieve the invalid items by calling get() with $allow_invalid set to TRUE. + * In some cases an invalid item may be acceptable rather than having to + * rebuild the cache. + * + * @param array $tags + * Associative array of tags, in the same format that is passed to + * CacheBackendInterface::set(). + * + * @see \Drupal\Core\Cache\CacheBackendInterface::set() + * @see \Drupal\Core\Cache\CacheTagInvalidationInterface::invalidateTags() + * @see \Drupal\Core\Cache\CacheBackendInterface::delete() + * @see \Drupal\Core\Cache\CacheBackendInterface::deleteMultiple() + * @see \Drupal\Core\Cache\CacheBackendInterface::deleteAll() + */ + public function deleteTags(array $tags) { + // TODO: Implement deleteTags() method. + } + + /** + * Marks cache items with any of the specified tags as invalid. + * + * @param array $tags + * Associative array of tags, in the same format that is passed to + * CacheBackendInterface::set(). + * + * @see \Drupal\Core\Cache\CacheBackendInterface::set() + * @see \Drupal\Core\Cache\CacheTagInvalidationInterface::deleteTags() + * @see \Drupal\Core\Cache\CacheBackendInterface::invalidate() + * @see \Drupal\Core\Cache\CacheBackendInterface::invalidateMultiple() + * @see \Drupal\Core\Cache\CacheBackendInterface::invalidateAll() + */ + public function invalidateTags(array $tags) { + // TODO: Implement invalidateTags() method. + } } diff --git a/core/lib/Drupal/Core/Cache/NullCacheTagHandler.php b/core/lib/Drupal/Core/Cache/NullCacheTagHandler.php new file mode 100644 index 0000000..76b4c41 --- /dev/null +++ b/core/lib/Drupal/Core/Cache/NullCacheTagHandler.php @@ -0,0 +1,30 @@ +invalidators[] = $service; + } + +} diff --git a/core/lib/Drupal/Core/Cache/PhpBackendFactory.php b/core/lib/Drupal/Core/Cache/PhpBackendFactory.php index 0801b72..872bf16 100644 --- a/core/lib/Drupal/Core/Cache/PhpBackendFactory.php +++ b/core/lib/Drupal/Core/Cache/PhpBackendFactory.php @@ -7,7 +7,7 @@ namespace Drupal\Core\Cache; -class PhpBackendFactory implements CacheFactoryInterface { +class PhpBackendFactory implements CacheFactoryInterface, CacheTagInvalidationInterface { /** * Gets PhpBackend for the specified cache bin. @@ -22,4 +22,43 @@ function get($bin) { return new PhpBackend($bin); } + /** + * Deletes items with any of the specified tags. + * + * If the cache items are being deleted because they are no longer "fresh", + * you may consider using invalidateTags() instead. This allows callers to + * retrieve the invalid items by calling get() with $allow_invalid set to TRUE. + * In some cases an invalid item may be acceptable rather than having to + * rebuild the cache. + * + * @param array $tags + * Associative array of tags, in the same format that is passed to + * CacheBackendInterface::set(). + * + * @see \Drupal\Core\Cache\CacheBackendInterface::set() + * @see \Drupal\Core\Cache\CacheTagInvalidationInterface::invalidateTags() + * @see \Drupal\Core\Cache\CacheBackendInterface::delete() + * @see \Drupal\Core\Cache\CacheBackendInterface::deleteMultiple() + * @see \Drupal\Core\Cache\CacheBackendInterface::deleteAll() + */ + public function deleteTags(array $tags) { + // TODO: Implement deleteTags() method. + } + + /** + * Marks cache items with any of the specified tags as invalid. + * + * @param array $tags + * Associative array of tags, in the same format that is passed to + * CacheBackendInterface::set(). + * + * @see \Drupal\Core\Cache\CacheBackendInterface::set() + * @see \Drupal\Core\Cache\CacheTagInvalidationInterface::deleteTags() + * @see \Drupal\Core\Cache\CacheBackendInterface::invalidate() + * @see \Drupal\Core\Cache\CacheBackendInterface::invalidateMultiple() + * @see \Drupal\Core\Cache\CacheBackendInterface::invalidateAll() + */ + public function invalidateTags(array $tags) { + // TODO: Implement invalidateTags() method. + } } diff --git a/core/lib/Drupal/Core/Installer/InstallerServiceProvider.php b/core/lib/Drupal/Core/Installer/InstallerServiceProvider.php index 6e93561..af823f7 100644 --- a/core/lib/Drupal/Core/Installer/InstallerServiceProvider.php +++ b/core/lib/Drupal/Core/Installer/InstallerServiceProvider.php @@ -48,6 +48,8 @@ public function register(ContainerBuilder $container) { ->addArgument(new Reference('request_stack')); $container ->register('router.dumper', 'Drupal\Core\Routing\NullMatcherDumper'); + $container + ->register('cache_tags', 'Drupal\Core\Cache\NullCacheTagHandler'); // Replace the route builder with an empty implementation. // @todo Convert installer steps into routes; add an installer.routing.yml. diff --git a/core/modules/config/src/Tests/Storage/CachedStorageTest.php b/core/modules/config/src/Tests/Storage/CachedStorageTest.php index 11c3599..2d4e464 100644 --- a/core/modules/config/src/Tests/Storage/CachedStorageTest.php +++ b/core/modules/config/src/Tests/Storage/CachedStorageTest.php @@ -90,7 +90,8 @@ public function containerBuild(ContainerBuilder $container) { parent::containerBuild($container); // Use the regular database cache backend to aid testing. $container->register('cache_factory', 'Drupal\Core\Cache\DatabaseBackendFactory') - ->addArgument(new Reference('database')); + ->addArgument(new Reference('database')) + ->addArgument(new Reference('cache_tag_storage')); } } diff --git a/core/modules/locale/src/Tests/LocaleTranslationUiTest.php b/core/modules/locale/src/Tests/LocaleTranslationUiTest.php index e9919cd..1cb8de7 100644 --- a/core/modules/locale/src/Tests/LocaleTranslationUiTest.php +++ b/core/modules/locale/src/Tests/LocaleTranslationUiTest.php @@ -137,7 +137,7 @@ public function testStringTranslation() { // Reset the tag cache on the tester side in order to pick up the call to // Cache::deleteTags() on the tested side. - drupal_static_reset('Drupal\Core\Cache\CacheBackendInterface::tagCache'); + drupal_static_reset('Drupal\Core\Cache\DatabaseCacheTagStorage::tagCache'); $this->assertTrue($name != $translation && t($name, array(), array('langcode' => $langcode)) == $translation, 't() works for non-English.'); // Refresh the locale() cache to get fresh data from t() below. We are in diff --git a/core/modules/simpletest/src/KernelTestBase.php b/core/modules/simpletest/src/KernelTestBase.php index f26c5d4..7abd200 100644 --- a/core/modules/simpletest/src/KernelTestBase.php +++ b/core/modules/simpletest/src/KernelTestBase.php @@ -256,7 +256,8 @@ public function containerBuild(ContainerBuilder $container) { $this->container->setParameter('language.default_values', Language::$defaultValues); $container->register('lock', 'Drupal\Core\Lock\NullLockBackend'); - $container->register('cache_factory', 'Drupal\Core\Cache\MemoryBackendFactory'); + $container->register('cache_factory', 'Drupal\Core\Cache\MemoryBackendFactory') + ->addTag('cache_tags'); $container ->register('config.storage', 'Drupal\Core\Config\DatabaseStorage') diff --git a/core/modules/simpletest/src/WebTestBase.php b/core/modules/simpletest/src/WebTestBase.php index d2b31ae..92d7de9 100644 --- a/core/modules/simpletest/src/WebTestBase.php +++ b/core/modules/simpletest/src/WebTestBase.php @@ -1151,9 +1151,9 @@ protected function refreshVariables() { // @todo Replace drupal_static() usage within classes and provide a // proper interface for invoking reset() on a cache backend: // https://www.drupal.org/node/2311945. - drupal_static_reset('Drupal\Core\Cache\CacheBackendInterface::tagCache'); - drupal_static_reset('Drupal\Core\Cache\DatabaseBackend::deletedTags'); - drupal_static_reset('Drupal\Core\Cache\DatabaseBackend::invalidatedTags'); + drupal_static_reset('Drupal\Core\Cache\DatabaseCacheTagStorage::tagCache'); + drupal_static_reset('Drupal\Core\Cache\DatabaseCacheTagStorage::deletedTags'); + drupal_static_reset('Drupal\Core\Cache\DatabaseCacheTagStorage::invalidatedTags'); foreach (Cache::getBins() as $backend) { if (is_callable(array($backend, 'reset'))) { $backend->reset(); diff --git a/core/tests/Drupal/Tests/Core/Cache/CacheCollectorTest.php b/core/tests/Drupal/Tests/Core/Cache/CacheCollectorTest.php index cf5b3f1..d8744d8 100644 --- a/core/tests/Drupal/Tests/Core/Cache/CacheCollectorTest.php +++ b/core/tests/Drupal/Tests/Core/Cache/CacheCollectorTest.php @@ -48,7 +48,7 @@ class CacheCollectorTest extends UnitTestCase { * {@inheritdoc} */ protected function setUp() { - $this->cache = $this->getMock('Drupal\Core\Cache\CacheBackendInterface'); + $this->cache = $this->getMock('Drupal\Core\Cache\CacheTagHandlerInterface'); $this->lock = $this->getMock('Drupal\Core\Lock\LockBackendInterface'); $this->cid = $this->randomMachineName(); $this->collector = new CacheCollectorHelper($this->cid, $this->cache, $this->lock); diff --git a/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityBaseUnitTest.php b/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityBaseUnitTest.php index 2da84fe..02ce8b5 100644 --- a/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityBaseUnitTest.php +++ b/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityBaseUnitTest.php @@ -79,9 +79,9 @@ class ConfigEntityBaseUnitTest extends UnitTestCase { /** * The mocked cache backend. * - * @var \Drupal\Core\Cache\CacheBackendInterface|\PHPUnit_Framework_MockObject_MockObject + * @var \Drupal\Core\Cache\cacheTagHandlerInterface|\PHPUnit_Framework_MockObject_MockObject */ - protected $cacheBackend; + protected $cacheTagHandler; /** * The mocked typed config manager. @@ -121,7 +121,7 @@ protected function setUp() { ->with('en') ->will($this->returnValue(new Language(array('id' => 'en')))); - $this->cacheBackend = $this->getMock('Drupal\Core\Cache\CacheBackendInterface'); + $this->cacheTagHandler = $this->getMock('Drupal\Core\Cache\CacheTagHandlerInterface'); $this->typedConfigManager = $this->getMock('Drupal\Core\Config\TypedConfigManagerInterface'); @@ -129,9 +129,8 @@ protected function setUp() { $container->set('entity.manager', $this->entityManager); $container->set('uuid', $this->uuid); $container->set('language_manager', $this->languageManager); - $container->set('cache.test', $this->cacheBackend); + $container->set('cache_tags', $this->cacheTagHandler); $container->set('config.typed', $this->typedConfigManager); - $container->setParameter('cache_bins', array('cache.test' => 'test')); \Drupal::setContainer($container); $this->entity = $this->getMockForAbstractClass('\Drupal\Core\Config\Entity\ConfigEntityBase', array($values, $this->entityTypeId)); @@ -361,7 +360,7 @@ public function testEnable() { * @depends testSetStatus */ public function testDisable() { - $this->cacheBackend->expects($this->once()) + $this->cacheTagHandler->expects($this->once()) ->method('invalidateTags') ->with(array($this->entityTypeId . ':' . $this->id)); diff --git a/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityStorageTest.php b/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityStorageTest.php index ddfbd81..bf7ca84 100644 --- a/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityStorageTest.php +++ b/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityStorageTest.php @@ -85,9 +85,9 @@ class ConfigEntityStorageTest extends UnitTestCase { /** * The mocked cache backend. * - * @var \Drupal\Core\Cache\CacheBackendInterface|\PHPUnit_Framework_MockObject_MockObject + * @var \Drupal\Core\Cache\cacheTagHandlerInterface|\PHPUnit_Framework_MockObject_MockObject */ - protected $cacheBackend; + protected $cacheTagHandler; /** * The mocked typed config manager. @@ -153,7 +153,7 @@ protected function setUp() { ->with('test_entity_type') ->will($this->returnValue($this->entityType)); - $this->cacheBackend = $this->getMock('Drupal\Core\Cache\CacheBackendInterface'); + $this->cacheTagHandler = $this->getMock('Drupal\Core\Cache\CacheTagHandlerInterface'); $this->typedConfigManager = $this->getMock('Drupal\Core\Config\TypedConfigManagerInterface'); $this->typedConfigManager->expects($this->any()) @@ -162,8 +162,7 @@ protected function setUp() { $container = new ContainerBuilder(); $container->set('entity.manager', $this->entityManager); $container->set('config.typed', $this->typedConfigManager); - $container->set('cache.test', $this->cacheBackend); - $container->setParameter('cache_bins', array('cache.test' => 'test')); + $container->set('cache_tags', $this->cacheTagHandler); \Drupal::setContainer($container); } @@ -173,7 +172,7 @@ protected function setUp() { * @covers ::doCreate */ public function testCreateWithPredefinedUuid() { - $this->cacheBackend->expects($this->never()) + $this->cacheTagHandler->expects($this->never()) ->method('invalidateTags'); $this->moduleHandler->expects($this->at(0)) @@ -198,7 +197,7 @@ public function testCreateWithPredefinedUuid() { * @return \Drupal\Core\Entity\EntityInterface */ public function testCreate() { - $this->cacheBackend->expects($this->never()) + $this->cacheTagHandler->expects($this->never()) ->method('invalidateTags'); $this->moduleHandler->expects($this->at(0)) @@ -240,7 +239,7 @@ public function testSaveInsert(EntityInterface $entity) { $config_object->expects($this->once()) ->method('save'); - $this->cacheBackend->expects($this->once()) + $this->cacheTagHandler->expects($this->once()) ->method('invalidateTags') ->with(array( $this->entityTypeId . '_list', // List cache tag. @@ -299,7 +298,7 @@ public function testSaveUpdate(EntityInterface $entity) { $config_object->expects($this->once()) ->method('save'); - $this->cacheBackend->expects($this->once()) + $this->cacheTagHandler->expects($this->once()) ->method('invalidateTags') ->with(array( $this->entityTypeId . ':foo', // Own cache tag. @@ -359,7 +358,7 @@ public function testSaveRename(ConfigEntityInterface $entity) { $config_object->expects($this->once()) ->method('save'); - $this->cacheBackend->expects($this->once()) + $this->cacheTagHandler->expects($this->once()) ->method('invalidateTags') ->with(array( $this->entityTypeId .':bar', // Own cache tag. @@ -403,7 +402,7 @@ public function testSaveRename(ConfigEntityInterface $entity) { * @expectedExceptionMessage The entity does not have an ID. */ public function testSaveInvalid() { - $this->cacheBackend->expects($this->never()) + $this->cacheTagHandler->expects($this->never()) ->method('invalidateTags'); $entity = $this->getMockEntity(); @@ -428,7 +427,7 @@ public function testSaveDuplicate() { $config_object->expects($this->never()) ->method('save'); - $this->cacheBackend->expects($this->never()) + $this->cacheTagHandler->expects($this->never()) ->method('invalidateTags'); $this->configFactory->expects($this->once()) @@ -459,7 +458,7 @@ public function testSaveMismatch() { $config_object->expects($this->never()) ->method('save'); - $this->cacheBackend->expects($this->never()) + $this->cacheTagHandler->expects($this->never()) ->method('invalidateTags'); $this->configFactory->expects($this->once()) @@ -492,7 +491,7 @@ public function testSaveNoMismatch() { $config_object->expects($this->once()) ->method('save'); - $this->cacheBackend->expects($this->once()) + $this->cacheTagHandler->expects($this->once()) ->method('invalidateTags') ->with(array( $this->entityTypeId . '_list', // List cache tag. @@ -542,7 +541,7 @@ public function testSaveChangedUuid() { array('id', 'foo'), ))); - $this->cacheBackend->expects($this->never()) + $this->cacheTagHandler->expects($this->never()) ->method('invalidateTags'); $this->configFactory->expects($this->at(1)) @@ -699,7 +698,7 @@ public function testLoadRevision() { * @covers ::deleteRevision */ public function testDeleteRevision() { - $this->cacheBackend->expects($this->never()) + $this->cacheTagHandler->expects($this->never()) ->method('invalidateTags'); $this->assertSame(NULL, $this->entityStorage->deleteRevision(1)); @@ -725,7 +724,7 @@ public function testDelete() { $config_map[] = array("the_config_prefix.$id", $config_object); } - $this->cacheBackend->expects($this->once()) + $this->cacheTagHandler->expects($this->once()) ->method('invalidateTags') ->with(array( $this->entityTypeId . ':bar', // Own cache tag. @@ -775,7 +774,7 @@ public function testDeleteNothing() { $this->configFactory->expects($this->never()) ->method('get'); - $this->cacheBackend->expects($this->never()) + $this->cacheTagHandler->expects($this->never()) ->method('invalidateTags'); $this->entityStorage->delete(array()); diff --git a/core/tests/Drupal/Tests/Core/Entity/EntityManagerTest.php b/core/tests/Drupal/Tests/Core/Entity/EntityManagerTest.php index 933b7ed..beaa312 100644 --- a/core/tests/Drupal/Tests/Core/Entity/EntityManagerTest.php +++ b/core/tests/Drupal/Tests/Core/Entity/EntityManagerTest.php @@ -120,6 +120,7 @@ protected function setUp() { ->will($this->returnValue(array())); $this->cache = $this->getMock('Drupal\Core\Cache\CacheBackendInterface'); + $cache_tag_handler = $this->getMock('Drupal\Core\Cache\CacheTagHandlerInterface'); $language = $this->getMock('Drupal\Core\Language\LanguageInterface'); $language->expects($this->any()) @@ -139,7 +140,7 @@ protected function setUp() { $this->formBuilder = $this->getMock('Drupal\Core\Form\FormBuilderInterface'); $this->controllerResolver = $this->getClassResolverStub(); - $this->container = $this->getContainerWithCacheBins($this->cache); + $this->container = $this->getContainerWithCacheBins($cache_tag_handler); $this->discovery = $this->getMock('Drupal\Component\Plugin\Discovery\DiscoveryInterface'); diff --git a/core/tests/Drupal/Tests/Core/Entity/EntityUnitTest.php b/core/tests/Drupal/Tests/Core/Entity/EntityUnitTest.php index 6535732..c512fb1 100644 --- a/core/tests/Drupal/Tests/Core/Entity/EntityUnitTest.php +++ b/core/tests/Drupal/Tests/Core/Entity/EntityUnitTest.php @@ -75,9 +75,9 @@ class EntityUnitTest extends UnitTestCase { /** * The mocked cache backend. * - * @var \Drupal\Core\Cache\CacheBackendInterface|\PHPUnit_Framework_MockObject_MockObject + * @var \Drupal\Core\Cache\cacheTagHandlerInterface|\PHPUnit_Framework_MockObject_MockObject */ - protected $cacheBackend; + protected $cacheTagHandler; /** * The entity values. @@ -116,14 +116,13 @@ protected function setUp() { ->with('en') ->will($this->returnValue(new Language(array('id' => 'en')))); - $this->cacheBackend = $this->getMock('Drupal\Core\Cache\CacheBackendInterface'); + $this->cacheTagHandler = $this->getMock('Drupal\Core\Cache\CacheTagHandler'); $container = new ContainerBuilder(); $container->set('entity.manager', $this->entityManager); $container->set('uuid', $this->uuid); $container->set('language_manager', $this->languageManager); - $container->set('cache.test', $this->cacheBackend); - $container->setParameter('cache_bins', array('cache.test' => 'test')); + $container->set('cache_tags', $this->cacheTagHandler); \Drupal::setContainer($container); $this->entity = $this->getMockForAbstractClass('\Drupal\Core\Entity\Entity', array($this->values, $this->entityTypeId)); @@ -393,12 +392,12 @@ public function testPreSave() { * @covers ::postSave */ public function testPostSave() { - $this->cacheBackend->expects($this->at(0)) + $this->cacheTagHandler->expects($this->at(0)) ->method('invalidateTags') ->with(array( $this->entityTypeId . '_list', // List cache tag. )); - $this->cacheBackend->expects($this->at(1)) + $this->cacheTagHandler->expects($this->at(1)) ->method('invalidateTags') ->with(array( $this->entityTypeId . ':' . $this->values['id'], // Own cache tag. @@ -450,7 +449,7 @@ public function testPreDelete() { * @covers ::postDelete */ public function testPostDelete() { - $this->cacheBackend->expects($this->once()) + $this->cacheTagHandler->expects($this->once()) ->method('invalidateTags') ->with(array( $this->entityTypeId . ':' . $this->values['id'], diff --git a/core/tests/Drupal/Tests/Core/Entity/KeyValueStore/KeyValueEntityStorageTest.php b/core/tests/Drupal/Tests/Core/Entity/KeyValueStore/KeyValueEntityStorageTest.php index ee10e54..a79b9c3 100644 --- a/core/tests/Drupal/Tests/Core/Entity/KeyValueStore/KeyValueEntityStorageTest.php +++ b/core/tests/Drupal/Tests/Core/Entity/KeyValueStore/KeyValueEntityStorageTest.php @@ -70,9 +70,9 @@ class KeyValueEntityStorageTest extends UnitTestCase { /** * The mocked cache backend. * - * @var \Drupal\Core\Cache\CacheBackendInterface|\PHPUnit_Framework_MockObject_MockObject + * @var \Drupal\Core\Cache\cacheTagHandlerInterface|\PHPUnit_Framework_MockObject_MockObject */ - protected $cacheBackend; + protected $cacheTagHandler; /** * {@inheritdoc} @@ -110,7 +110,7 @@ protected function setUpKeyValueEntityStorage($uuid_key = 'uuid') { ->with('test_entity_type') ->will($this->returnValue($this->entityType)); - $this->cacheBackend = $this->getMock('Drupal\Core\Cache\CacheBackendInterface'); + $this->cacheTagHandler = $this->getMock('Drupal\Core\Cache\CacheTagHandlerInterface'); $this->keyValueStore = $this->getMock('Drupal\Core\KeyValueStore\KeyValueStoreInterface'); $this->moduleHandler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface'); @@ -130,8 +130,7 @@ protected function setUpKeyValueEntityStorage($uuid_key = 'uuid') { $container = new ContainerBuilder(); $container->set('entity.manager', $this->entityManager); $container->set('language_manager', $this->languageManager); - $container->set('cache.test', $this->cacheBackend); - $container->setParameter('cache_bins', array('cache.test' => 'test')); + $container->set('cache_tags', $this->cacheTagHandler); \Drupal::setContainer($container); } diff --git a/core/tests/Drupal/Tests/Core/Extension/ThemeHandlerTest.php b/core/tests/Drupal/Tests/Core/Extension/ThemeHandlerTest.php index 0a58e81..89ed10c 100644 --- a/core/tests/Drupal/Tests/Core/Extension/ThemeHandlerTest.php +++ b/core/tests/Drupal/Tests/Core/Extension/ThemeHandlerTest.php @@ -121,7 +121,7 @@ protected function setUp() { $logger = $this->getMock('Psr\Log\LoggerInterface'); $this->themeHandler = new TestThemeHandler($this->root, $this->configFactory, $this->moduleHandler, $this->state, $this->infoParser, $logger, $this->cssCollectionOptimizer, $this->configInstaller, $this->configManager, $this->routeBuilderIndicator, $this->extensionDiscovery); - $cache_backend = $this->getMock('Drupal\Core\Cache\CacheBackendInterface'); + $cache_backend = $this->getMock('Drupal\Core\Cache\CacheTagHandlerInterface'); $this->getContainerWithCacheBins($cache_backend); } diff --git a/core/tests/Drupal/Tests/Core/Plugin/DefaultPluginManagerTest.php b/core/tests/Drupal/Tests/Core/Plugin/DefaultPluginManagerTest.php index c2ef841..e9bd4ce 100644 --- a/core/tests/Drupal/Tests/Core/Plugin/DefaultPluginManagerTest.php +++ b/core/tests/Drupal/Tests/Core/Plugin/DefaultPluginManagerTest.php @@ -190,7 +190,7 @@ public function testDefaultPluginManagerWithFilledCache() { */ public function testCacheClearWithTags() { $cid = $this->randomMachineName(); - $cache_backend = $this->getMockBuilder('Drupal\Core\Cache\MemoryBackend') + $cache_backend = $this->getMockBuilder('Drupal\Core\Cache\CacheTagHandlerInterface') ->disableOriginalConstructor() ->getMock(); $cache_backend diff --git a/core/tests/Drupal/Tests/UnitTestCase.php b/core/tests/Drupal/Tests/UnitTestCase.php index 43748e8..268dadd 100644 --- a/core/tests/Drupal/Tests/UnitTestCase.php +++ b/core/tests/Drupal/Tests/UnitTestCase.php @@ -8,8 +8,7 @@ namespace Drupal\Tests; use Drupal\Component\Utility\Random; -use Drupal\Component\Utility\String; -use Drupal\Core\Cache\CacheBackendInterface; +use Drupal\Core\Cache\CacheTagHandlerInterface; use Drupal\Core\DependencyInjection\ContainerBuilder; /** @@ -199,22 +198,18 @@ public function getStringTranslationStub() { /** * Sets up a container with cache bins. * - * @param \Drupal\Core\Cache\CacheBackendInterface $backend + * @param \Drupal\Core\Cache\CacheTagHandlerInterface $cache_tags_handler * The cache backend to set up. * * @return \Symfony\Component\DependencyInjection\ContainerInterface|\PHPUnit_Framework_MockObject_MockObject * The container with the cache bins set up. */ - protected function getContainerWithCacheBins(CacheBackendInterface $backend) { + protected function getContainerWithCacheBins(CacheTagHandlerInterface $cache_tags_handler) { $container = $this->getMock('Symfony\Component\DependencyInjection\ContainerInterface'); $container->expects($this->any()) - ->method('getParameter') - ->with('cache_bins') - ->will($this->returnValue(array('cache.test' => 'test'))); - $container->expects($this->any()) ->method('get') - ->with('cache.test') - ->will($this->returnValue($backend)); + ->with('cache_tags') + ->will($this->returnValue($cache_tags_handler)); \Drupal::setContainer($container); return $container; diff --git a/sites/development.services.yml b/sites/development.services.yml index cc21211..75c5f44 100644 --- a/sites/development.services.yml +++ b/sites/development.services.yml @@ -5,5 +5,9 @@ services: cache.backend.memory: class: Drupal\Core\Cache\MemoryBackendFactory + tags: + - { name: cache_tags } cache.backend.null: class: Drupal\Core\Cache\NullBackendFactory + tags: + - { name: cache_tags }