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@18
|
11 use Drupal\Core\StringTranslation\StringTranslationTrait;
|
Chris@17
|
12 use Drupal\layout_builder\Access\LayoutPreviewAccessAllowed;
|
Chris@14
|
13 use Drupal\layout_builder\Event\SectionComponentBuildRenderArrayEvent;
|
Chris@14
|
14 use Drupal\layout_builder\LayoutBuilderEvents;
|
Chris@18
|
15 use Drupal\views\Plugin\Block\ViewsBlock;
|
Chris@14
|
16 use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
Chris@14
|
17
|
Chris@14
|
18 /**
|
Chris@14
|
19 * Builds render arrays and handles access for all block components.
|
Chris@14
|
20 *
|
Chris@14
|
21 * @internal
|
Chris@18
|
22 * Tagged services are internal.
|
Chris@14
|
23 */
|
Chris@14
|
24 class BlockComponentRenderArray implements EventSubscriberInterface {
|
Chris@14
|
25
|
Chris@18
|
26 use StringTranslationTrait;
|
Chris@18
|
27
|
Chris@14
|
28 /**
|
Chris@14
|
29 * The current user.
|
Chris@14
|
30 *
|
Chris@14
|
31 * @var \Drupal\Core\Session\AccountInterface
|
Chris@14
|
32 */
|
Chris@14
|
33 protected $currentUser;
|
Chris@14
|
34
|
Chris@14
|
35 /**
|
Chris@14
|
36 * Creates a BlockComponentRenderArray object.
|
Chris@14
|
37 *
|
Chris@14
|
38 * @param \Drupal\Core\Session\AccountInterface $current_user
|
Chris@14
|
39 * The current user.
|
Chris@14
|
40 */
|
Chris@14
|
41 public function __construct(AccountInterface $current_user) {
|
Chris@14
|
42 $this->currentUser = $current_user;
|
Chris@14
|
43 }
|
Chris@14
|
44
|
Chris@14
|
45 /**
|
Chris@14
|
46 * {@inheritdoc}
|
Chris@14
|
47 */
|
Chris@14
|
48 public static function getSubscribedEvents() {
|
Chris@14
|
49 $events[LayoutBuilderEvents::SECTION_COMPONENT_BUILD_RENDER_ARRAY] = ['onBuildRender', 100];
|
Chris@14
|
50 return $events;
|
Chris@14
|
51 }
|
Chris@14
|
52
|
Chris@14
|
53 /**
|
Chris@14
|
54 * Builds render arrays for block plugins and sets it on the event.
|
Chris@14
|
55 *
|
Chris@14
|
56 * @param \Drupal\layout_builder\Event\SectionComponentBuildRenderArrayEvent $event
|
Chris@14
|
57 * The section component render event.
|
Chris@14
|
58 */
|
Chris@14
|
59 public function onBuildRender(SectionComponentBuildRenderArrayEvent $event) {
|
Chris@14
|
60 $block = $event->getPlugin();
|
Chris@14
|
61 if (!$block instanceof BlockPluginInterface) {
|
Chris@14
|
62 return;
|
Chris@14
|
63 }
|
Chris@14
|
64
|
Chris@17
|
65 // Set block access dependency even if we are not checking access on
|
Chris@17
|
66 // this level. The block itself may render another
|
Chris@17
|
67 // RefinableDependentAccessInterface object and need to pass on this value.
|
Chris@17
|
68 if ($block instanceof RefinableDependentAccessInterface) {
|
Chris@17
|
69 $contexts = $event->getContexts();
|
Chris@17
|
70 if (isset($contexts['layout_builder.entity'])) {
|
Chris@17
|
71 if ($entity = $contexts['layout_builder.entity']->getContextValue()) {
|
Chris@17
|
72 if ($event->inPreview()) {
|
Chris@17
|
73 // If previewing in Layout Builder allow access.
|
Chris@17
|
74 $block->setAccessDependency(new LayoutPreviewAccessAllowed());
|
Chris@17
|
75 }
|
Chris@17
|
76 else {
|
Chris@17
|
77 $block->setAccessDependency($entity);
|
Chris@17
|
78 }
|
Chris@17
|
79 }
|
Chris@17
|
80 }
|
Chris@17
|
81 }
|
Chris@17
|
82
|
Chris@14
|
83 // Only check access if the component is not being previewed.
|
Chris@14
|
84 if ($event->inPreview()) {
|
Chris@14
|
85 $access = AccessResult::allowed()->setCacheMaxAge(0);
|
Chris@14
|
86 }
|
Chris@14
|
87 else {
|
Chris@14
|
88 $access = $block->access($this->currentUser, TRUE);
|
Chris@14
|
89 }
|
Chris@14
|
90
|
Chris@14
|
91 $event->addCacheableDependency($access);
|
Chris@14
|
92 if ($access->isAllowed()) {
|
Chris@14
|
93 $event->addCacheableDependency($block);
|
Chris@14
|
94
|
Chris@18
|
95 // @todo Revisit after https://www.drupal.org/node/3027653, as this will
|
Chris@18
|
96 // provide a better way to remove contextual links from Views blocks.
|
Chris@18
|
97 // Currently, doing this requires setting
|
Chris@18
|
98 // \Drupal\views\ViewExecutable::$showAdminLinks() to false before the
|
Chris@18
|
99 // Views block is built.
|
Chris@18
|
100 if ($block instanceof ViewsBlock && $event->inPreview()) {
|
Chris@18
|
101 $block->getViewExecutable()->setShowAdminLinks(FALSE);
|
Chris@18
|
102 }
|
Chris@18
|
103
|
Chris@17
|
104 $content = $block->build();
|
Chris@17
|
105 $is_content_empty = Element::isEmpty($content);
|
Chris@17
|
106 $is_placeholder_ready = $event->inPreview() && $block instanceof PreviewFallbackInterface;
|
Chris@17
|
107 // If the content is empty and no placeholder is available, return.
|
Chris@17
|
108 if ($is_content_empty && !$is_placeholder_ready) {
|
Chris@17
|
109 return;
|
Chris@17
|
110 }
|
Chris@17
|
111
|
Chris@14
|
112 $build = [
|
Chris@14
|
113 // @todo Move this to BlockBase in https://www.drupal.org/node/2931040.
|
Chris@14
|
114 '#theme' => 'block',
|
Chris@14
|
115 '#configuration' => $block->getConfiguration(),
|
Chris@14
|
116 '#plugin_id' => $block->getPluginId(),
|
Chris@14
|
117 '#base_plugin_id' => $block->getBaseId(),
|
Chris@14
|
118 '#derivative_plugin_id' => $block->getDerivativeId(),
|
Chris@14
|
119 '#weight' => $event->getComponent()->getWeight(),
|
Chris@17
|
120 'content' => $content,
|
Chris@14
|
121 ];
|
Chris@18
|
122
|
Chris@18
|
123 if ($block instanceof PreviewFallbackInterface) {
|
Chris@18
|
124 $preview_fallback_string = $block->getPreviewFallbackString();
|
Chris@18
|
125 }
|
Chris@18
|
126 else {
|
Chris@18
|
127 $preview_fallback_string = $this->t('"@block" block', ['@block' => $block->label()]);
|
Chris@18
|
128 }
|
Chris@18
|
129 // @todo Use new label methods so
|
Chris@18
|
130 // data-layout-content-preview-placeholder-label doesn't have to use
|
Chris@18
|
131 // preview fallback in https://www.drupal.org/node/2025649.
|
Chris@18
|
132 $build['#attributes']['data-layout-content-preview-placeholder-label'] = $preview_fallback_string;
|
Chris@18
|
133
|
Chris@17
|
134 if ($is_content_empty && $is_placeholder_ready) {
|
Chris@18
|
135 $build['content']['#markup'] = $this->t('Placeholder for the @preview_fallback', ['@preview_fallback' => $block->getPreviewFallbackString()]);
|
Chris@17
|
136 }
|
Chris@14
|
137 $event->setBuild($build);
|
Chris@14
|
138 }
|
Chris@14
|
139 }
|
Chris@14
|
140
|
Chris@14
|
141 }
|