diff --git a/core/lib/Drupal/Core/Annotation/ContextDefinition.php b/core/lib/Drupal/Core/Annotation/ContextDefinition.php index 75fbc9b..18095b2 100644 --- a/core/lib/Drupal/Core/Annotation/ContextDefinition.php +++ b/core/lib/Drupal/Core/Annotation/ContextDefinition.php @@ -100,7 +100,7 @@ public function __construct(array $values) { // used in the classes they pass to. foreach (['label', 'description'] as $key) { // @todo Remove this workaround in https://www.drupal.org/node/2362727. - if (isset($values[$key]) && $values[$key]->get() instanceof TranslationWrapper) { + if (isset($values[$key]) && $values[$key] instanceof Translation && $values[$key]->get() instanceof TranslationWrapper) { $values[$key] = (string) $values[$key]->get(); } else { diff --git a/core/lib/Drupal/Core/Block/BlockBase.php b/core/lib/Drupal/Core/Block/BlockBase.php index 5af5efa..b5f10da 100644 --- a/core/lib/Drupal/Core/Block/BlockBase.php +++ b/core/lib/Drupal/Core/Block/BlockBase.php @@ -10,6 +10,7 @@ use Drupal\block\BlockInterface; use Drupal\Component\Utility\SafeMarkup; use Drupal\Core\Access\AccessResult; +use Drupal\Core\Cache\CacheableDependencyInterface; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Plugin\ContextAwarePluginAssignmentTrait; use Drupal\Core\Plugin\ContextAwarePluginBase; @@ -315,21 +316,39 @@ public function setTransliteration(TransliterationInterface $transliteration) { * {@inheritdoc} */ public function getCacheContexts() { - return []; + $cache_contexts = []; + foreach ($this->getContextValues() as $key => $context) { + if ($context instanceof CacheableDependencyInterface) { + $cache_contexts = Cache::mergeContexts($cache_contexts, $context->getCacheContexts()); + } + } + return $cache_contexts; } /** * {@inheritdoc} */ public function getCacheTags() { - return []; + $cache_tags = []; + foreach ($this->getContextValues() as $key => $context) { + if ($context instanceof CacheableDependencyInterface) { + $cache_tags = Cache::mergeTags($cache_tags, $context->getCacheTags()); + } + } + return $cache_tags; } /** * {@inheritdoc} */ public function getCacheMaxAge() { - return (int)$this->configuration['cache']['max_age']; + $max_age = (int)$this->configuration['cache']['max_age']; + foreach ($this->getContextValues() as $key => $context) { + if ($context instanceof CacheableDependencyInterface) { + $max_age = Cache::mergeMaxAges($max_age, $context->getCacheMaxAge()); + } + } + return $max_age; } } diff --git a/core/lib/Drupal/Core/Plugin/ContextAwarePluginAssignmentTrait.php b/core/lib/Drupal/Core/Plugin/ContextAwarePluginAssignmentTrait.php index 88249f5..e3ae261 100644 --- a/core/lib/Drupal/Core/Plugin/ContextAwarePluginAssignmentTrait.php +++ b/core/lib/Drupal/Core/Plugin/ContextAwarePluginAssignmentTrait.php @@ -53,18 +53,19 @@ protected function addContextAssignmentElement(ContextAwarePluginInterface $plug ]; $element['context_slot_title'] = [ '#type' => 'item', - '#title' => $this->t('@context value:', ['@context' => ucfirst($context_slot)]), + '#title' => $definition->getLabel() ?: $context_slot, '#markup' => $options[$context_id], ]; } if (count($options) > 1) { - // Remove the default value title because we have more than one value. + // The context display element is only useful when a single context is + // available, we have multiple and require user interaction. unset($element['context_slot_title']); $assignments = $plugin->getContextMapping(); $element[$context_slot] = [ - '#title' => $this->t('Select a @context value:', ['@context' => $context_slot]), + '#title' => $definition->getLabel() ?: $context_slot, '#type' => 'select', '#options' => $options, '#required' => $definition->isRequired(), diff --git a/core/lib/Drupal/Core/Plugin/ContextAwarePluginBase.php b/core/lib/Drupal/Core/Plugin/ContextAwarePluginBase.php index df86cf0..ec3046d 100644 --- a/core/lib/Drupal/Core/Plugin/ContextAwarePluginBase.php +++ b/core/lib/Drupal/Core/Plugin/ContextAwarePluginBase.php @@ -62,6 +62,10 @@ public function getContextMapping() { * {@inheritdoc} */ public function setContextMapping(array $context_mapping) { + // The ContextAwarePluginAssignmentTrait adds a visual element to the + // context mapping when only one context is available. We should unset this + // before saving the context mapping. + unset($context_mapping['context_slot_title']); if ($this instanceof ConfigurablePluginInterface) { $configuration = $this->getConfiguration(); $configuration['context_mapping'] = $context_mapping; diff --git a/core/modules/aggregator/config/schema/aggregator.schema.yml b/core/modules/aggregator/config/schema/aggregator.schema.yml index 80bcbb8..cb2837c 100644 --- a/core/modules/aggregator/config/schema/aggregator.schema.yml +++ b/core/modules/aggregator/config/schema/aggregator.schema.yml @@ -48,6 +48,7 @@ block.settings.aggregator_feed_block: type: mapping label: 'Context assignments' mapping: + # This will be stored in the format of 'aggregator.feed:$uuid'. feed: type: string label: 'Feed' diff --git a/core/modules/aggregator/src/Entity/Feed.php b/core/modules/aggregator/src/Entity/Feed.php index 6f4f3fc..5c74ed2 100644 --- a/core/modules/aggregator/src/Entity/Feed.php +++ b/core/modules/aggregator/src/Entity/Feed.php @@ -115,9 +115,9 @@ public static function postDelete(EntityStorageInterface $storage, array $entiti parent::postDelete($storage, $entities); if (\Drupal::moduleHandler()->moduleExists('block')) { // Make sure there are no active blocks for these feeds. - $context_ids = array_keys($entities); - foreach ($context_ids as $key => $value) { - $context_ids[$key] = 'aggregator.feed:' . $value; + $context_ids = []; + foreach ($entities as $key => $entity) { + $context_ids[$key] = 'aggregator.feed:' . $entity->uuid(); } $ids = \Drupal::entityQuery('block') ->condition('plugin', 'aggregator_feed_block') diff --git a/core/modules/aggregator/src/EventSubscriber/AggregatorFeedContext.php b/core/modules/aggregator/src/EventSubscriber/AggregatorFeedContext.php index 09dd845..5a884e8 100644 --- a/core/modules/aggregator/src/EventSubscriber/AggregatorFeedContext.php +++ b/core/modules/aggregator/src/EventSubscriber/AggregatorFeedContext.php @@ -42,7 +42,7 @@ class AggregatorFeedContext extends BlockContextSubscriberBase { protected $themeManager; /** - * Constructs a new NodeRouteContext. + * Constructs a new AggregatorFeedContext. * * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager * The entity manager. @@ -64,11 +64,14 @@ public function onBlockActiveContext(BlockContextEvent $event) { $block_plugin = $block->getPlugin(); if ($block_plugin instanceof ContextAwarePluginInterface) { $contexts = $block_plugin->getContextMapping(); - list(, $fid) = explode(':', $contexts['feed'], 2); - $feed = $this->feedStorage->load($fid); + // The context mapping is stored as aggregator.feed:uuid, so we're just + // extracting the UUID so that we can load the specific feed object. + list(, $uuid) = explode(':', $contexts['feed'], 2); + $feeds = $this->feedStorage->loadByProperties(['uuid' => $uuid]); + $feed = reset($feeds); $context = new Context(new ContextDefinition('entity:aggregator_feed')); $context->setContextValue($feed); - $event->setContext('aggregator.feed:' . $feed->id(), $context); + $event->setContext('aggregator.feed:' . $feed->uuid(), $context); } } } @@ -81,7 +84,7 @@ public function onBlockAdministrativeContext(BlockContextEvent $event) { foreach ($feeds as $feed) { $context = new Context(new ContextDefinition('entity:aggregator_feed', $feed->label())); $context->setContextValue($feed); - $event->setContext('aggregator.feed:' . $feed->id(), $context); + $event->setContext('aggregator.feed:' . $feed->uuid(), $context); } } diff --git a/core/modules/aggregator/src/Plugin/Block/AggregatorFeedBlock.php b/core/modules/aggregator/src/Plugin/Block/AggregatorFeedBlock.php index 7e178b4..58010a8 100644 --- a/core/modules/aggregator/src/Plugin/Block/AggregatorFeedBlock.php +++ b/core/modules/aggregator/src/Plugin/Block/AggregatorFeedBlock.php @@ -9,7 +9,6 @@ use Drupal\aggregator\ItemStorageInterface; use Drupal\Core\Block\BlockBase; -use Drupal\Core\Cache\Cache; use Drupal\Core\Entity\Query\QueryInterface; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; @@ -163,13 +162,4 @@ public function build() { } } - /** - * {@inheritdoc} - */ - public function getCacheTags() { - $cache_tags = parent::getCacheTags(); - $feed = $this->getContextValue('feed'); - return Cache::mergeTags($cache_tags, $feed->getCacheTags()); - } - } diff --git a/core/modules/aggregator/src/Tests/AggregatorRenderingTest.php b/core/modules/aggregator/src/Tests/AggregatorRenderingTest.php index e9f0fa3..ea8183d 100644 --- a/core/modules/aggregator/src/Tests/AggregatorRenderingTest.php +++ b/core/modules/aggregator/src/Tests/AggregatorRenderingTest.php @@ -44,7 +44,7 @@ public function testBlockLinks() { $block = $this->drupalPlaceBlock("aggregator_feed_block", array('label' => 'feed-' . $feed->label())); // Configure the feed that should be displayed. - $block->getPlugin()->setContextMapping(['feed' => 'aggregator.feed:' . $feed->id()]); + $block->getPlugin()->setContextMapping(['feed' => 'aggregator.feed:' . $feed->uuid()]); $block->getPlugin()->setConfigurationValue('block_count', 2); $block->save(); diff --git a/core/modules/aggregator/src/Tests/DeleteFeedTest.php b/core/modules/aggregator/src/Tests/DeleteFeedTest.php index 0dbf5e3..e91c08e 100644 --- a/core/modules/aggregator/src/Tests/DeleteFeedTest.php +++ b/core/modules/aggregator/src/Tests/DeleteFeedTest.php @@ -30,10 +30,10 @@ public function testDeleteFeed() { // Place a block for both feeds. $block = $this->drupalPlaceBlock('aggregator_feed_block'); - $block->getPlugin()->setContextMapping(['feed' => 'aggregator.feed:' . $feed1->id()]); + $block->getPlugin()->setContextMapping(['feed' => 'aggregator.feed:' . $feed1->uuid()]); $block->save(); $block2 = $this->drupalPlaceBlock('aggregator_feed_block'); - $block2->getPlugin()->setContextMapping(['feed' => 'aggregator.feed:' . $feed2->id()]); + $block2->getPlugin()->setContextMapping(['feed' => 'aggregator.feed:' . $feed2->uuid()]); $block2->save(); // Delete feed. diff --git a/core/modules/block/src/BlockForm.php b/core/modules/block/src/BlockForm.php index 137d6e9..b3ae2f6 100644 --- a/core/modules/block/src/BlockForm.php +++ b/core/modules/block/src/BlockForm.php @@ -329,7 +329,7 @@ public function submitForm(array &$form, FormStateInterface $form_state) { // Call the plugin submit handler. $block = $entity->getPlugin(); $block->submitConfigurationForm($form, $settings); - if ($block instanceof ContextAwarePluginInterface) { + if ($block instanceof ContextAwarePluginInterface && $block->getContextDefinitions()) { $context_mapping = $settings->getValue('context_mapping', []); $block->setContextMapping($context_mapping); } @@ -343,7 +343,7 @@ public function submitForm(array &$form, FormStateInterface $form_state) { $condition_values = (new FormState()) ->setValues($values); $condition->submitConfigurationForm($form, $condition_values); - if ($condition instanceof ContextAwarePluginInterface) { + if ($condition instanceof ContextAwarePluginInterface && $condition->getContextDefinitions()) { $context_mapping = isset($values['context_mapping']) ? $values['context_mapping'] : []; $condition->setContextMapping($context_mapping); } diff --git a/core/modules/block/src/EventSubscriber/NodeRouteContext.php b/core/modules/block/src/EventSubscriber/NodeRouteContext.php index 97cb0bb..ddbf846 100644 --- a/core/modules/block/src/EventSubscriber/NodeRouteContext.php +++ b/core/modules/block/src/EventSubscriber/NodeRouteContext.php @@ -61,7 +61,7 @@ public function onBlockActiveContext(BlockContextEvent $event) { * {@inheritdoc} */ public function onBlockAdministrativeContext(BlockContextEvent $event) { - $context = new Context(new ContextDefinition('entity:node', $this->t('Node from route'))); + $context = new Context(new ContextDefinition('entity:node', $this->t('Node from URL'))); $event->setContext('node.node', $context); } diff --git a/core/tests/Drupal/Tests/Core/Annotation/ContextDefinitionTest.php b/core/tests/Drupal/Tests/Core/Annotation/ContextDefinitionTest.php new file mode 100644 index 0000000..7f8382f --- /dev/null +++ b/core/tests/Drupal/Tests/Core/Annotation/ContextDefinitionTest.php @@ -0,0 +1,70 @@ +translationManager = $this->getStringTranslationStub(); + } + + /** + * Test the ContextDefinition Annotation. + */ + public function testContextDefinitionAnnotation() { + $container = new ContainerBuilder(); + $container->set('string_translation', $this->translationManager); + \Drupal::setContainer($container); + + $values = [ + 'value' => 'entity:node', + //'label' => new Translation(['value' => 'test']), + 'label' => 'test', + 'description' => 'test', + ]; + $context_definition = new ContextDefinition($values); + $definition = $context_definition->get(); + //throw new \Exception(print_r(, TRUE)); + // If the label or description are not a Translation annotation instance, + // it should be replaced by NULL. + $this->assertNull($definition->getLabel()); + $this->assertNull($definition->getDescription()); + + $values = [ + 'value' => 'entity:node', + 'label' => new Translation(['value' => 'test']), + 'description' => new Translation(['value' => 'test']), + ]; + $context_definition = new ContextDefinition($values); + $definition = $context_definition->get(); + //throw new \Exception(print_r(, TRUE)); + // If the label or description are a Translation annotation instance, the + // translated string should be returned. + $this->assertEquals('test', $definition->getLabel()); + $this->assertEquals('test', $definition->getDescription()); + } + +}