diff --git a/core/lib/Drupal/Component/Plugin/Discovery/DerivativeDiscoveryDecorator.php b/core/lib/Drupal/Component/Plugin/Discovery/DerivativeDiscoveryDecorator.php index 6b47af0171..4bc2cbb180 100644 --- a/core/lib/Drupal/Component/Plugin/Discovery/DerivativeDiscoveryDecorator.php +++ b/core/lib/Drupal/Component/Plugin/Discovery/DerivativeDiscoveryDecorator.php @@ -3,6 +3,7 @@ namespace Drupal\Component\Plugin\Discovery; use Drupal\Component\Plugin\Definition\DerivablePluginDefinitionInterface; +use Drupal\Component\Plugin\Derivative\DeriverInterface; use Drupal\Component\Plugin\Exception\InvalidDeriverException; /** @@ -61,6 +62,7 @@ public function getDefinition($plugin_id, $exception_on_invalid = TRUE) { $deriver = $this->getDeriver($base_plugin_id, $base_plugin_definition); if ($deriver) { $derivative_plugin_definition = $deriver->getDerivativeDefinition($derivative_id, $base_plugin_definition); + $this->processDeriver($deriver); // If a plugin defined itself as a derivative, merge in possible // defaults from the derivative. if ($derivative_id && isset($plugin_definition)) { @@ -75,6 +77,13 @@ public function getDefinition($plugin_id, $exception_on_invalid = TRUE) { return $plugin_definition; } + /** + * Allows subclasses to provide additional processing for the deriver. + */ + protected function processDeriver(DeriverInterface $deriver) { + // Intentionally empty. + } + /** * {@inheritdoc} * @@ -99,6 +108,7 @@ protected function getDerivatives(array $base_plugin_definitions) { $deriver = $this->getDeriver($base_plugin_id, $plugin_definition); if ($deriver) { $derivative_definitions = $deriver->getDerivativeDefinitions($plugin_definition); + $this->processDeriver($deriver); foreach ($derivative_definitions as $derivative_id => $derivative_definition) { $plugin_id = $this->encodePluginId($base_plugin_id, $derivative_id); // Use this definition as defaults if a plugin already defined diff --git a/core/lib/Drupal/Core/Cache/CacheableDependencyTrait.php b/core/lib/Drupal/Core/Cache/CacheableDependencyTrait.php index 19cb0f2b76..a485a7f6c5 100644 --- a/core/lib/Drupal/Core/Cache/CacheableDependencyTrait.php +++ b/core/lib/Drupal/Core/Cache/CacheableDependencyTrait.php @@ -64,4 +64,84 @@ public function getCacheMaxAge() { return $this->cacheMaxAge; } + /** + * Adds cache contexts. + * + * @param string[] $cache_contexts + * The cache contexts to be added. + * + * @return $this + * + * @see \Drupal\Core\Cache\RefinableCacheableDependencyInterface::addCacheContexts() + */ + protected function addCacheContexts(array $cache_contexts) { + if ($cache_contexts) { + $this->cacheContexts = Cache::mergeContexts($this->cacheContexts, $cache_contexts); + } + return $this; + } + + /** + * Adds cache tags. + * + * @param string[] $cache_tags + * The cache tags to be added. + * + * @return $this + * + * @see \Drupal\Core\Cache\RefinableCacheableDependencyInterface::addCacheTags() + */ + protected function addCacheTags(array $cache_tags) { + if ($cache_tags) { + $this->cacheTags = Cache::mergeTags($this->cacheTags, $cache_tags); + } + return $this; + } + + /** + * Merges the maximum age (in seconds) with the existing maximum age. + * + * The max age will be set to the given value if it is lower than the existing + * value. + * + * @param int $max_age + * The max age to associate. + * + * @return $this + * + * @throws \InvalidArgumentException + * Thrown if a non-integer value is supplied. + * + * @see \Drupal\Core\Cache\RefinableCacheableDependencyInterface::mergeCacheMaxAge() + */ + protected function mergeCacheMaxAge($max_age) { + $this->cacheMaxAge = Cache::mergeMaxAges($this->cacheMaxAge, $max_age); + return $this; + } + + /** + * Adds a dependency on an object: merges its cacheability metadata. + * + * @param \Drupal\Core\Cache\CacheableDependencyInterface|object $other_object + * The dependency. If the object implements CacheableDependencyInterface, + * then its cacheability metadata will be used. Otherwise, the passed in + * object must be assumed to be uncacheable, so max-age 0 is set. + * + * @return $this + * + * @see \Drupal\Core\Cache\RefinableCacheableDependencyInterface::addCacheableDependency() + */ + protected function addCacheableDependency($other_object) { + if ($other_object instanceof CacheableDependencyInterface) { + $this->addCacheContexts($other_object->getCacheContexts()); + $this->addCacheTags($other_object->getCacheTags()); + $this->mergeCacheMaxAge($other_object->getCacheMaxAge()); + } + else { + // Not a cacheable dependency, this can not be cached. + $this->cacheMaxAge = 0; + } + return $this; + } + } diff --git a/core/lib/Drupal/Core/Cache/RefinableCacheableDependencyTrait.php b/core/lib/Drupal/Core/Cache/RefinableCacheableDependencyTrait.php index fcbc11f8d1..6de21967bf 100644 --- a/core/lib/Drupal/Core/Cache/RefinableCacheableDependencyTrait.php +++ b/core/lib/Drupal/Core/Cache/RefinableCacheableDependencyTrait.php @@ -7,50 +7,39 @@ */ trait RefinableCacheableDependencyTrait { - use CacheableDependencyTrait; + use CacheableDependencyTrait { + addCacheableDependency as traitAddCacheableDependency; + addCacheContexts as traitAddCacheContexts; + addCacheTags as traitAddCacheTags; + mergeCacheMaxAge as traitMergeCacheMaxAge; + } /** * {@inheritdoc} */ public function addCacheableDependency($other_object) { - if ($other_object instanceof CacheableDependencyInterface) { - $this->addCacheContexts($other_object->getCacheContexts()); - $this->addCacheTags($other_object->getCacheTags()); - $this->mergeCacheMaxAge($other_object->getCacheMaxAge()); - } - else { - // Not a cacheable dependency, this can not be cached. - $this->cacheMaxAge = 0; - } - return $this; + return $this->traitAddCacheableDependency($other_object); } /** * {@inheritdoc} */ public function addCacheContexts(array $cache_contexts) { - if ($cache_contexts) { - $this->cacheContexts = Cache::mergeContexts($this->cacheContexts, $cache_contexts); - } - return $this; + return $this->traitAddCacheContexts($cache_contexts); } /** * {@inheritdoc} */ public function addCacheTags(array $cache_tags) { - if ($cache_tags) { - $this->cacheTags = Cache::mergeTags($this->cacheTags, $cache_tags); - } - return $this; + return $this->traitAddCacheTags($cache_tags); } /** * {@inheritdoc} */ public function mergeCacheMaxAge($max_age) { - $this->cacheMaxAge = Cache::mergeMaxAges($this->cacheMaxAge, $max_age); - return $this; + return $this->traitMergeCacheMaxAge($max_age); } } diff --git a/core/lib/Drupal/Core/Entity/EntityFieldManager.php b/core/lib/Drupal/Core/Entity/EntityFieldManager.php index 88186c6706..7036323590 100644 --- a/core/lib/Drupal/Core/Entity/EntityFieldManager.php +++ b/core/lib/Drupal/Core/Entity/EntityFieldManager.php @@ -3,6 +3,8 @@ namespace Drupal\Core\Entity; use Drupal\Core\Cache\Cache; +use Drupal\Core\Cache\CacheableDependencyInterface; +use Drupal\Core\Cache\CacheableDependencyTrait; use Drupal\Core\Cache\CacheBackendInterface; use Drupal\Core\Cache\UseCacheBackendTrait; use Drupal\Core\Extension\ModuleHandlerInterface; @@ -18,8 +20,9 @@ * This includes field definitions, base field definitions, and field storage * definitions. */ -class EntityFieldManager implements EntityFieldManagerInterface { +class EntityFieldManager implements EntityFieldManagerInterface, CacheableDependencyInterface { + use CacheableDependencyTrait; use UseCacheBackendTrait; use StringTranslationTrait; @@ -169,7 +172,7 @@ public function getBaseFieldDefinitions($entity_type_id) { else { // Rebuild the definitions and put it into the cache. $this->baseFieldDefinitions[$entity_type_id] = $this->buildBaseFieldDefinitions($entity_type_id); - $this->cacheSet($cid, $this->baseFieldDefinitions[$entity_type_id], Cache::PERMANENT, ['entity_types', 'entity_field_info']); + $this->cacheSet($cid, $this->baseFieldDefinitions[$entity_type_id], Cache::PERMANENT, Cache::mergeTags($this->getCacheTags(), $this->getEntityTypeManagerCacheTags())); } } return $this->baseFieldDefinitions[$entity_type_id]; @@ -327,7 +330,7 @@ public function getFieldDefinitions($entity_type_id, $bundle) { else { // Rebuild the definitions and put it into the cache. $bundle_field_definitions = $this->buildBundleFieldDefinitions($entity_type_id, $bundle, $base_field_definitions); - $this->cacheSet($cid, $bundle_field_definitions, Cache::PERMANENT, ['entity_types', 'entity_field_info']); + $this->cacheSet($cid, $bundle_field_definitions, Cache::PERMANENT, Cache::mergeTags($this->getEntityTypeManagerCacheTags(), $this->getCacheTags())); } // Field definitions consist of the bundle specific overrides and the // base fields, merge them together. Use array_replace() to replace base @@ -435,7 +438,7 @@ public function getFieldStorageDefinitions($entity_type_id) { else { // Rebuild the definitions and put it into the cache. $field_storage_definitions = $this->buildFieldStorageDefinitions($entity_type_id); - $this->cacheSet($cid, $field_storage_definitions, Cache::PERMANENT, ['entity_types', 'entity_field_info']); + $this->cacheSet($cid, $field_storage_definitions, Cache::PERMANENT, Cache::mergeTags($this->getEntityTypeManagerCacheTags(), $this->getCacheTags())); } $this->fieldStorageDefinitions[$entity_type_id] += $field_storage_definitions; } @@ -497,7 +500,7 @@ public function getFieldMap() { } } - $this->cacheSet($cid, $this->fieldMap, Cache::PERMANENT, ['entity_types', 'entity_field_info']); + $this->cacheSet($cid, $this->fieldMap, Cache::PERMANENT, Cache::mergeTags($this->getEntityTypeManagerCacheTags(), $this->getCacheTags())); } } return $this->fieldMap; @@ -570,7 +573,7 @@ public function clearCachedFieldDefinitions() { $this->fieldMapByFieldType = []; $this->entityDisplayRepository->clearDisplayModeInfo(); $this->extraFields = []; - Cache::invalidateTags(['entity_field_info']); + Cache::invalidateTags($this->getCacheTags()); // The typed data manager statically caches prototype objects with injected // definitions, clear those as well. $this->typedDataManager->clearCachedDefinitions(); @@ -617,11 +620,26 @@ public function getExtraFields($entity_type_id, $bundle) { // Store in the 'static' and persistent caches. $this->extraFields[$entity_type_id][$bundle] = $info; - $this->cacheSet($cache_id, $info, Cache::PERMANENT, [ - 'entity_field_info', - ]); + $this->cacheSet($cache_id, $info, Cache::PERMANENT, $this->getCacheTags()); return $this->extraFields[$entity_type_id][$bundle]; } + /** + * {@inheritdoc} + */ + public function getCacheTags() { + return ['entity_field_info']; + } + + /** + * Gets the cache tags from the entity type manager. + * + * @return string[] + * A set of cache tags. + */ + protected function getEntityTypeManagerCacheTags() { + return ($this->entityTypeManager instanceof CacheableDependencyInterface) ? $this->entityTypeManager->getCacheTags() : []; + } + } diff --git a/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php b/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php index c74fcbe958..f25a897f01 100644 --- a/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php +++ b/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php @@ -5,8 +5,9 @@ use Drupal\Component\Assertion\Inspector; use Drupal\Component\Plugin\Definition\PluginDefinitionInterface; use Drupal\Component\Plugin\Discovery\CachedDiscoveryInterface; -use Drupal\Core\Cache\CacheableDependencyInterface; use Drupal\Core\Cache\CacheBackendInterface; +use Drupal\Core\Cache\RefinableCacheableDependencyInterface; +use Drupal\Core\Cache\RefinableCacheableDependencyTrait; use Drupal\Core\Cache\UseCacheBackendTrait; use Drupal\Component\Plugin\Discovery\DiscoveryCachedTrait; use Drupal\Core\Plugin\Discovery\ContainerDerivativeDiscoveryDecorator; @@ -23,9 +24,10 @@ * * @ingroup plugin_api */ -class DefaultPluginManager extends PluginManagerBase implements PluginManagerInterface, CachedDiscoveryInterface, CacheableDependencyInterface { +class DefaultPluginManager extends PluginManagerBase implements PluginManagerInterface, CachedDiscoveryInterface, RefinableCacheableDependencyInterface { use DiscoveryCachedTrait; + use RefinableCacheableDependencyTrait; use UseCacheBackendTrait; /** @@ -282,6 +284,11 @@ protected function getFactory() { */ protected function findDefinitions() { $definitions = $this->getDiscovery()->getDefinitions(); + + // Add the discovery as a dependency after retrieving the definitions so + // that derivers have the opportunity to run and add their own dependencies. + $this->addCacheableDependency($this->getDiscovery()); + foreach ($definitions as $plugin_id => &$definition) { $this->processDefinition($definition, $plugin_id); } diff --git a/core/lib/Drupal/Core/Plugin/Discovery/ContainerDerivativeDiscoveryDecorator.php b/core/lib/Drupal/Core/Plugin/Discovery/ContainerDerivativeDiscoveryDecorator.php index f6908b66e9..400fa1eb1c 100644 --- a/core/lib/Drupal/Core/Plugin/Discovery/ContainerDerivativeDiscoveryDecorator.php +++ b/core/lib/Drupal/Core/Plugin/Discovery/ContainerDerivativeDiscoveryDecorator.php @@ -2,14 +2,19 @@ namespace Drupal\Core\Plugin\Discovery; +use Drupal\Component\Plugin\Derivative\DeriverInterface; use Drupal\Component\Plugin\Discovery\DerivativeDiscoveryDecorator; +use Drupal\Core\Cache\CacheableDependencyInterface; +use Drupal\Core\Cache\CacheableDependencyTrait; /** * Injects dependencies into derivers if they use ContainerDeriverInterface. * * @see \Drupal\Core\Plugin\Discovery\ContainerDeriverInterface */ -class ContainerDerivativeDiscoveryDecorator extends DerivativeDiscoveryDecorator { +class ContainerDerivativeDiscoveryDecorator extends DerivativeDiscoveryDecorator implements CacheableDependencyInterface { + + use CacheableDependencyTrait; /** * {@inheritdoc} @@ -32,4 +37,11 @@ protected function getDeriver($base_plugin_id, $base_definition) { return $this->derivers[$base_plugin_id] ?: NULL; } + /** + * {@inheritdoc} + */ + protected function processDeriver(DeriverInterface $deriver) { + $this->addCacheableDependency($deriver); + } + } diff --git a/core/modules/block_content/src/Entity/BlockContent.php b/core/modules/block_content/src/Entity/BlockContent.php index 1037beeef5..001d4babcd 100644 --- a/core/modules/block_content/src/Entity/BlockContent.php +++ b/core/modules/block_content/src/Entity/BlockContent.php @@ -116,31 +116,6 @@ public function getTheme() { return $this->theme; } - /** - * {@inheritdoc} - */ - public function postSave(EntityStorageInterface $storage, $update = TRUE) { - parent::postSave($storage, $update); - if ($this->isReusable() || (isset($this->original) && $this->original->isReusable())) { - static::invalidateBlockPluginCache(); - } - } - - /** - * {@inheritdoc} - */ - public static function postDelete(EntityStorageInterface $storage, array $entities) { - parent::postDelete($storage, $entities); - /** @var \Drupal\block_content\BlockContentInterface $block */ - foreach ($entities as $block) { - if ($block->isReusable()) { - // If any deleted blocks are reusable clear the block cache. - static::invalidateBlockPluginCache(); - return; - } - } - } - /** * {@inheritdoc} */ @@ -322,12 +297,4 @@ public function setNonReusable() { return $this->set('reusable', FALSE); } - /** - * Invalidates the block plugin cache after changes and deletions. - */ - protected static function invalidateBlockPluginCache() { - // Invalidate the block cache to update custom block-based derivatives. - \Drupal::service('plugin.manager.block')->clearCachedDefinitions(); - } - } diff --git a/core/modules/block_content/src/Plugin/Block/BlockContentBlock.php b/core/modules/block_content/src/Plugin/Block/BlockContentBlock.php index 6ca88d198a..c56c96c59a 100644 --- a/core/modules/block_content/src/Plugin/Block/BlockContentBlock.php +++ b/core/modules/block_content/src/Plugin/Block/BlockContentBlock.php @@ -164,9 +164,7 @@ public function blockForm($form, FormStateInterface $form_state) { * {@inheritdoc} */ public function blockSubmit($form, FormStateInterface $form_state) { - // Invalidate the block cache to update custom block-based derivatives. $this->configuration['view_mode'] = $form_state->getValue('view_mode'); - $this->blockManager->clearCachedDefinitions(); } /** diff --git a/core/modules/block_content/src/Plugin/Derivative/BlockContent.php b/core/modules/block_content/src/Plugin/Derivative/BlockContent.php index ba1ab98968..a187c0edd2 100644 --- a/core/modules/block_content/src/Plugin/Derivative/BlockContent.php +++ b/core/modules/block_content/src/Plugin/Derivative/BlockContent.php @@ -3,6 +3,8 @@ namespace Drupal\block_content\Plugin\Derivative; use Drupal\Component\Plugin\Derivative\DeriverBase; +use Drupal\Core\Cache\CacheableDependencyInterface; +use Drupal\Core\Cache\CacheableDependencyTrait; use Drupal\Core\Entity\EntityStorageInterface; use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -10,7 +12,9 @@ /** * Retrieves block plugin definitions for all custom blocks. */ -class BlockContent extends DeriverBase implements ContainerDeriverInterface { +class BlockContent extends DeriverBase implements ContainerDeriverInterface, CacheableDependencyInterface { + + use CacheableDependencyTrait; /** * The custom block storage. @@ -27,6 +31,8 @@ class BlockContent extends DeriverBase implements ContainerDeriverInterface { */ public function __construct(EntityStorageInterface $block_content_storage) { $this->blockContentStorage = $block_content_storage; + + $this->addCacheTags($this->blockContentStorage->getEntityType()->getListCacheTags()); } /** diff --git a/core/modules/block_content/tests/src/Kernel/BlockContentDeletionTest.php b/core/modules/block_content/tests/src/Kernel/BlockContentDeletionTest.php index d91e1d826c..169ab87b27 100644 --- a/core/modules/block_content/tests/src/Kernel/BlockContentDeletionTest.php +++ b/core/modules/block_content/tests/src/Kernel/BlockContentDeletionTest.php @@ -55,6 +55,13 @@ public function testDeletingBlockContentShouldClearPluginCache() { // Now delete the block content entity. $block_content->delete(); + + // While the persistent cache is cleared, the static cache must be manually + // reset within the same request. + $property = new \ReflectionProperty($block_manager, 'definitions'); + $property->setAccessible(TRUE); + $property->setValue($block_manager, NULL); + // The plugin should no longer exist. $this->assertFalse($block_manager->hasDefinition($plugin_id)); } diff --git a/core/modules/block_content/tests/src/Kernel/BlockContentDeriverTest.php b/core/modules/block_content/tests/src/Kernel/BlockContentDeriverTest.php index c18dd9aa7d..0d7dd156f8 100644 --- a/core/modules/block_content/tests/src/Kernel/BlockContentDeriverTest.php +++ b/core/modules/block_content/tests/src/Kernel/BlockContentDeriverTest.php @@ -57,6 +57,12 @@ public function testReusableBlocksOnlyAreDerived() { $block_content->setNonReusable(); $block_content->save(); + // While the persistent cache is cleared, the static cache must be manually + // reset within the same request. + $property = new \ReflectionProperty($block_manager, 'definitions'); + $property->setAccessible(TRUE); + $property->setValue($block_manager, NULL); + // Ensure the non-reusable block content is not provided a derivative block // plugin. $this->assertFalse($block_manager->hasDefinition($plugin_id)); diff --git a/core/modules/layout_builder/layout_builder.module b/core/modules/layout_builder/layout_builder.module index 5d7c60615c..8a9853b2a1 100644 --- a/core/modules/layout_builder/layout_builder.module +++ b/core/modules/layout_builder/layout_builder.module @@ -76,7 +76,6 @@ function layout_builder_field_config_insert(FieldConfigInterface $field_config) // Clear the sample entity for this entity type and bundle. $sample_entity_generator = \Drupal::service('layout_builder.sample_entity_generator'); $sample_entity_generator->delete($field_config->getTargetEntityTypeId(), $field_config->getTargetBundle()); - \Drupal::service('plugin.manager.block')->clearCachedDefinitions(); } /** @@ -86,7 +85,6 @@ function layout_builder_field_config_delete(FieldConfigInterface $field_config) // Clear the sample entity for this entity type and bundle. $sample_entity_generator = \Drupal::service('layout_builder.sample_entity_generator'); $sample_entity_generator->delete($field_config->getTargetEntityTypeId(), $field_config->getTargetBundle()); - \Drupal::service('plugin.manager.block')->clearCachedDefinitions(); } /** diff --git a/core/modules/layout_builder/src/Plugin/Derivative/ExtraFieldBlockDeriver.php b/core/modules/layout_builder/src/Plugin/Derivative/ExtraFieldBlockDeriver.php index d6621c0f47..1c73ab90cd 100644 --- a/core/modules/layout_builder/src/Plugin/Derivative/ExtraFieldBlockDeriver.php +++ b/core/modules/layout_builder/src/Plugin/Derivative/ExtraFieldBlockDeriver.php @@ -4,6 +4,8 @@ use Drupal\Component\Plugin\Derivative\DeriverBase; use Drupal\Component\Plugin\PluginBase; +use Drupal\Core\Cache\CacheableDependencyInterface; +use Drupal\Core\Cache\CacheableDependencyTrait; use Drupal\Core\Entity\EntityFieldManagerInterface; use Drupal\Core\Entity\EntityTypeBundleInfoInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; @@ -21,8 +23,9 @@ * experimental modules and development releases of contributed modules. * See https://www.drupal.org/core/experimental for more information. */ -class ExtraFieldBlockDeriver extends DeriverBase implements ContainerDeriverInterface { +class ExtraFieldBlockDeriver extends DeriverBase implements ContainerDeriverInterface, CacheableDependencyInterface { + use CacheableDependencyTrait; use StringTranslationTrait; /** @@ -60,6 +63,8 @@ public function __construct(EntityFieldManagerInterface $entity_field_manager, E $this->entityFieldManager = $entity_field_manager; $this->entityTypeManager = $entity_type_manager; $this->entityTypeBundleInfo = $entity_type_bundle_info; + + $this->addCacheableDependency($this->entityFieldManager); } /** diff --git a/core/modules/layout_builder/src/Plugin/Derivative/FieldBlockDeriver.php b/core/modules/layout_builder/src/Plugin/Derivative/FieldBlockDeriver.php index 57d2c1ec7c..fe7099abcb 100644 --- a/core/modules/layout_builder/src/Plugin/Derivative/FieldBlockDeriver.php +++ b/core/modules/layout_builder/src/Plugin/Derivative/FieldBlockDeriver.php @@ -4,6 +4,8 @@ use Drupal\Component\Plugin\Derivative\DeriverBase; use Drupal\Component\Plugin\PluginBase; +use Drupal\Core\Cache\CacheableDependencyInterface; +use Drupal\Core\Cache\CacheableDependencyTrait; use Drupal\Core\Entity\EntityFieldManagerInterface; use Drupal\Core\Entity\EntityTypeRepositoryInterface; use Drupal\Core\Field\FieldConfigInterface; @@ -19,8 +21,9 @@ * * @internal */ -class FieldBlockDeriver extends DeriverBase implements ContainerDeriverInterface { +class FieldBlockDeriver extends DeriverBase implements ContainerDeriverInterface, CacheableDependencyInterface { + use CacheableDependencyTrait; use StringTranslationTrait; /** @@ -68,6 +71,8 @@ public function __construct(EntityTypeRepositoryInterface $entity_type_repositor $this->entityFieldManager = $entity_field_manager; $this->fieldTypeManager = $field_type_manager; $this->formatterManager = $formatter_manager; + + $this->addCacheableDependency($this->entityFieldManager); } /** diff --git a/core/modules/layout_builder/tests/src/Kernel/LayoutBuilderInstallTest.php b/core/modules/layout_builder/tests/src/Kernel/LayoutBuilderInstallTest.php index aa1b9942c8..a22941f115 100644 --- a/core/modules/layout_builder/tests/src/Kernel/LayoutBuilderInstallTest.php +++ b/core/modules/layout_builder/tests/src/Kernel/LayoutBuilderInstallTest.php @@ -72,6 +72,13 @@ public function testCompatibility() { $this->entity->test_field_display_post_install = 'Test string'; $this->entity->save(); + // While the persistent cache is cleared, the static cache must be manually + // reset within the same request. + $block_manager = \Drupal::service('plugin.manager.block'); + $property = new \ReflectionProperty($block_manager, 'definitions'); + $property->setAccessible(TRUE); + $property->setValue($block_manager, NULL); + $this->display = $this->reloadEntity($this->display); $this->display ->setComponent('test_field_display_post_install', ['weight' => 50]) diff --git a/core/modules/statistics/src/StatisticsSettingsForm.php b/core/modules/statistics/src/StatisticsSettingsForm.php index 85c455bfae..6b6dde9b23 100644 --- a/core/modules/statistics/src/StatisticsSettingsForm.php +++ b/core/modules/statistics/src/StatisticsSettingsForm.php @@ -2,11 +2,8 @@ namespace Drupal\statistics; -use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Form\ConfigFormBase; -use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\Form\FormStateInterface; -use Symfony\Component\DependencyInjection\ContainerInterface; /** * Configure statistics settings for this site. @@ -15,37 +12,6 @@ */ class StatisticsSettingsForm extends ConfigFormBase { - /** - * The module handler. - * - * @var \Drupal\Core\Extension\ModuleHandlerInterface - */ - protected $moduleHandler; - - /** - * Constructs a \Drupal\statistics\StatisticsSettingsForm object. - * - * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory - * The factory for configuration objects. - * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler - * The module handler. - */ - public function __construct(ConfigFactoryInterface $config_factory, ModuleHandlerInterface $module_handler) { - parent::__construct($config_factory); - - $this->moduleHandler = $module_handler; - } - - /** - * {@inheritdoc} - */ - public static function create(ContainerInterface $container) { - return new static( - $container->get('config.factory'), - $container->get('module_handler') - ); - } - /** * {@inheritdoc} */ @@ -90,12 +56,6 @@ public function submitForm(array &$form, FormStateInterface $form_state) { ->set('count_content_views', $form_state->getValue('statistics_count_content_views')) ->save(); - // The popular statistics block is dependent on these settings, so clear the - // block plugin definitions cache. - if ($this->moduleHandler->moduleExists('block')) { - \Drupal::service('plugin.manager.block')->clearCachedDefinitions(); - } - parent::submitForm($form, $form_state); } diff --git a/core/modules/system/src/Entity/Menu.php b/core/modules/system/src/Entity/Menu.php index 14830099e0..08aefdf091 100644 --- a/core/modules/system/src/Entity/Menu.php +++ b/core/modules/system/src/Entity/Menu.php @@ -98,10 +98,6 @@ public static function preDelete(EntityStorageInterface $storage, array $entitie public function save() { $return = parent::save(); \Drupal::cache('menu')->invalidateAll(); - // Invalidate the block cache to update menu-based derivatives. - if (\Drupal::moduleHandler()->moduleExists('block')) { - \Drupal::service('plugin.manager.block')->clearCachedDefinitions(); - } return $return; } @@ -111,11 +107,6 @@ public function save() { public function delete() { parent::delete(); \Drupal::cache('menu')->invalidateAll(); - - // Invalidate the block cache to update menu-based derivatives. - if (\Drupal::moduleHandler()->moduleExists('block')) { - \Drupal::service('plugin.manager.block')->clearCachedDefinitions(); - } } } diff --git a/core/modules/system/src/Plugin/Derivative/SystemMenuBlock.php b/core/modules/system/src/Plugin/Derivative/SystemMenuBlock.php index 5da5027172..bb92c44664 100644 --- a/core/modules/system/src/Plugin/Derivative/SystemMenuBlock.php +++ b/core/modules/system/src/Plugin/Derivative/SystemMenuBlock.php @@ -3,6 +3,8 @@ namespace Drupal\system\Plugin\Derivative; use Drupal\Component\Plugin\Derivative\DeriverBase; +use Drupal\Core\Cache\CacheableDependencyInterface; +use Drupal\Core\Cache\CacheableDependencyTrait; use Drupal\Core\Entity\EntityStorageInterface; use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -12,7 +14,9 @@ * * @see \Drupal\system\Plugin\Block\SystemMenuBlock */ -class SystemMenuBlock extends DeriverBase implements ContainerDeriverInterface { +class SystemMenuBlock extends DeriverBase implements ContainerDeriverInterface, CacheableDependencyInterface { + + use CacheableDependencyTrait; /** * The menu storage. @@ -29,6 +33,8 @@ class SystemMenuBlock extends DeriverBase implements ContainerDeriverInterface { */ public function __construct(EntityStorageInterface $menu_storage) { $this->menuStorage = $menu_storage; + + $this->addCacheTags($this->menuStorage->getEntityType()->getListCacheTags()); } /** diff --git a/core/modules/views/src/Plugin/Derivative/ViewsBlock.php b/core/modules/views/src/Plugin/Derivative/ViewsBlock.php index f4da73d4bd..c354338d2a 100644 --- a/core/modules/views/src/Plugin/Derivative/ViewsBlock.php +++ b/core/modules/views/src/Plugin/Derivative/ViewsBlock.php @@ -2,6 +2,10 @@ namespace Drupal\views\Plugin\Derivative; +use Drupal\Core\Cache\CacheableDependencyInterface; +use Drupal\Core\Cache\CacheableDependencyTrait; +use Drupal\Core\Cache\RefinableCacheableDependencyInterface; +use Drupal\Core\Cache\RefinableCacheableDependencyTrait; use Drupal\Core\Entity\EntityStorageInterface; use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface; use Drupal\Core\StringTranslation\TranslatableMarkup; @@ -12,7 +16,9 @@ * * @see \Drupal\views\Plugin\Block\ViewsBlock */ -class ViewsBlock implements ContainerDeriverInterface { +class ViewsBlock implements ContainerDeriverInterface, CacheableDependencyInterface { + + use CacheableDependencyTrait; /** * List of derivative definitions. @@ -56,6 +62,8 @@ public static function create(ContainerInterface $container, $base_plugin_id) { public function __construct($base_plugin_id, EntityStorageInterface $view_storage) { $this->basePluginId = $base_plugin_id; $this->viewStorage = $view_storage; + + $this->addCacheTags($this->viewStorage->getEntityType()->getListCacheTags()); } /** diff --git a/core/modules/views/src/Plugin/Derivative/ViewsExposedFilterBlock.php b/core/modules/views/src/Plugin/Derivative/ViewsExposedFilterBlock.php index f700f16ace..6865e01214 100644 --- a/core/modules/views/src/Plugin/Derivative/ViewsExposedFilterBlock.php +++ b/core/modules/views/src/Plugin/Derivative/ViewsExposedFilterBlock.php @@ -2,6 +2,8 @@ namespace Drupal\views\Plugin\Derivative; +use Drupal\Core\Cache\CacheableDependencyInterface; +use Drupal\Core\Cache\CacheableDependencyTrait; use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface; use Drupal\Core\Entity\EntityStorageInterface; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -11,7 +13,9 @@ * * @see \Drupal\views\Plugin\Block\ViewsExposedFilterBlock */ -class ViewsExposedFilterBlock implements ContainerDeriverInterface { +class ViewsExposedFilterBlock implements ContainerDeriverInterface, CacheableDependencyInterface { + + use CacheableDependencyTrait; /** * List of derivative definitions. @@ -45,6 +49,8 @@ class ViewsExposedFilterBlock implements ContainerDeriverInterface { public function __construct($base_plugin_id, EntityStorageInterface $view_storage) { $this->basePluginId = $base_plugin_id; $this->viewStorage = $view_storage; + + $this->addCacheTags($this->viewStorage->getEntityType()->getListCacheTags()); } /** diff --git a/core/modules/views/src/Plugin/views/display/Block.php b/core/modules/views/src/Plugin/views/display/Block.php index e210ee3231..96cd5278ae 100644 --- a/core/modules/views/src/Plugin/views/display/Block.php +++ b/core/modules/views/src/Plugin/views/display/Block.php @@ -2,7 +2,6 @@ namespace Drupal\views\Plugin\views\display; -use Drupal\Component\Plugin\Discovery\CachedDiscoveryInterface; use Drupal\Core\Block\BlockManagerInterface; use Drupal\Core\Entity\EntityManagerInterface; use Drupal\Core\Form\FormStateInterface; @@ -377,9 +376,6 @@ public function remove() { $block->delete(); } } - if ($this->blockManager instanceof CachedDiscoveryInterface) { - $this->blockManager->clearCachedDefinitions(); - } } } diff --git a/core/tests/Drupal/Tests/Core/Entity/EntityFieldManagerTest.php b/core/tests/Drupal/Tests/Core/Entity/EntityFieldManagerTest.php index 87b8a68fc1..c57f6aeaa5 100644 --- a/core/tests/Drupal/Tests/Core/Entity/EntityFieldManagerTest.php +++ b/core/tests/Drupal/Tests/Core/Entity/EntityFieldManagerTest.php @@ -9,6 +9,7 @@ use Drupal\Component\Plugin\Exception\PluginNotFoundException; use Drupal\Core\Cache\Cache; +use Drupal\Core\Cache\CacheableDependencyInterface; use Drupal\Core\Cache\CacheBackendInterface; use Drupal\Core\Cache\CacheTagsInvalidatorInterface; use Drupal\Core\Config\Entity\ConfigEntityStorageInterface; @@ -171,7 +172,9 @@ protected function setUp() { $this->keyValueFactory = $this->prophesize(KeyValueFactoryInterface::class); - $this->entityTypeManager = $this->prophesize(EntityTypeManagerInterface::class); + $this->entityTypeManager = $this->prophesize(EntityTypeManagerInterface::class)->willImplement(CacheableDependencyInterface::class); + $this->entityTypeManager->getCacheTags()->willReturn(['entity_types']); + $this->entityTypeRepository = $this->prophesize(EntityTypeRepositoryInterface::class); $this->entityTypeBundleInfo = $this->prophesize(EntityTypeBundleInfoInterface::class); $this->entityDisplayRepository = $this->prophesize(EntityDisplayRepositoryInterface::class); @@ -361,7 +364,7 @@ public function testGetBaseFieldDefinitionsWithCaching() { $this->cacheBackend->get('entity_base_field_definitions:test_entity_type:en') ->willReturn(FALSE) ->shouldBeCalled(); - $this->cacheBackend->set('entity_base_field_definitions:test_entity_type:en', Argument::any(), Cache::PERMANENT, ['entity_types', 'entity_field_info']) + $this->cacheBackend->set('entity_base_field_definitions:test_entity_type:en', Argument::any(), Cache::PERMANENT, ['entity_field_info', 'entity_types']) ->will(function ($args) { $data = (object) ['data' => $args[1]]; $this->get('entity_base_field_definitions:test_entity_type:en') @@ -391,7 +394,7 @@ public function testGetFieldDefinitionsWithCaching() { $this->cacheBackend->get('entity_bundle_field_definitions:test_entity_type:test_bundle:en') ->willReturn(FALSE) ->shouldBeCalledTimes(1); - $this->cacheBackend->set('entity_bundle_field_definitions:test_entity_type:test_bundle:en', Argument::any(), Cache::PERMANENT, ['entity_types', 'entity_field_info']) + $this->cacheBackend->set('entity_bundle_field_definitions:test_entity_type:test_bundle:en', Argument::any(), Cache::PERMANENT, ['entity_field_info', 'entity_types']) ->will(function ($args) { $data = (object) ['data' => $args[1]]; $this->get('entity_bundle_field_definitions:test_entity_type:test_bundle:en') @@ -431,7 +434,7 @@ public function testGetFieldStorageDefinitionsWithCaching() { ->shouldBeCalledTimes(2); $this->cacheBackend->get('entity_field_storage_definitions:test_entity_type:en')->willReturn(FALSE); - $this->cacheBackend->set('entity_field_storage_definitions:test_entity_type:en', Argument::any(), Cache::PERMANENT, ['entity_types', 'entity_field_info']) + $this->cacheBackend->set('entity_field_storage_definitions:test_entity_type:en', Argument::any(), Cache::PERMANENT, ['entity_field_info', 'entity_types']) ->will(function () use ($expected) { $this->get('entity_field_storage_definitions:test_entity_type:en') ->willReturn((object) ['data' => $expected])