diff --git a/core/lib/Drupal/Core/Annotation/ContextDefinition.php b/core/lib/Drupal/Core/Annotation/ContextDefinition.php index 987bab95..75fbc9b 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] instanceof TranslationWrapper) { + if (isset($values[$key]) && $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 7ec2e6c..5af5efa 100644 --- a/core/lib/Drupal/Core/Block/BlockBase.php +++ b/core/lib/Drupal/Core/Block/BlockBase.php @@ -11,6 +11,7 @@ use Drupal\Component\Utility\SafeMarkup; use Drupal\Core\Access\AccessResult; use Drupal\Core\Form\FormStateInterface; +use Drupal\Core\Plugin\ContextAwarePluginAssignmentTrait; use Drupal\Core\Plugin\ContextAwarePluginBase; use Drupal\Component\Utility\Unicode; use Drupal\Component\Utility\NestedArray; @@ -30,6 +31,8 @@ */ abstract class BlockBase extends ContextAwarePluginBase implements BlockPluginInterface { + use ContextAwarePluginAssignmentTrait; + /** * The transliteration service. * @@ -204,6 +207,9 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta '#options' => $period, ); + // Add context form elements. + $contexts = $form_state->getTemporaryValue('gathered_contexts') ?: []; + $form['context_mapping'] = $this->addContextAssignmentElement($this, $contexts); // Add plugin-specific settings for this block type. $form += $this->blockForm($form, $form_state); return $form; diff --git a/core/lib/Drupal/Core/Plugin/ContextAwarePluginAssignmentTrait.php b/core/lib/Drupal/Core/Plugin/ContextAwarePluginAssignmentTrait.php index 19d756c..cc5e092 100644 --- a/core/lib/Drupal/Core/Plugin/ContextAwarePluginAssignmentTrait.php +++ b/core/lib/Drupal/Core/Plugin/ContextAwarePluginAssignmentTrait.php @@ -51,9 +51,18 @@ protected function addContextAssignmentElement(ContextAwarePluginInterface $plug '#type' => 'value', '#value' => $context_id, ]; + $element['context_slot_title'] = [ + '#type' => 'item', + '#title' => $this->t('@context value:', ['@context' => $context_slot]), + '#markup' => $options[$context_id], + ]; } if (count($options) > 1) { + // The context display element is only useful when a single context is + // avaialable, 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]), @@ -61,6 +70,7 @@ protected function addContextAssignmentElement(ContextAwarePluginInterface $plug '#options' => $options, '#required' => $definition->isRequired(), '#default_value' => !empty($assignments[$context_slot]) ? $assignments[$context_slot] : '', + '#description' => $definition->getDescription(), ]; } } 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 85710b8..c835f15 100644 --- a/core/modules/aggregator/config/schema/aggregator.schema.yml +++ b/core/modules/aggregator/config/schema/aggregator.schema.yml @@ -44,6 +44,11 @@ block.settings.aggregator_feed_block: block_count: type: integer label: 'Block count' - feed: - type: string - label: 'Feed' + context_mapping: + 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/AggregatorServiceProvider.php b/core/modules/aggregator/src/AggregatorServiceProvider.php new file mode 100644 index 0000000..e61d7bf --- /dev/null +++ b/core/modules/aggregator/src/AggregatorServiceProvider.php @@ -0,0 +1,33 @@ +getParameter('container.modules'); + if (isset($modules['block'])) { + $container->register('block.aggregator_feed_context', 'Drupal\aggregator\EventSubscriber\AggregatorFeedContext') + ->addArgument(new Reference('entity.manager')) + ->addArgument(new Reference('theme.manager')) + ->addTag('event_subscriber'); + } + } + +} diff --git a/core/modules/aggregator/src/Entity/Feed.php b/core/modules/aggregator/src/Entity/Feed.php index 6f3d2e2..5c74ed2 100644 --- a/core/modules/aggregator/src/Entity/Feed.php +++ b/core/modules/aggregator/src/Entity/Feed.php @@ -115,9 +115,13 @@ 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 = []; + foreach ($entities as $key => $entity) { + $context_ids[$key] = 'aggregator.feed:' . $entity->uuid(); + } $ids = \Drupal::entityQuery('block') ->condition('plugin', 'aggregator_feed_block') - ->condition('settings.feed', array_keys($entities)) + ->condition('settings.context_mapping.feed', $context_ids) ->execute(); if ($ids) { $block_storage = \Drupal::entityManager()->getStorage('block'); diff --git a/core/modules/aggregator/src/EventSubscriber/AggregatorFeedContext.php b/core/modules/aggregator/src/EventSubscriber/AggregatorFeedContext.php new file mode 100644 index 0000000..5a884e8 --- /dev/null +++ b/core/modules/aggregator/src/EventSubscriber/AggregatorFeedContext.php @@ -0,0 +1,91 @@ +feedStorage = $entity_manager->getStorage('aggregator_feed'); + $this->blockStorage = $entity_manager->getStorage('block'); + $this->themeManager = $theme_manager; + } + + /** + * {@inheritdoc} + */ + public function onBlockActiveContext(BlockContextEvent $event) { + foreach ($this->blockStorage->loadByProperties(['plugin' => 'aggregator_feed_block', 'theme' => $this->themeManager->getActiveTheme()->getName()]) as $block_id => $block) { + /** @var $block \Drupal\block\Entity\Block */ + $block_plugin = $block->getPlugin(); + if ($block_plugin instanceof ContextAwarePluginInterface) { + $contexts = $block_plugin->getContextMapping(); + // 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->uuid(), $context); + } + } + } + + /** + * {@inheritdoc} + */ + public function onBlockAdministrativeContext(BlockContextEvent $event) { + $feeds = $this->feedStorage->loadMultiple(); + foreach ($feeds as $feed) { + $context = new Context(new ContextDefinition('entity:aggregator_feed', $feed->label())); + $context->setContextValue($feed); + $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 f49abd5..7e178b4 100644 --- a/core/modules/aggregator/src/Plugin/Block/AggregatorFeedBlock.php +++ b/core/modules/aggregator/src/Plugin/Block/AggregatorFeedBlock.php @@ -7,7 +7,6 @@ namespace Drupal\aggregator\Plugin\Block; -use Drupal\aggregator\FeedStorageInterface; use Drupal\aggregator\ItemStorageInterface; use Drupal\Core\Block\BlockBase; use Drupal\Core\Cache\Cache; @@ -23,19 +22,16 @@ * @Block( * id = "aggregator_feed_block", * admin_label = @Translation("Aggregator feed"), - * category = @Translation("Lists (Views)") + * category = @Translation("Lists (Views)"), + * context = { + * "feed" = @ContextDefinition("entity:aggregator_feed", label = @Translation("Aggregator feed"), description = @Translation("Select the feed that should be displayed")) + * } * ) + * */ class AggregatorFeedBlock extends BlockBase implements ContainerFactoryPluginInterface { /** - * The entity storage for feeds. - * - * @var \Drupal\aggregator\FeedStorageInterface - */ - protected $feedStorage; - - /** * The entity storage for items. * * @var \Drupal\aggregator\ItemStorageInterface @@ -58,16 +54,13 @@ class AggregatorFeedBlock extends BlockBase implements ContainerFactoryPluginInt * The plugin_id for the plugin instance. * @param mixed $plugin_definition * The plugin implementation definition. - * @param \Drupal\aggregator\FeedStorageInterface $feed_storage - * The entity storage for feeds. * @param \Drupal\aggregator\ItemStorageInterface $item_storage * The entity storage for feed items. * @param \Drupal\Core\Entity\Query\QueryInterface $item_query * The entity query object for feed items. */ - public function __construct(array $configuration, $plugin_id, $plugin_definition, FeedStorageInterface $feed_storage, ItemStorageInterface $item_storage, QueryInterface $item_query) { + public function __construct(array $configuration, $plugin_id, $plugin_definition, ItemStorageInterface $item_storage, QueryInterface $item_query) { parent::__construct($configuration, $plugin_id, $plugin_definition); - $this->feedStorage = $feed_storage; $this->itemStorage = $item_storage; $this->itemQuery = $item_query; } @@ -81,7 +74,6 @@ public static function create(ContainerInterface $container, array $configuratio $configuration, $plugin_id, $plugin_definition, - $container->get('entity.manager')->getStorage('aggregator_feed'), $container->get('entity.manager')->getStorage('aggregator_item'), $container->get('entity.query')->get('aggregator_item') ); @@ -95,7 +87,6 @@ public function defaultConfiguration() { // By default, the block will contain 10 feed items. return array( 'block_count' => 10, - 'feed' => NULL, ); } @@ -111,17 +102,6 @@ protected function blockAccess(AccountInterface $account) { * {@inheritdoc} */ public function blockForm($form, FormStateInterface $form_state) { - $feeds = $this->feedStorage->loadMultiple(); - $options = array(); - foreach ($feeds as $feed) { - $options[$feed->id()] = $feed->label(); - } - $form['feed'] = array( - '#type' => 'select', - '#title' => $this->t('Select the feed that should be displayed'), - '#default_value' => $this->configuration['feed'], - '#options' => $options, - ); $range = range(2, 20); $form['block_count'] = array( '#type' => 'select', @@ -137,7 +117,6 @@ public function blockForm($form, FormStateInterface $form_state) { */ public function blockSubmit($form, FormStateInterface $form_state) { $this->configuration['block_count'] = $form_state->getValue('block_count'); - $this->configuration['feed'] = $form_state->getValue('feed'); } /** @@ -145,41 +124,42 @@ public function blockSubmit($form, FormStateInterface $form_state) { */ public function build() { // Load the selected feed. - if ($feed = $this->feedStorage->load($this->configuration['feed'])) { - $result = $this->itemQuery - ->condition('fid', $feed->id()) - ->range(0, $this->configuration['block_count']) - ->sort('timestamp', 'DESC') - ->sort('iid', 'DESC') - ->execute(); - - $items = $this->itemStorage->loadMultiple($result); - - $more_link = array( - '#type' => 'more_link', - '#url' => $feed->urlInfo(), - '#attributes' => array('title' => $this->t("View this feed's recent news.")), + /** @var $feed \Drupal\aggregator\Entity\Feed */ + $feed = $this->getContextValue('feed'); + $result = $this->itemQuery + ->condition('fid', $feed->id()) + ->range(0, $this->configuration['block_count']) + ->sort('timestamp', 'DESC') + ->sort('iid', 'DESC') + ->execute(); + + /** @var $items \Drupal\aggregator\Entity\Item[] */ + $items = $this->itemStorage->loadMultiple($result); + + $more_link = array( + '#type' => 'more_link', + '#url' => $feed->urlInfo(), + '#attributes' => array('title' => $this->t("View this feed's recent news.")), + ); + $read_more = drupal_render($more_link); + $rendered_items = array(); + foreach ($items as $item) { + $aggregator_block_item = array( + '#type' => 'link', + '#url' => $item->urlInfo(), + '#title' => $item->label(), + ); + $rendered_items[] = drupal_render($aggregator_block_item); + } + // Only display the block if there are items to show. + if (count($rendered_items) > 0) { + $item_list = array( + '#theme' => 'item_list', + '#items' => $rendered_items, + ); + return array( + '#children' => drupal_render($item_list) . $read_more, ); - $read_more = drupal_render($more_link); - $rendered_items = array(); - foreach ($items as $item) { - $aggregator_block_item = array( - '#type' => 'link', - '#url' => $item->urlInfo(), - '#title' => $item->label(), - ); - $rendered_items[] = drupal_render($aggregator_block_item); - } - // Only display the block if there are items to show. - if (count($rendered_items) > 0) { - $item_list = array( - '#theme' => 'item_list', - '#items' => $rendered_items, - ); - return array( - '#children' => drupal_render($item_list) . $read_more, - ); - } } } @@ -188,7 +168,7 @@ public function build() { */ public function getCacheTags() { $cache_tags = parent::getCacheTags(); - $feed = $this->feedStorage->load($this->configuration['feed']); + $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 dcdc4c0..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()->setConfigurationValue('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 5663da6..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()->setConfigurationValue('feed', $feed1->id()); + $block->getPlugin()->setContextMapping(['feed' => 'aggregator.feed:' . $feed1->uuid()]); $block->save(); $block2 = $this->drupalPlaceBlock('aggregator_feed_block'); - $block2->getPlugin()->setConfigurationValue('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 08d7508..b3ae2f6 100644 --- a/core/modules/block/src/BlockForm.php +++ b/core/modules/block/src/BlockForm.php @@ -327,7 +327,12 @@ public function submitForm(array &$form, FormStateInterface $form_state) { $settings = (new FormState())->setValues($form_state->getValue('settings')); // Call the plugin submit handler. - $entity->getPlugin()->submitConfigurationForm($form, $settings); + $block = $entity->getPlugin(); + $block->submitConfigurationForm($form, $settings); + if ($block instanceof ContextAwarePluginInterface && $block->getContextDefinitions()) { + $context_mapping = $settings->getValue('context_mapping', []); + $block->setContextMapping($context_mapping); + } // Update the original form values. $form_state->setValue('settings', $settings->getValues()); @@ -338,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/BlockListBuilder.php b/core/modules/block/src/BlockListBuilder.php index 6521287..24f51ca 100644 --- a/core/modules/block/src/BlockListBuilder.php +++ b/core/modules/block/src/BlockListBuilder.php @@ -7,6 +7,8 @@ namespace Drupal\block; +use Drupal\block\Event\BlockContextEvent; +use Drupal\block\Event\BlockEvents; use Drupal\Component\Utility\Html; use Drupal\Core\Block\BlockManagerInterface; use Drupal\Component\Serialization\Json; @@ -19,6 +21,7 @@ use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Url; use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\Request; /** @@ -57,6 +60,13 @@ class BlockListBuilder extends ConfigEntityListBuilder implements FormInterface protected $blockManager; /** + * The event dispatcher. + * + * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface + */ + protected $eventDispatcher; + + /** * Constructs a new BlockListBuilder object. * * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type @@ -65,11 +75,14 @@ class BlockListBuilder extends ConfigEntityListBuilder implements FormInterface * The entity storage class. * @param \Drupal\Core\Block\BlockManagerInterface $block_manager * The block manager. + * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher + * The event dispatcher. */ - public function __construct(EntityTypeInterface $entity_type, EntityStorageInterface $storage, BlockManagerInterface $block_manager) { + public function __construct(EntityTypeInterface $entity_type, EntityStorageInterface $storage, BlockManagerInterface $block_manager, EventDispatcherInterface $event_dispatcher) { parent::__construct($entity_type, $storage); $this->blockManager = $block_manager; + $this->eventDispatcher = $event_dispatcher; } /** @@ -79,7 +92,8 @@ public static function createInstance(ContainerInterface $container, EntityTypeI return new static( $entity_type, $container->get('entity.manager')->getStorage($entity_type->id()), - $container->get('plugin.manager.block') + $container->get('plugin.manager.block'), + $container->get('event_dispatcher') ); } @@ -333,7 +347,9 @@ public function buildForm(array $form, FormStateInterface $form_state) { $form['place_blocks']['list']['#attributes']['class'][] = 'entity-meta'; // Only add blocks which work without any available context. - $definitions = $this->blockManager->getDefinitionsForContexts(); + $event = new BlockContextEvent(); + $contexts = $this->eventDispatcher->dispatch(BlockEvents::ADMINISTRATIVE_CONTEXT, $event)->getContexts(); + $definitions = $this->blockManager->getDefinitionsForContexts($contexts); $sorted_definitions = $this->blockManager->getSortedDefinitions($definitions); foreach ($sorted_definitions as $plugin_id => $plugin_definition) { $category = SafeMarkup::checkPlain($plugin_definition['category']); diff --git a/core/modules/block/src/BlockRepository.php b/core/modules/block/src/BlockRepository.php index 485a66f..303ddf5 100644 --- a/core/modules/block/src/BlockRepository.php +++ b/core/modules/block/src/BlockRepository.php @@ -7,6 +7,7 @@ namespace Drupal\block; +use Drupal\Component\Plugin\ContextAwarePluginInterface; use Drupal\Core\Entity\EntityManagerInterface; use Drupal\Core\Plugin\Context\ContextHandlerInterface; use Drupal\Core\Theme\ThemeManagerInterface; @@ -76,6 +77,11 @@ public function getVisibleBlocksPerRegion(array $contexts) { $full = array(); foreach ($this->blockStorage->loadByProperties(array('theme' => $this->getTheme())) as $block_id => $block) { /** @var \Drupal\block\BlockInterface $block */ + $block_plugin = $block->getPlugin(); + if ($block_plugin instanceof ContextAwarePluginInterface) { + $this->contextHandler->applyContextMapping($block_plugin, $contexts); + } + /** @var \Drupal\block\BlockInterface $block */ // Set the contexts on the block before checking access. if ($block->setContexts($contexts)->access('view')) { $full[$block->getRegion()][$block_id] = $block; diff --git a/core/modules/block/src/EventSubscriber/NodeRouteContext.php b/core/modules/block/src/EventSubscriber/NodeRouteContext.php index 66458c0..cbb7fc7 100644 --- a/core/modules/block/src/EventSubscriber/NodeRouteContext.php +++ b/core/modules/block/src/EventSubscriber/NodeRouteContext.php @@ -12,12 +12,15 @@ use Drupal\Core\Plugin\Context\ContextDefinition; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\node\Entity\Node; +use Drupal\Core\StringTranslation\StringTranslationTrait; /** * Sets the current node as a context on node routes. */ class NodeRouteContext extends BlockContextSubscriberBase { + use StringTranslationTrait; + /** * The route match object. * @@ -58,7 +61,7 @@ public function onBlockActiveContext(BlockContextEvent $event) { * {@inheritdoc} */ public function onBlockAdministrativeContext(BlockContextEvent $event) { - $context = new Context(new ContextDefinition('entity:node')); + $context = new Context(new ContextDefinition('entity:node', $this->t('Node from url'))); $event->setContext('node.node', $context); } diff --git a/core/modules/block/src/Tests/BlockInterfaceTest.php b/core/modules/block/src/Tests/BlockInterfaceTest.php index 5e8b54c..adb3930 100644 --- a/core/modules/block/src/Tests/BlockInterfaceTest.php +++ b/core/modules/block/src/Tests/BlockInterfaceTest.php @@ -99,6 +99,7 @@ public function testBlockInterface() { '#options' => $period, ), ), + 'context_mapping' => array(), 'display_message' => array( '#type' => 'textfield', '#title' => t('Display message'), diff --git a/core/modules/block/src/Tests/BlockUiTest.php b/core/modules/block/src/Tests/BlockUiTest.php index aba4ba1..0a8f867 100644 --- a/core/modules/block/src/Tests/BlockUiTest.php +++ b/core/modules/block/src/Tests/BlockUiTest.php @@ -165,12 +165,30 @@ public function testContextAwareBlocks() { $this->drupalGet('admin/structure/block'); $elements = $this->xpath('//details[@id="edit-category-block-test"]//ul[contains(@class, :ul_class)]/li[contains(@class, :li_class)]/a[contains(@href, :href) and text()=:text]', $arguments); - $this->assertTrue(empty($elements), 'The context-aware test block does not appear.'); + $this->assertTrue(!empty($elements), 'The context-aware test block appears.'); $definition = \Drupal::service('plugin.manager.block')->getDefinition('test_context_aware'); $this->assertTrue(!empty($definition), 'The context-aware test block exists.'); } /** + * Tests the behavior of unsatisfied context-aware blocks. + */ + public function testContextAwareUnsatisfiedBlocks() { + $arguments = array( + ':ul_class' => 'block-list', + ':li_class' => 'test-context-aware-unsatisfied', + ':href' => 'admin/structure/block/add/test_context_aware_unsatisfied/classy', + ':text' => 'Test context-aware block', + ); + + $this->drupalGet('admin/structure/block'); + $elements = $this->xpath('//details[@id="edit-category-block-test"]//ul[contains(@class, :ul_class)]/li[contains(@class, :li_class)]/a[contains(@href, :href) and text()=:text]', $arguments); + $this->assertTrue(empty($elements), 'The context-aware test block does not appear.'); + $definition = \Drupal::service('plugin.manager.block')->getDefinition('test_context_aware_unsatisfied'); + $this->assertTrue(!empty($definition), 'The context-aware test block exists.'); + } + + /** * Tests that the BlockForm populates machine name correctly. */ public function testMachineNameSuggestion() { diff --git a/core/modules/block/tests/modules/block_test/src/Plugin/Block/TestContextAwareUnsatisfiedBlock.php b/core/modules/block/tests/modules/block_test/src/Plugin/Block/TestContextAwareUnsatisfiedBlock.php new file mode 100644 index 0000000..7232e74 --- /dev/null +++ b/core/modules/block/tests/modules/block_test/src/Plugin/Block/TestContextAwareUnsatisfiedBlock.php @@ -0,0 +1,34 @@ + 'test', + ]; + } + +}