Chris@14
|
1 <?php
|
Chris@14
|
2
|
Chris@14
|
3 namespace Drupal\layout_builder\EventSubscriber;
|
Chris@14
|
4
|
Chris@17
|
5 use Drupal\block_content\Access\RefinableDependentAccessInterface;
|
Chris@14
|
6 use Drupal\Core\Access\AccessResult;
|
Chris@14
|
7 use Drupal\Core\Block\BlockPluginInterface;
|
Chris@17
|
8 use Drupal\Core\Render\Element;
|
Chris@17
|
9 use Drupal\Core\Render\PreviewFallbackInterface;
|
Chris@14
|
10 use Drupal\Core\Session\AccountInterface;
|
Chris@17
|
11 use Drupal\layout_builder\Access\LayoutPreviewAccessAllowed;
|
Chris@14
|
12 use Drupal\layout_builder\Event\SectionComponentBuildRenderArrayEvent;
|
Chris@14
|
13 use Drupal\layout_builder\LayoutBuilderEvents;
|
Chris@14
|
14 use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
Chris@14
|
15
|
Chris@14
|
16 /**
|
Chris@14
|
17 * Builds render arrays and handles access for all block components.
|
Chris@14
|
18 *
|
Chris@14
|
19 * @internal
|
Chris@14
|
20 * Layout Builder is currently experimental and should only be leveraged by
|
Chris@14
|
21 * experimental modules and development releases of contributed modules.
|
Chris@14
|
22 * See https://www.drupal.org/core/experimental for more information.
|
Chris@14
|
23 */
|
Chris@14
|
24 class BlockComponentRenderArray implements EventSubscriberInterface {
|
Chris@14
|
25
|
Chris@14
|
26 /**
|
Chris@14
|
27 * The current user.
|
Chris@14
|
28 *
|
Chris@14
|
29 * @var \Drupal\Core\Session\AccountInterface
|
Chris@14
|
30 */
|
Chris@14
|
31 protected $currentUser;
|
Chris@14
|
32
|
Chris@14
|
33 /**
|
Chris@14
|
34 * Creates a BlockComponentRenderArray object.
|
Chris@14
|
35 *
|
Chris@14
|
36 * @param \Drupal\Core\Session\AccountInterface $current_user
|
Chris@14
|
37 * The current user.
|
Chris@14
|
38 */
|
Chris@14
|
39 public function __construct(AccountInterface $current_user) {
|
Chris@14
|
40 $this->currentUser = $current_user;
|
Chris@14
|
41 }
|
Chris@14
|
42
|
Chris@14
|
43 /**
|
Chris@14
|
44 * {@inheritdoc}
|
Chris@14
|
45 */
|
Chris@14
|
46 public static function getSubscribedEvents() {
|
Chris@14
|
47 $events[LayoutBuilderEvents::SECTION_COMPONENT_BUILD_RENDER_ARRAY] = ['onBuildRender', 100];
|
Chris@14
|
48 return $events;
|
Chris@14
|
49 }
|
Chris@14
|
50
|
Chris@14
|
51 /**
|
Chris@14
|
52 * Builds render arrays for block plugins and sets it on the event.
|
Chris@14
|
53 *
|
Chris@14
|
54 * @param \Drupal\layout_builder\Event\SectionComponentBuildRenderArrayEvent $event
|
Chris@14
|
55 * The section component render event.
|
Chris@14
|
56 */
|
Chris@14
|
57 public function onBuildRender(SectionComponentBuildRenderArrayEvent $event) {
|
Chris@14
|
58 $block = $event->getPlugin();
|
Chris@14
|
59 if (!$block instanceof BlockPluginInterface) {
|
Chris@14
|
60 return;
|
Chris@14
|
61 }
|
Chris@14
|
62
|
Chris@17
|
63 // Set block access dependency even if we are not checking access on
|
Chris@17
|
64 // this level. The block itself may render another
|
Chris@17
|
65 // RefinableDependentAccessInterface object and need to pass on this value.
|
Chris@17
|
66 if ($block instanceof RefinableDependentAccessInterface) {
|
Chris@17
|
67 $contexts = $event->getContexts();
|
Chris@17
|
68 if (isset($contexts['layout_builder.entity'])) {
|
Chris@17
|
69 if ($entity = $contexts['layout_builder.entity']->getContextValue()) {
|
Chris@17
|
70 if ($event->inPreview()) {
|
Chris@17
|
71 // If previewing in Layout Builder allow access.
|
Chris@17
|
72 $block->setAccessDependency(new LayoutPreviewAccessAllowed());
|
Chris@17
|
73 }
|
Chris@17
|
74 else {
|
Chris@17
|
75 $block->setAccessDependency($entity);
|
Chris@17
|
76 }
|
Chris@17
|
77 }
|
Chris@17
|
78 }
|
Chris@17
|
79 }
|
Chris@17
|
80
|
Chris@14
|
81 // Only check access if the component is not being previewed.
|
Chris@14
|
82 if ($event->inPreview()) {
|
Chris@14
|
83 $access = AccessResult::allowed()->setCacheMaxAge(0);
|
Chris@14
|
84 }
|
Chris@14
|
85 else {
|
Chris@14
|
86 $access = $block->access($this->currentUser, TRUE);
|
Chris@14
|
87 }
|
Chris@14
|
88
|
Chris@14
|
89 $event->addCacheableDependency($access);
|
Chris@14
|
90 if ($access->isAllowed()) {
|
Chris@14
|
91 $event->addCacheableDependency($block);
|
Chris@14
|
92
|
Chris@17
|
93 $content = $block->build();
|
Chris@17
|
94 $is_content_empty = Element::isEmpty($content);
|
Chris@17
|
95 $is_placeholder_ready = $event->inPreview() && $block instanceof PreviewFallbackInterface;
|
Chris@17
|
96 // If the content is empty and no placeholder is available, return.
|
Chris@17
|
97 if ($is_content_empty && !$is_placeholder_ready) {
|
Chris@17
|
98 return;
|
Chris@17
|
99 }
|
Chris@17
|
100
|
Chris@14
|
101 $build = [
|
Chris@14
|
102 // @todo Move this to BlockBase in https://www.drupal.org/node/2931040.
|
Chris@14
|
103 '#theme' => 'block',
|
Chris@14
|
104 '#configuration' => $block->getConfiguration(),
|
Chris@14
|
105 '#plugin_id' => $block->getPluginId(),
|
Chris@14
|
106 '#base_plugin_id' => $block->getBaseId(),
|
Chris@14
|
107 '#derivative_plugin_id' => $block->getDerivativeId(),
|
Chris@14
|
108 '#weight' => $event->getComponent()->getWeight(),
|
Chris@17
|
109 'content' => $content,
|
Chris@14
|
110 ];
|
Chris@17
|
111 if ($is_content_empty && $is_placeholder_ready) {
|
Chris@17
|
112 $build['content']['#markup'] = $block->getPreviewFallbackString();
|
Chris@17
|
113 }
|
Chris@14
|
114 $event->setBuild($build);
|
Chris@14
|
115 }
|
Chris@14
|
116 }
|
Chris@14
|
117
|
Chris@14
|
118 }
|