Pull merge.
[yaffs-website] / web / core / modules / layout_builder / src / EventSubscriber / BlockComponentRenderArray.php
1 <?php
2
3 namespace Drupal\layout_builder\EventSubscriber;
4
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;
15
16 /**
17  * Builds render arrays and handles access for all block components.
18  *
19  * @internal
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.
23  */
24 class BlockComponentRenderArray implements EventSubscriberInterface {
25
26   /**
27    * The current user.
28    *
29    * @var \Drupal\Core\Session\AccountInterface
30    */
31   protected $currentUser;
32
33   /**
34    * Creates a BlockComponentRenderArray object.
35    *
36    * @param \Drupal\Core\Session\AccountInterface $current_user
37    *   The current user.
38    */
39   public function __construct(AccountInterface $current_user) {
40     $this->currentUser = $current_user;
41   }
42
43   /**
44    * {@inheritdoc}
45    */
46   public static function getSubscribedEvents() {
47     $events[LayoutBuilderEvents::SECTION_COMPONENT_BUILD_RENDER_ARRAY] = ['onBuildRender', 100];
48     return $events;
49   }
50
51   /**
52    * Builds render arrays for block plugins and sets it on the event.
53    *
54    * @param \Drupal\layout_builder\Event\SectionComponentBuildRenderArrayEvent $event
55    *   The section component render event.
56    */
57   public function onBuildRender(SectionComponentBuildRenderArrayEvent $event) {
58     $block = $event->getPlugin();
59     if (!$block instanceof BlockPluginInterface) {
60       return;
61     }
62
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());
73           }
74           else {
75             $block->setAccessDependency($entity);
76           }
77         }
78       }
79     }
80
81     // Only check access if the component is not being previewed.
82     if ($event->inPreview()) {
83       $access = AccessResult::allowed()->setCacheMaxAge(0);
84     }
85     else {
86       $access = $block->access($this->currentUser, TRUE);
87     }
88
89     $event->addCacheableDependency($access);
90     if ($access->isAllowed()) {
91       $event->addCacheableDependency($block);
92
93       $build = [
94         // @todo Move this to BlockBase in https://www.drupal.org/node/2931040.
95         '#theme' => 'block',
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(),
102       ];
103       if ($event->inPreview() && Element::isEmpty($build['content']) && $block instanceof PreviewFallbackInterface) {
104         $build['content']['#markup'] = $block->getPreviewFallbackString();
105       }
106       $event->setBuild($build);
107     }
108   }
109
110 }