3 namespace Drupal\layout_builder\EventSubscriber;
5 use Drupal\block_content\Access\RefinableDependentAccessInterface;
6 use Drupal\Core\Access\AccessResult;
7 use Drupal\Core\Block\BlockPluginInterface;
8 use Drupal\Core\Render\Element;
9 use Drupal\Core\Render\PreviewFallbackInterface;
10 use Drupal\Core\Session\AccountInterface;
11 use Drupal\layout_builder\Access\LayoutPreviewAccessAllowed;
12 use Drupal\layout_builder\Event\SectionComponentBuildRenderArrayEvent;
13 use Drupal\layout_builder\LayoutBuilderEvents;
14 use Symfony\Component\EventDispatcher\EventSubscriberInterface;
17 * Builds render arrays and handles access for all block components.
20 * Layout Builder is currently experimental and should only be leveraged by
21 * experimental modules and development releases of contributed modules.
22 * See https://www.drupal.org/core/experimental for more information.
24 class BlockComponentRenderArray implements EventSubscriberInterface {
29 * @var \Drupal\Core\Session\AccountInterface
31 protected $currentUser;
34 * Creates a BlockComponentRenderArray object.
36 * @param \Drupal\Core\Session\AccountInterface $current_user
39 public function __construct(AccountInterface $current_user) {
40 $this->currentUser = $current_user;
46 public static function getSubscribedEvents() {
47 $events[LayoutBuilderEvents::SECTION_COMPONENT_BUILD_RENDER_ARRAY] = ['onBuildRender', 100];
52 * Builds render arrays for block plugins and sets it on the event.
54 * @param \Drupal\layout_builder\Event\SectionComponentBuildRenderArrayEvent $event
55 * The section component render event.
57 public function onBuildRender(SectionComponentBuildRenderArrayEvent $event) {
58 $block = $event->getPlugin();
59 if (!$block instanceof BlockPluginInterface) {
63 // Set block access dependency even if we are not checking access on
64 // this level. The block itself may render another
65 // RefinableDependentAccessInterface object and need to pass on this value.
66 if ($block instanceof RefinableDependentAccessInterface) {
67 $contexts = $event->getContexts();
68 if (isset($contexts['layout_builder.entity'])) {
69 if ($entity = $contexts['layout_builder.entity']->getContextValue()) {
70 if ($event->inPreview()) {
71 // If previewing in Layout Builder allow access.
72 $block->setAccessDependency(new LayoutPreviewAccessAllowed());
75 $block->setAccessDependency($entity);
81 // Only check access if the component is not being previewed.
82 if ($event->inPreview()) {
83 $access = AccessResult::allowed()->setCacheMaxAge(0);
86 $access = $block->access($this->currentUser, TRUE);
89 $event->addCacheableDependency($access);
90 if ($access->isAllowed()) {
91 $event->addCacheableDependency($block);
94 // @todo Move this to BlockBase in https://www.drupal.org/node/2931040.
96 '#configuration' => $block->getConfiguration(),
97 '#plugin_id' => $block->getPluginId(),
98 '#base_plugin_id' => $block->getBaseId(),
99 '#derivative_plugin_id' => $block->getDerivativeId(),
100 '#weight' => $event->getComponent()->getWeight(),
101 'content' => $block->build(),
103 if ($event->inPreview() && Element::isEmpty($build['content']) && $block instanceof PreviewFallbackInterface) {
104 $build['content']['#markup'] = $block->getPreviewFallbackString();
106 $event->setBuild($build);