/** * #pre_render callback for building a block. * * Renders the content using the provided block plugin, and then: * - if there is no content, aborts rendering, and makes sure the block won't * be rendered. * - if there is content, moves the contextual links from the block content to * the block itself. */ public function buildBlock($build) { $content = $build['#block']->getPlugin()->build(); // Remove the block entity from the render array, to ensure that blocks // can be rendered without the block config entity. unset($build['#block']); if ($content !== NULL && !Element::isEmpty($content)) { // Place the $content returned by the block plugin into a 'content' child // element, as a way to allow the plugin to have complete control of its // properties and rendering (e.g., its own #theme) without conflicting // with the properties used above, or alternate ones used by alternate // block rendering approaches in contrib (e.g., Panels). However, the use // of a child element is an implementation detail of this particular block // rendering approach. Semantically, the content returned by the plugin // "is the" block, and in particular, #attributes and #contextual_links is // information about the *entire* block. Therefore, we must move these // properties from $content and merge them into the top-level element. foreach (array('#attributes', '#contextual_links') as $property) { if (isset($content[$property])) { $build[$property] += $content[$property]; unset($content[$property]); } } $build['content'] = $content; } else { // Abort rendering: render as the empty string and ensure this block is // render cached, so we can avoid the work of having to repeatedly // determine whether the block is empty. E.g. modifying or adding entities // could cause the block to no longer be empty. $build = array('#markup' => '', '#cache' => $build['#cache']); // If $content is not empty, then it contains cacheability metadata, and // we must merge it with the existing cacheability metadata. This allows // blocks to be empty, yet still bubble cacheability metadata, to indicate // why they are empty. if (!empty($content)) { CacheableMetadata::createFromRenderArray($build)->merge(CacheableMetadata::createFromRenderArray($content))->applyTo($build); } } return $build; }
/** * {@inheritdoc} */ public function build() { // Get block $block = $this->getBlock(); // Apply block config. $block_config = $this->blockConfig(); $block->setConfiguration($block_config); // Get render array. $block_elements = $block->build(); // Return an empty array if there is nothing to render. return Element::isEmpty($block_elements) ? [] : $block_elements; }
/** * Build render arrays for each of the regions. * * @param array $regions * The render array representing regions. * @param array $contexts * The array of context objects. * * @return array * An associative array, keyed by region ID, containing the render arrays * representing the content of each region. */ protected function buildRegions(array $regions, array $contexts) { $build = []; foreach ($regions as $region => $blocks) { if (!$blocks) { continue; } $region_name = Html::getClass("block-region-{$region}"); $build[$region]['#prefix'] = '<div class="' . $region_name . '">'; $build[$region]['#suffix'] = '</div>'; /** @var \Drupal\Core\Block\BlockPluginInterface[] $blocks */ $weight = 0; foreach ($blocks as $block_id => $block) { if ($block instanceof ContextAwarePluginInterface) { $this->contextHandler->applyContextMapping($block, $contexts); } if ($block->access($this->account)) { $block_render_array = ['#theme' => 'block', '#attributes' => [], '#contextual_links' => [], '#weight' => $weight++, '#configuration' => $block->getConfiguration(), '#plugin_id' => $block->getPluginId(), '#base_plugin_id' => $block->getBaseId(), '#derivative_plugin_id' => $block->getDerivativeId()]; // Build the block and bubble its attributes up if possible. This // allows modules like Quickedit to function. // See \Drupal\block\BlockViewBuilder::preRender() for reference. $content = $block->build(); if ($content !== NULL && !Element::isEmpty($content)) { foreach (['#attributes', '#contextual_links'] as $property) { if (isset($content[$property])) { $block_render_array[$property] += $content[$property]; unset($content[$property]); } } } $block_render_array['content'] = $content; $build[$region][$block_id] = $block_render_array; } } } return $build; }
/** * #pre_render callback for building a block. * * Renders the content using the provided block plugin, if there is no * content, aborts rendering, and makes sure the block won't be rendered. */ public function buildBlock($build) { $content = $build['#block_plugin']->build(); // Remove the block plugin from the render array. unset($build['#block_plugin']); if ($content !== NULL && !Element::isEmpty($content)) { $build['content'] = $content; } else { // Abort rendering: render as the empty string and ensure this block is // render cached, so we can avoid the work of having to repeatedly // determine whether the block is empty. E.g. modifying or adding entities // could cause the block to no longer be empty. $build = ['#markup' => '', '#cache' => $build['#cache']]; } // If $content is not empty, then it contains cacheability metadata, and // we must merge it with the existing cacheability metadata. This allows // blocks to be empty, yet still bubble cacheability metadata, to indicate // why they are empty. if (!empty($content)) { CacheableMetadata::createFromRenderArray($build)->merge(CacheableMetadata::createFromRenderArray($content))->applyTo($build); } return $build; }
/** * Indicates whether the given element is empty. * * An element that only has #cache set is considered empty, because it will * render to the empty string. * * @return bool * Whether the given element is empty. */ public function isEmpty() { return \Drupal\Core\Render\Element::isEmpty($this->array); }
/** * {@inheritdoc} */ public function submitForm(array &$form, FormStateInterface $form_state) { // Return early if there are any errors. if ($form_state->hasAnyErrors()) { return $form; } $block_instance = $this->getBlockInstance($form_state); // Submit the block configuration form. $this->submitBlock($block_instance, $form, $form_state); // If a temporary configuration for this variant exists, use it. $temp_store_key = $this->panelsDisplay->id(); if ($variant_config = $this->tempStore->get($temp_store_key)) { $this->panelsDisplay->setConfiguration($variant_config); } // Set the block region appropriately. $block_config = $block_instance->getConfiguration(); $block_config['region'] = $form_state->getValue(array('settings', 'region')); // Determine if we need to update or add this block. if ($uuid = $form_state->getValue('uuid')) { $this->panelsDisplay->updateBlock($uuid, $block_config); } else { $uuid = $this->panelsDisplay->addBlock($block_config); } // Set the tempstore value. $this->tempStore->set($this->panelsDisplay->id(), $this->panelsDisplay->getConfiguration()); // Assemble data required for our App. $build = $this->buildBlockInstance($block_instance); // Bubble block attributes up if possible. This allows modules like // Quickedit to function. // See \Drupal\block\BlockViewBuilder::preRender() for reference. if ($build['content'] !== NULL && !Element::isEmpty($build['content'])) { foreach (['#attributes', '#contextual_links'] as $property) { if (isset($build['content'][$property])) { $build[$property] += $build['content'][$property]; unset($build['content'][$property]); } } } // Add our data attribute for the Backbone app. $build['#attributes']['data-block-id'] = $uuid; $block_model = ['uuid' => $uuid, 'label' => $block_instance->label(), 'id' => $block_instance->getPluginId(), 'region' => $block_config['region'], 'html' => $this->renderer->render($build)]; $form['build'] = $build; // Add Block metadata and HTML as a drupalSetting. $form['#attached']['drupalSettings']['panels_ipe']['updated_block'] = $block_model; return $form; }
/** * @covers ::isEmpty * * @dataProvider providerTestIsEmpty */ public function testIsEmpty(array $element, $expected) { $this->assertSame(Element::isEmpty($element), $expected); }