diff --git a/core/lib/Drupal/Core/Cache/RefinableCacheableDependencyInterface.php b/core/lib/Drupal/Core/Cache/RefinableCacheableDependencyInterface.php index 4f9f6bc..11e1584 100644 --- a/core/lib/Drupal/Core/Cache/RefinableCacheableDependencyInterface.php +++ b/core/lib/Drupal/Core/Cache/RefinableCacheableDependencyInterface.php @@ -6,8 +6,6 @@ namespace Drupal\Core\Cache; -use Drupal\Core\Cache\CacheableMetadata; - /** * Allows to add cacheability metadata to an object for the current runtime. * @@ -55,13 +53,17 @@ public function addCacheTags(array $cache_tags); public function mergeCacheMaxAge($max_age); /** - * Adds the passed in cacheability metadata to the object. + * Adds a dependency on an object: merges its cacheability metadata. * - * @param \Drupal\Core\Cache\CacheableMetadata $metadata - * The cacheability metadata to add. + * @param \Drupal\Core\Cache\CacheableDependencyInterface|mixed $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\CacheableMetadata::createFromObject() */ - public function addCacheableMetadata(CacheableMetadata $metadata); + public function addCacheableDependency($other_object); } diff --git a/core/lib/Drupal/Core/Cache/RefinableCacheableDependencyTrait.php b/core/lib/Drupal/Core/Cache/RefinableCacheableDependencyTrait.php index 1728bc9..7a516ae 100644 --- a/core/lib/Drupal/Core/Cache/RefinableCacheableDependencyTrait.php +++ b/core/lib/Drupal/Core/Cache/RefinableCacheableDependencyTrait.php @@ -36,10 +36,22 @@ /** * {@inheritdoc} */ - public function addCacheableMetadata(CacheableMetadata $metadata) { - $this->addCacheContexts($metadata->getCacheContexts()); - $this->addCacheTags($metadata->getCacheTags()); - $this->mergeCacheMaxAge($metadata->getCacheMaxAge()); + public function addCacheableDependency($other_object) { + if ($other_object instanceof CacheableDependencyInterface) { + $this->addCacheContexts($other_object->getCacheContexts()); + $this->addCacheTags($other_object->getCacheTags()); + if ($this->maxAge === Cache::PERMANENT) { + $this->maxAge = $other_object->getCacheMaxAge(); + } + elseif (($max_age = $other_object->getCacheMaxAge()) && $max_age !== Cache::PERMANENT) { + $this->maxAge = Cache::mergeMaxAges($this->maxAge, $max_age); + } + } + else { + // Not a cacheable dependency, this can not be cached. + $this->maxAge = 0; + } + return $this; } /** diff --git a/core/lib/Drupal/Core/Config/ConfigFactory.php b/core/lib/Drupal/Core/Config/ConfigFactory.php index eba111f..6ec8a5c 100644 --- a/core/lib/Drupal/Core/Config/ConfigFactory.php +++ b/core/lib/Drupal/Core/Config/ConfigFactory.php @@ -127,8 +127,7 @@ protected function doGet($name, $immutable = TRUE) { } } - // Propagate cacheable dependencies to the config object. - $this->propagateConfigOverriderCacheability($cache_key, $name); + $this->propagateConfigOverrideCacheability($cache_key, $name); return $this->cache[$cache_key]; } @@ -188,8 +187,7 @@ protected function doLoadMultiple(array $names, $immutable = TRUE) { } } - // Propagate cacheable dependencies to the config object. - $this->propagateConfigOverriderCacheability($cache_key, $name); + $this->propagateConfigOverrideCacheability($cache_key, $name); $list[$name] = $this->cache[$cache_key]; } @@ -218,16 +216,16 @@ protected function loadOverrides(array $names) { } /** - * Propagates overridden cacheable dependencies to cached config objects. + * Propagates cacheability of config overrides to cached config objects. * * @param string $cache_key * The key of the cached config object to update. * @param string $name * The name of the configuration object to construct. */ - protected function propagateConfigOverriderCacheability($cache_key, $name) { + protected function propagateConfigOverrideCacheability($cache_key, $name) { foreach ($this->configFactoryOverrides as $override) { - $this->cache[$cache_key]->addCacheableMetadata($override->getCacheableMetadata($name)); + $this->cache[$cache_key]->addCacheableDependency($override->getCacheableMetadata($name)); } } diff --git a/core/lib/Drupal/Core/Config/ConfigFactoryOverrideInterface.php b/core/lib/Drupal/Core/Config/ConfigFactoryOverrideInterface.php index 80cc361..07938a0 100644 --- a/core/lib/Drupal/Core/Config/ConfigFactoryOverrideInterface.php +++ b/core/lib/Drupal/Core/Config/ConfigFactoryOverrideInterface.php @@ -61,6 +61,9 @@ public function createConfigObject($name, $collection = StorageInterface::DEFAUL /** * Gets the cacheability metadata associated with the config factory override. * + * @param string $name + * The name of the configuration override to get metadata for. + * * @return \Drupal\Core\Cache\CacheableMetadata * A cacheable metadata object. */ diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php index c067ab5..7787185 100644 --- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php +++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php @@ -194,11 +194,11 @@ protected function doLoadMultiple(array $ids = NULL) { } $entities = $this->mapFromStorageRecords($records, $configs); - // Add cacheability metadata to the entities. + // Config entities wrap config objects, and therefore they need to inherit + // the cacheability metadata of config objects (to ensure e.g. additional + // cacheability metadata added by config overrides is not lost). foreach ($entities as $id => $entity) { - $entity - ->addCacheContexts($configs[$id]->getCacheContexts()) - ->mergeCacheMaxAge($configs[$id]->getCacheMaxAge()); + $entity->addCacheableDependency($configs[$id]); // Remove the self-referring cache tag that is present on Config objects // before setting it. A ConfigEntity doesn't need this since it will be diff --git a/core/modules/views_ui/src/ViewUI.php b/core/modules/views_ui/src/ViewUI.php index 2828259..3234869 100644 --- a/core/modules/views_ui/src/ViewUI.php +++ b/core/modules/views_ui/src/ViewUI.php @@ -10,8 +10,8 @@ use Drupal\Component\Utility\Html; use Drupal\Component\Utility\Timer; use Drupal\Component\Utility\Xss; -use Drupal\Core\Cache\CacheableMetadata; -use Drupal\Core\Config\Entity\ThirdPartySettingsInterface; +use Drupal\Core\Cache\Cache; +use Drupal\Core\Cache\CacheableDependencyInterface; use Drupal\Core\EventSubscriber\AjaxResponseSubscriber; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Url; @@ -19,7 +19,6 @@ use Drupal\Core\Entity\EntityStorageInterface; use Drupal\views\ViewExecutable; use Drupal\Core\Database\Database; -use Drupal\Core\TypedData\TypedDataInterface; use Drupal\Core\Session\AccountInterface; use Drupal\views\Plugin\views\query\Sql; use Drupal\views\Entity\View; @@ -1340,10 +1339,9 @@ public function hasTrustedData() { /** * {@inheritdoc} */ - public function addCacheableMetadata(CacheableMetadata $metadata) { - $this->addCacheContexts($metadata->getCacheContexts()); - $this->addCacheTags($metadata->getCacheTags()); - $this->mergeCacheMaxAge($metadata->getCacheMaxAge()); + public function addCacheableDependency($other_object) { + $this->storage->addCacheableDependency($other_object); + return $this; } /** diff --git a/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityStorageTest.php b/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityStorageTest.php index 7e0564f..f5ff705 100644 --- a/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityStorageTest.php +++ b/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityStorageTest.php @@ -581,20 +581,20 @@ public function testSaveNoMismatch() { $this->configFactory->expects($this->once()) ->method('get') ->with('the_config_prefix.baz') - ->will($this->returnValue($config_object)); + ->willReturn($config_object); $this->configFactory->expects($this->once()) ->method('rename') ->willReturn($this->configFactory); $this->configFactory->expects($this->exactly(1)) ->method('getEditable') ->with('the_config_prefix.foo') - ->will($this->returnValue($config_object)); + ->willReturn($config_object); $this->entityQuery->expects($this->once()) ->method('condition') ->will($this->returnSelf()); $this->entityQuery->expects($this->once()) ->method('execute') - ->will($this->returnValue(array('baz'))); + ->willReturn(['baz']); $entity = $this->getMockEntity(array('id' => 'foo')); $entity->setOriginalId('baz'); @@ -615,7 +615,7 @@ public function testSaveChangedUuid() { ->getMock(); $config_object->expects($this->atLeastOnce()) ->method('isNew') - ->will($this->returnValue(FALSE)); + ->willReturn(FALSE); $config_object->expects($this->never()) ->method('save'); $config_object->expects($this->exactly(2)) @@ -626,16 +626,16 @@ public function testSaveChangedUuid() { ))); $config_object->expects($this->exactly(1)) ->method('getCacheContexts') - ->will($this->returnValue([])); + ->willReturn([]); $config_object->expects($this->exactly(1)) ->method('getCacheTags') - ->will($this->returnValue(['config:foo'])); + ->willReturn(['config:foo']); $config_object->expects($this->exactly(1)) ->method('getCacheMaxAge') - ->will($this->returnValue(Cache::PERMANENT)); + ->willReturn(Cache::PERMANENT); $config_object->expects($this->exactly(1)) ->method('getName') - ->will($this->returnValue('foo')); + ->willReturn('foo'); $this->cacheTagsInvalidator->expects($this->never()) ->method('invalidateTags'); @@ -643,29 +643,29 @@ public function testSaveChangedUuid() { $this->configFactory->expects($this->at(1)) ->method('loadMultiple') ->with(array('the_config_prefix.foo')) - ->will($this->returnValue(array())); + ->willReturn([]); $this->configFactory->expects($this->at(2)) ->method('loadMultiple') ->with(array('the_config_prefix.foo')) - ->will($this->returnValue(array($config_object))); + ->willReturn(array($config_object)); $this->configFactory->expects($this->once()) ->method('get') ->with('the_config_prefix.foo') - ->will($this->returnValue($config_object)); + ->willReturn($config_object); $this->configFactory->expects($this->never()) ->method('rename') - ->will($this->returnValue($config_object)); + ->willReturn($config_object); $this->moduleHandler->expects($this->exactly(2)) ->method('getImplementations') - ->will($this->returnValue(array())); + ->willReturn([]); $this->entityQuery->expects($this->once()) ->method('condition') ->will($this->returnSelf()); $this->entityQuery->expects($this->once()) ->method('execute') - ->will($this->returnValue(array('foo'))); + ->willReturn(['foo']); $entity = $this->getMockEntity(array('id' => 'foo')); @@ -691,24 +691,24 @@ public function testLoad() { ))); $config_object->expects($this->exactly(1)) ->method('getCacheContexts') - ->will($this->returnValue([])); + ->willReturn([]); $config_object->expects($this->exactly(1)) ->method('getCacheTags') - ->will($this->returnValue(['config:foo'])); + ->willReturn(['config:foo']); $config_object->expects($this->exactly(1)) ->method('getCacheMaxAge') - ->will($this->returnValue(Cache::PERMANENT)); + ->willReturn(Cache::PERMANENT); $config_object->expects($this->exactly(1)) ->method('getName') - ->will($this->returnValue('foo')); + ->willReturn('foo'); $this->configFactory->expects($this->once()) ->method('loadMultiple') ->with(array('the_config_prefix.foo')) - ->will($this->returnValue(array($config_object))); + ->willReturn([$config_object]); $this->moduleHandler->expects($this->exactly(2)) ->method('getImplementations') - ->will($this->returnValue(array())); + ->willReturn([]); $entity = $this->entityStorage->load('foo'); $this->assertInstanceOf('Drupal\Core\Entity\EntityInterface', $entity); @@ -733,16 +733,16 @@ public function testLoadMultipleAll() { ))); $foo_config_object->expects($this->exactly(1)) ->method('getCacheContexts') - ->will($this->returnValue([])); + ->willReturn([]); $foo_config_object->expects($this->exactly(1)) ->method('getCacheTags') - ->will($this->returnValue(['config:foo'])); + ->willReturn(['config:foo']); $foo_config_object->expects($this->exactly(1)) ->method('getCacheMaxAge') - ->will($this->returnValue(Cache::PERMANENT)); + ->willReturn(Cache::PERMANENT); $foo_config_object->expects($this->exactly(1)) ->method('getName') - ->will($this->returnValue('foo')); + ->willReturn('foo'); $bar_config_object = $this->getMockBuilder('Drupal\Core\Config\Config') ->disableOriginalConstructor() @@ -755,28 +755,28 @@ public function testLoadMultipleAll() { ))); $bar_config_object->expects($this->exactly(1)) ->method('getCacheContexts') - ->will($this->returnValue([])); + ->willReturn([]); $bar_config_object->expects($this->exactly(1)) ->method('getCacheTags') - ->will($this->returnValue(['config:bar'])); + ->willReturn(['config:bar']); $bar_config_object->expects($this->exactly(1)) ->method('getCacheMaxAge') - ->will($this->returnValue(Cache::PERMANENT)); + ->willReturn(Cache::PERMANENT); $bar_config_object->expects($this->exactly(1)) ->method('getName') - ->will($this->returnValue('foo')); + ->willReturn('foo'); $this->configFactory->expects($this->once()) ->method('listAll') ->with('the_config_prefix.') - ->will($this->returnValue(array('the_config_prefix.foo' , 'the_config_prefix.bar'))); + ->willReturn(array('the_config_prefix.foo' , 'the_config_prefix.bar')); $this->configFactory->expects($this->once()) ->method('loadMultiple') ->with(array('the_config_prefix.foo' , 'the_config_prefix.bar')) - ->will($this->returnValue(array($foo_config_object, $bar_config_object))); + ->willReturn(array($foo_config_object, $bar_config_object)); $this->moduleHandler->expects($this->exactly(2)) ->method('getImplementations') - ->will($this->returnValue(array())); + ->willReturn([]); $entities = $this->entityStorage->loadMultiple(); $expected['foo'] = 'foo'; @@ -806,24 +806,24 @@ public function testLoadMultipleIds() { ))); $config_object->expects($this->exactly(1)) ->method('getCacheContexts') - ->will($this->returnValue([])); + ->willReturn([]); $config_object->expects($this->exactly(1)) ->method('getCacheTags') - ->will($this->returnValue(['config:foo'])); + ->willReturn(['config:foo']); $config_object->expects($this->exactly(1)) ->method('getCacheMaxAge') - ->will($this->returnValue(Cache::PERMANENT)); + ->willReturn(Cache::PERMANENT); $config_object->expects($this->exactly(1)) ->method('getName') - ->will($this->returnValue('foo')); + ->willReturn('foo'); $this->configFactory->expects($this->once()) ->method('loadMultiple') ->with(array('the_config_prefix.foo')) - ->will($this->returnValue(array($config_object))); + ->willReturn(array($config_object)); $this->moduleHandler->expects($this->exactly(2)) ->method('getImplementations') - ->will($this->returnValue(array())); + ->willReturn([]); $entities = $this->entityStorage->loadMultiple(array('foo')); foreach ($entities as $id => $entity) {