annotate core/modules/layout_builder/src/EventSubscriber/BlockComponentRenderArray.php @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents af1871eacc83
children
rev   line source
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 }