class BlockComponentRenderArray

Same name in other branches
  1. 8.9.x core/modules/layout_builder/src/EventSubscriber/BlockComponentRenderArray.php \Drupal\layout_builder\EventSubscriber\BlockComponentRenderArray
  2. 10 core/modules/layout_builder/src/EventSubscriber/BlockComponentRenderArray.php \Drupal\layout_builder\EventSubscriber\BlockComponentRenderArray
  3. 11.x core/modules/layout_builder/src/EventSubscriber/BlockComponentRenderArray.php \Drupal\layout_builder\EventSubscriber\BlockComponentRenderArray

Builds render arrays and handles access for all block components.

@internal Tagged services are internal.

Hierarchy

Expanded class hierarchy of BlockComponentRenderArray

2 files declare their use of BlockComponentRenderArray
BlockComponentRenderArrayTest.php in core/modules/layout_builder/tests/src/Unit/BlockComponentRenderArrayTest.php
SectionRenderTest.php in core/modules/layout_builder/tests/src/Unit/SectionRenderTest.php
1 string reference to 'BlockComponentRenderArray'
layout_builder.services.yml in core/modules/layout_builder/layout_builder.services.yml
core/modules/layout_builder/layout_builder.services.yml
1 service uses BlockComponentRenderArray
layout_builder.render_block_component_subscriber in core/modules/layout_builder/layout_builder.services.yml
Drupal\layout_builder\EventSubscriber\BlockComponentRenderArray

File

core/modules/layout_builder/src/EventSubscriber/BlockComponentRenderArray.php, line 26

Namespace

Drupal\layout_builder\EventSubscriber
View source
class BlockComponentRenderArray implements EventSubscriberInterface {
    use StringTranslationTrait;
    
    /**
     * The current user.
     *
     * @var \Drupal\Core\Session\AccountInterface
     */
    protected $currentUser;
    
    /**
     * Creates a BlockComponentRenderArray object.
     *
     * @param \Drupal\Core\Session\AccountInterface $current_user
     *   The current user.
     */
    public function __construct(AccountInterface $current_user) {
        $this->currentUser = $current_user;
    }
    
    /**
     * {@inheritdoc}
     */
    public static function getSubscribedEvents() {
        $events[LayoutBuilderEvents::SECTION_COMPONENT_BUILD_RENDER_ARRAY] = [
            'onBuildRender',
            100,
        ];
        return $events;
    }
    
    /**
     * Builds render arrays for block plugins and sets it on the event.
     *
     * @param \Drupal\layout_builder\Event\SectionComponentBuildRenderArrayEvent $event
     *   The section component render event.
     */
    public function onBuildRender(SectionComponentBuildRenderArrayEvent $event) {
        $block = $event->getPlugin();
        if (!$block instanceof BlockPluginInterface) {
            return;
        }
        // Set block access dependency even if we are not checking access on
        // this level. The block itself may render another
        // RefinableDependentAccessInterface object and need to pass on this value.
        if ($block instanceof RefinableDependentAccessInterface) {
            $contexts = $event->getContexts();
            if (isset($contexts['layout_builder.entity'])) {
                if ($entity = $contexts['layout_builder.entity']->getContextValue()) {
                    if ($event->inPreview()) {
                        // If previewing in Layout Builder allow access.
                        $block->setAccessDependency(new LayoutPreviewAccessAllowed());
                    }
                    else {
                        $block->setAccessDependency($entity);
                    }
                }
            }
        }
        // Only check access if the component is not being previewed.
        if ($event->inPreview()) {
            $access = AccessResult::allowed()->setCacheMaxAge(0);
        }
        else {
            $access = $block->access($this->currentUser, TRUE);
        }
        $event->addCacheableDependency($access);
        if ($access->isAllowed()) {
            $event->addCacheableDependency($block);
            // @todo Revisit after https://www.drupal.org/node/3027653, as this will
            //   provide a better way to remove contextual links from Views blocks.
            //   Currently, doing this requires setting
            //   \Drupal\views\ViewExecutable::$showAdminLinks() to false before the
            //   Views block is built.
            if ($block instanceof ViewsBlock && $event->inPreview()) {
                $block->getViewExecutable()
                    ->setShowAdminLinks(FALSE);
            }
            $content = $block->build();
            // We don't output the block render data if there are no render elements
            // found, but we want to capture the cache metadata from the block
            // regardless.
            $event->addCacheableDependency(CacheableMetadata::createFromRenderArray($content));
            $is_content_empty = Element::isEmpty($content);
            $is_placeholder_ready = $event->inPreview() && $block instanceof PreviewFallbackInterface;
            // If the content is empty and no placeholder is available, return.
            if ($is_content_empty && !$is_placeholder_ready) {
                return;
            }
            $build = [
                // @todo Move this to BlockBase in https://www.drupal.org/node/2931040.
'#theme' => 'block',
                '#configuration' => $block->getConfiguration(),
                '#plugin_id' => $block->getPluginId(),
                '#base_plugin_id' => $block->getBaseId(),
                '#derivative_plugin_id' => $block->getDerivativeId(),
                '#in_preview' => $event->inPreview(),
                '#weight' => $event->getComponent()
                    ->getWeight(),
            ];
            // Place the $content returned by the block plugin into a 'content' child
            // element, as a way to allow the plugin to have complete control of its
            // properties and rendering (for instance, its own #theme) without
            // conflicting with the properties used above, or alternate ones used by
            // alternate block rendering approaches in contributed modules. However,
            // the use of a child element is an implementation detail of this
            // particular block rendering approach. Semantically, the content returned
            // by the block plugin, and in particular, attributes and contextual links
            // are information that belong to the entire block. Therefore, we must
            // move these properties from $content and merge them into the top-level
            // element.
            if (isset($content['#attributes'])) {
                $build['#attributes'] = $content['#attributes'];
                unset($content['#attributes']);
            }
            // Hide contextual links for inline blocks until the UX issues surrounding
            // editing them directly are resolved.
            // @see https://www.drupal.org/project/drupal/issues/3075308
            if (!$block instanceof InlineBlock && !empty($content['#contextual_links'])) {
                $build['#contextual_links'] = $content['#contextual_links'];
            }
            $build['content'] = $content;
            if ($event->inPreview()) {
                if ($block instanceof PreviewFallbackInterface) {
                    $preview_fallback_string = $block->getPreviewFallbackString();
                }
                else {
                    $preview_fallback_string = $this->t('"@block" block', [
                        '@block' => $block->label(),
                    ]);
                }
                // @todo Use new label methods so
                //   data-layout-content-preview-placeholder-label doesn't have to use
                //   preview fallback in https://www.drupal.org/node/2025649.
                $build['#attributes']['data-layout-content-preview-placeholder-label'] = $preview_fallback_string;
                if ($is_content_empty && $is_placeholder_ready) {
                    $build['content']['#markup'] = $this->t('Placeholder for the @preview_fallback', [
                        '@preview_fallback' => $block->getPreviewFallbackString(),
                    ]);
                }
            }
            $event->setBuild($build);
        }
    }

}

Members

Title Sort descending Modifiers Object type Summary Overrides
BlockComponentRenderArray::$currentUser protected property The current user.
BlockComponentRenderArray::getSubscribedEvents public static function
BlockComponentRenderArray::onBuildRender public function Builds render arrays for block plugins and sets it on the event.
BlockComponentRenderArray::__construct public function Creates a BlockComponentRenderArray object.
StringTranslationTrait::$stringTranslation protected property The string translation service. 3
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.