Commit 749f41ff authored by webchick's avatar webchick

Issue #2921626 by tim.plunkett, EclipseGc, larowlan, dead_arm: Add proper...

Issue #2921626 by tim.plunkett, EclipseGc, larowlan, dead_arm: Add proper context-awareness to Layout Builder
parent 358989ea
......@@ -9,6 +9,9 @@
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\FieldableEntityInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\Context\Context;
use Drupal\Core\Plugin\Context\ContextDefinition;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
......@@ -166,9 +169,13 @@ function layout_builder_add_layout_section_field($entity_type_id, $bundle, $fiel
*/
function layout_builder_entity_view_alter(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display) {
if ($display->getThirdPartySetting('layout_builder', 'allow_custom', FALSE) && !$entity->layout_builder__layout->isEmpty()) {
$contexts = \Drupal::service('context.repository')->getAvailableContexts();
// @todo Use EntityContextDefinition after resolving
// https://www.drupal.org/node/2932462.
$contexts['layout_builder.entity'] = new Context(new ContextDefinition("entity:{$entity->getEntityTypeId()}", new TranslatableMarkup('@entity being viewed', ['@entity' => $entity->getEntityType()->getLabel()])), $entity);
$sections = $entity->layout_builder__layout->getSections();
foreach ($sections as $delta => $section) {
$build['_layout_builder'][$delta] = $section->toRenderArray();
$build['_layout_builder'][$delta] = $section->toRenderArray($contexts);
}
// If field layout is active, that is all that needs to be removed.
......
<?php
namespace Drupal\layout_builder\Context;
use Drupal\Core\Plugin\Context\ContextInterface;
use Drupal\layout_builder\SectionStorageInterface;
/**
* Provides a wrapper around getting contexts from a section storage object.
*/
trait LayoutBuilderContextTrait {
/**
* The context repository.
*
* @var \Drupal\Core\Plugin\Context\ContextRepositoryInterface
*/
protected $contextRepository;
/**
* Gets the context repository service.
*
* @return \Drupal\Core\Plugin\Context\ContextRepositoryInterface
* The context repository service.
*/
protected function contextRepository() {
if (!$this->contextRepository) {
$this->contextRepository = \Drupal::service('context.repository');
}
return $this->contextRepository;
}
/**
* Provides all available contexts, both global and section_storage-specific.
*
* @param \Drupal\layout_builder\SectionStorageInterface $section_storage
* The section storage.
*
* @return \Drupal\Core\Plugin\Context\ContextInterface[]
* The array of context objects.
*/
protected function getAvailableContexts(SectionStorageInterface $section_storage) {
// Get all globally available contexts that have a defined value.
$contexts = array_filter($this->contextRepository()->getAvailableContexts(), function (ContextInterface $context) {
return $context->hasContextValue();
});
// Add in the per-section_storage contexts.
$contexts += $section_storage->getContexts();
return $contexts;
}
}
......@@ -5,6 +5,7 @@
use Drupal\Core\Block\BlockManagerInterface;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Url;
use Drupal\layout_builder\Context\LayoutBuilderContextTrait;
use Drupal\layout_builder\SectionStorageInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
......@@ -16,6 +17,7 @@
class ChooseBlockController implements ContainerInjectionInterface {
use AjaxHelperTrait;
use LayoutBuilderContextTrait;
/**
* The block manager.
......@@ -60,7 +62,8 @@ public function build(SectionStorageInterface $section_storage, $delta, $region)
$build['#type'] = 'container';
$build['#attributes']['class'][] = 'block-categories';
foreach ($this->blockManager->getGroupedDefinitions() as $category => $blocks) {
$definitions = $this->blockManager->getDefinitionsForContexts($this->getAvailableContexts($section_storage));
foreach ($this->blockManager->getGroupedDefinitions($definitions) as $category => $blocks) {
$build[$category]['#type'] = 'details';
$build[$category]['#open'] = TRUE;
$build[$category]['#title'] = $category;
......
......@@ -6,6 +6,7 @@
use Drupal\Core\Plugin\PluginFormInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\Url;
use Drupal\layout_builder\Context\LayoutBuilderContextTrait;
use Drupal\layout_builder\LayoutTempstoreRepositoryInterface;
use Drupal\layout_builder\Section;
use Drupal\layout_builder\SectionStorageInterface;
......@@ -19,6 +20,7 @@
*/
class LayoutBuilderController implements ContainerInjectionInterface {
use LayoutBuilderContextTrait;
use StringTranslationTrait;
/**
......@@ -170,7 +172,7 @@ protected function buildAdministrativeSection(SectionStorageInterface $section_s
$section = $section_storage->getSection($delta);
$layout = $section->getLayout();
$build = $section->toRenderArray();
$build = $section->toRenderArray($this->getAvailableContexts($section_storage));
$layout_definition = $layout->getPluginDefinition();
foreach ($layout_definition->getRegions() as $region => $info) {
......
......@@ -3,6 +3,9 @@
namespace Drupal\layout_builder\Field;
use Drupal\Core\Field\FieldItemList;
use Drupal\Core\Plugin\Context\Context;
use Drupal\Core\Plugin\Context\ContextDefinition;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\layout_builder\Section;
use Drupal\layout_builder\SectionStorageInterface;
......@@ -74,6 +77,17 @@ public function removeSection($delta) {
return $this;
}
/**
* {@inheritdoc}
*/
public function getContexts() {
$entity = $this->getEntity();
// @todo Use EntityContextDefinition after resolving
// https://www.drupal.org/node/2932462.
$contexts['layout_builder.entity'] = new Context(new ContextDefinition("entity:{$entity->getEntityTypeId()}", new TranslatableMarkup('@entity being viewed', ['@entity' => $entity->getEntityType()->getLabel()])), $entity);
return $contexts;
}
/**
* {@inheritdoc}
*/
......
......@@ -14,6 +14,7 @@
use Drupal\Core\Plugin\ContextAwarePluginInterface;
use Drupal\Core\Plugin\PluginFormFactoryInterface;
use Drupal\Core\Plugin\PluginWithFormsInterface;
use Drupal\layout_builder\Context\LayoutBuilderContextTrait;
use Drupal\layout_builder\Controller\LayoutRebuildTrait;
use Drupal\layout_builder\LayoutTempstoreRepositoryInterface;
use Drupal\layout_builder\Section;
......@@ -29,6 +30,7 @@
use AjaxFormHelperTrait;
use ContextAwarePluginAssignmentTrait;
use LayoutBuilderContextTrait;
use LayoutRebuildTrait;
/**
......@@ -179,7 +181,7 @@ public function buildForm(array $form, FormStateInterface $form_state, SectionSt
$this->region = $region;
$this->block = $this->prepareBlock($plugin_id, $configuration);
$form_state->setTemporaryValue('gathered_contexts', $this->contextRepository->getAvailableContexts());
$form_state->setTemporaryValue('gathered_contexts', $this->getAvailableContexts($section_storage));
// @todo Remove once https://www.drupal.org/node/2268787 is resolved.
$form_state->set('block_theme', $this->config('system.theme')->get('default'));
......
......@@ -66,13 +66,16 @@ public function __construct($layout_id, array $layout_settings = [], array $comp
/**
* Returns the renderable array for this section.
*
* @param \Drupal\Core\Plugin\Context\ContextInterface[] $contexts
* An array of available contexts.
*
* @return array
* A renderable array representing the content of the section.
*/
public function toRenderArray() {
public function toRenderArray(array $contexts = []) {
$regions = [];
foreach ($this->getComponents() as $component) {
if ($output = $component->toRenderArray()) {
if ($output = $component->toRenderArray($contexts)) {
$regions[$component->getRegion()][$component->getUuid()] = $output;
}
}
......
......@@ -88,13 +88,16 @@ public function __construct($uuid, $region, array $configuration = [], array $ad
/**
* Returns the renderable array for this component.
*
* @param \Drupal\Core\Plugin\Context\ContextInterface[] $contexts
* An array of available contexts.
*
* @return array
* A renderable array representing the content of the component.
*/
public function toRenderArray() {
public function toRenderArray(array $contexts = []) {
$output = [];
$plugin = $this->getPlugin();
$plugin = $this->getPlugin($contexts);
// @todo Figure out the best way to unify fields and blocks and components
// in https://www.drupal.org/node/1875974.
if ($plugin instanceof BlockPluginInterface) {
......@@ -259,13 +262,15 @@ public function getUuid() {
/**
* Gets the plugin for this component.
*
* @param \Drupal\Core\Plugin\Context\ContextInterface[] $contexts
* An array of contexts to set on the plugin.
*
* @return \Drupal\Component\Plugin\PluginInspectionInterface
* The plugin.
*/
public function getPlugin() {
public function getPlugin(array $contexts = []) {
$plugin = $this->pluginManager()->createInstance($this->getPluginId(), $this->getConfiguration());
if ($plugin instanceof ContextAwarePluginInterface) {
$contexts = $this->contextRepository()->getRuntimeContexts(array_values($plugin->getContextMapping()));
if ($contexts && $plugin instanceof ContextAwarePluginInterface) {
$this->contextHandler()->applyContextMapping($plugin, $contexts);
}
return $plugin;
......@@ -281,16 +286,6 @@ protected function pluginManager() {
return \Drupal::service('plugin.manager.block');
}
/**
* Wraps the context repository.
*
* @return \Drupal\Core\Plugin\Context\ContextRepositoryInterface
* The context repository.
*/
protected function contextRepository() {
return \Drupal::service('context.repository');
}
/**
* Wraps the context handler.
*
......
......@@ -68,6 +68,14 @@ public function insertSection($delta, Section $section);
*/
public function removeSection($delta);
/**
* Provides any available contexts for the object using the sections.
*
* @return \Drupal\Core\Plugin\Context\ContextInterface[]
* The array of context objects.
*/
public function getContexts();
/**
* Returns an identifier for this storage.
*
......
......@@ -55,7 +55,7 @@ protected function setUp() {
*/
public function providerTestLayoutSectionFormatter() {
$data = [];
$data['block_with_context'] = [
$data['block_with_global_context'] = [
[
[
'section' => new Section('layout_onecol', [], [
......@@ -80,6 +80,31 @@ public function providerTestLayoutSectionFormatter() {
'user:2',
'UNCACHEABLE',
];
$data['block_with_entity_context'] = [
[
[
'section' => new Section('layout_onecol', [], [
'baz' => new SectionComponent('baz', 'content', [
'id' => 'field_block:node:body',
'context_mapping' => [
'entity' => 'layout_builder.entity',
],
]),
]),
],
],
[
'.layout--onecol',
'.field--name-body',
],
[
'Body',
'The node body',
],
'',
'',
'MISS',
];
$data['single_section_single_block'] = [
[
[
......
......@@ -199,9 +199,6 @@ public function testContextAwareBlock() {
$block->getDerivativeId()->willReturn(NULL);
$block->getConfiguration()->willReturn([]);
$this->contextRepository->getRuntimeContexts([])->willReturn([]);
$this->contextHandler->applyContextMapping($block->reveal(), [])->shouldBeCalled();
$section = [
new SectionComponent('some_uuid', 'content', ['id' => 'block_plugin_id']),
];
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment