You are here

public function Blocks::execute in Context 8.4

Same name and namespace in other branches
  1. 8 src/Plugin/ContextReaction/Blocks.php \Drupal\context\Plugin\ContextReaction\Blocks::execute()
  2. 8.0 src/Plugin/ContextReaction/Blocks.php \Drupal\context\Plugin\ContextReaction\Blocks::execute()

Executes the plugin.

Parameters

array $build: The current build of the page.

string|null $title: The page title.

string|null $main_content: The main page content.

Return value

array Blocks that will be built.

Overrides ExecutableInterface::execute

File

src/Plugin/ContextReaction/Blocks.php, line 186

Class

Blocks
Provides a content reaction.

Namespace

Drupal\context\Plugin\ContextReaction

Code

public function execute(array $build = [], $title = NULL, $main_content = NULL) {
  $cacheability = CacheableMetadata::createFromRenderArray($build);

  // Use the currently active theme to fetch blocks.
  $theme = $this->themeManager
    ->getActiveTheme()
    ->getName();
  $regions = $this
    ->getBlocks()
    ->getAllByRegion($theme);

  // Add each block to the page build.
  foreach ($regions as $region => $blocks) {

    /** @var $blocks BlockPluginInterface[] */
    foreach ($blocks as $block_id => $block) {
      $configuration = $block
        ->getConfiguration();
      $block_placement_key = $this
        ->blockShouldBePlacedUniquely($block) ? $block_id : $block
        ->getConfiguration()['id'];
      if ($block instanceof MainContentBlockPluginInterface) {
        if (isset($build['content']['system_main'])) {
          unset($build['content']['system_main']);
        }
        $block
          ->setMainContent($main_content);
      }

      // Same as Drupal\block\BlockAccessControlHandler::checkAccess().
      try {

        // Inject runtime contexts.
        // Must be before $block->access() to prevent ContextException.
        if ($block instanceof ContextAwarePluginInterface) {
          $contexts = $this->contextRepository
            ->getRuntimeContexts($block
            ->getContextMapping());
          $this->contextHandler
            ->applyContextMapping($block, $contexts);
        }

        // Make sure the user is allowed to view the block.
        $access = $block
          ->access($this->account, TRUE);
      } catch (MissingValueContextException $e) {

        // The contexts exist but have no value. Deny access without
        // disabling caching.
        $access = AccessResult::forbidden();
      } catch (ContextException $e) {

        // If any context is missing then we might be missing cacheable
        // metadata, and don't know based on what conditions the block is
        // accessible or not. Make sure the result cannot be cached.
        $access = AccessResult::forbidden()
          ->setCacheMaxAge(0);
      }
      $cacheability
        ->addCacheableDependency($access);

      // If the user is not allowed then do not render the block.
      if (!$access
        ->isAllowed()) {
        continue;
      }
      if ($block instanceof TitleBlockPluginInterface) {
        if (isset($build['content']['messages'])) {
          unset($build['content']['messages']);
        }
        $block
          ->setTitle($title);
      }
      $context_entity = $this->entityTypeManager
        ->getStorage('context')
        ->load($configuration['context_id']);

      // Create the render array for the block as a whole.
      // @see template_preprocess_block().
      $block_build = [
        '#theme' => 'block',
        // Must be defined to avoid array merge error in preRender().
        '#attributes' => [],
        '#configuration' => $configuration,
        '#plugin_id' => $block
          ->getPluginId(),
        '#base_plugin_id' => $block
          ->getBaseId(),
        '#derivative_plugin_id' => $block
          ->getDerivativeId(),
        '#id' => $block
          ->getConfiguration()['custom_id'],
        '#block_plugin' => $block,
        // Add a block entity with the configuration of the block plugin so
        // modules depending on the block property in e.g.
        // hook_block_view_alter will still work.
        '#block' => Block::create($this->blocks[$block_id] + [
          'plugin' => $block
            ->getPluginId(),
        ]),
        '#pre_render' => [
          [
            $this,
            'preRenderBlock',
          ],
        ],
        '#cache' => [
          'keys' => [
            'context_blocks_reaction',
            $configuration['context_id'],
            'block',
            $block_placement_key,
          ],
          'tags' => Cache::mergeTags($block
            ->getCacheTags(), !empty($context_entity) ? $context_entity
            ->getCacheTags() : []),
          'contexts' => $block
            ->getCacheContexts(),
          'max-age' => $block
            ->getCacheMaxAge(),
        ],
      ];

      // Add additional contextual link, for editing block configuration.
      $block_build['#contextual_links']['context_block'] = [
        'route_parameters' => [
          'context' => $configuration['context_id'],
          'reaction_id' => 'blocks',
          'block_id' => $block
            ->getConfiguration()['uuid'],
        ],
      ];
      if (array_key_exists('weight', $configuration)) {
        $block_build['#weight'] = $configuration['weight'];
      }

      // Invoke block_view_alter().
      // If an alter hook wants to modify the block contents, it can append
      // another #pre_render hook.
      \Drupal::moduleHandler()
        ->alter([
        'block_view',
        'block_view_' . $block
          ->getBaseId(),
      ], $block_build, $block);

      // Allow altering of cacheability metadata or setting #create_placeholder.
      \Drupal::moduleHandler()
        ->alter([
        'block_build',
        "block_build_" . $block
          ->getBaseId(),
      ], $block_build, $block);
      $build[$region][$block_placement_key] = $block_build;

      // After merging with blocks from Block layout, we want to sort all of
      // them again.
      $build[$region]['#sorted'] = FALSE;

      // The main content block cannot be cached: it is a placeholder for the
      // render array returned by the controller. It should be rendered as-is,
      // with other placed blocks "decorating" it. Analogous reasoning for the
      // title block.
      if ($block instanceof MainContentBlockPluginInterface || $block instanceof TitleBlockPluginInterface) {
        unset($build[$region][$block_placement_key]['#cache']['keys']);
      }
      $cacheability
        ->addCacheableDependency($block);
    }
  }
  $cacheability
    ->applyTo($build);
  return $build;
}