Issue #3001313 by bnjmnm, tim.plunkett, bobbygryzynger, Cyberschorsch, yogeshmpawar, mikey en, hershy.k, borisson_: Field blocks in the layout builder do not have view mode suggestions

merge-requests/1119/head
Lee Rowlands 2019-06-28 07:26:47 +10:00
parent 81179a0baa
commit 90534acefb
No known key found for this signature in database
GPG Key ID: 2B829A3DF9204DC4
17 changed files with 225 additions and 7 deletions

View File

@ -405,3 +405,15 @@ function layout_builder_preprocess_language_content_settings_table(&$variables)
}
}
}
/**
* Implements hook_theme_suggestions_HOOK_alter().
*/
function layout_builder_theme_suggestions_field_alter(&$suggestions, array $variables) {
$element = $variables['element'];
if (isset($element['#third_party_settings']['layout_builder']['view_mode'])) {
// See system_theme_suggestions_field().
$suggestions[] = 'field__' . $element['#entity_type'] . '__' . $element['#field_name'] . '__' . $element['#bundle'] . '__' . $element['#third_party_settings']['layout_builder']['view_mode'];
}
return $suggestions;
}

View File

@ -109,6 +109,7 @@ trait LayoutEntityHelperTrait {
$view_mode = 'full';
if ($entity instanceof LayoutEntityDisplayInterface) {
$contexts['display'] = EntityContext::fromEntity($entity);
$contexts['view_mode'] = new Context(new ContextDefinition('string'), $entity->getMode());
}
else {
$contexts['entity'] = EntityContext::fromEntity($entity);

View File

@ -156,6 +156,7 @@ class FieldBlock extends BlockBase implements ContextAwarePluginInterface, Conta
*/
public function build() {
$display_settings = $this->getConfiguration()['formatter'];
$display_settings['third_party_settings']['layout_builder']['view_mode'] = $this->getContextValue('view_mode');
$entity = $this->getEntity();
try {
$build = $entity->get($this->fieldName)->view($display_settings);

View File

@ -9,6 +9,7 @@ use Drupal\Core\Entity\EntityTypeRepositoryInterface;
use Drupal\Core\Field\FieldConfigInterface;
use Drupal\Core\Field\FieldTypePluginManagerInterface;
use Drupal\Core\Field\FormatterPluginManager;
use Drupal\Core\Plugin\Context\ContextDefinition;
use Drupal\Core\Plugin\Context\EntityContextDefinition;
use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
@ -123,6 +124,7 @@ class FieldBlockDeriver extends DeriverBase implements ContainerDeriverInterface
$context_definition->addConstraint('Bundle', [$bundle]);
$derivative['context_definitions'] = [
'entity' => $context_definition,
'view_mode' => new ContextDefinition('string'),
];
$derivative_id = $entity_type_id . PluginBase::DERIVATIVE_SEPARATOR . $bundle . PluginBase::DERIVATIVE_SEPARATOR . $field_name;

View File

@ -2,6 +2,7 @@
namespace Drupal\layout_builder\Plugin\SectionStorage;
use Drupal\Component\Plugin\Context\ContextInterface as ComponentContextInterface;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Cache\RefinableCacheableDependencyInterface;
@ -33,6 +34,7 @@ use Symfony\Component\Routing\RouteCollection;
* weight = 20,
* context_definitions = {
* "display" = @ContextDefinition("entity:entity_view_display"),
* "view_mode" = @ContextDefinition("string", default_value = "default"),
* },
* )
*
@ -432,4 +434,15 @@ class DefaultsSectionStorage extends SectionStorageBase implements ContainerFact
return $this->isLayoutBuilderEnabled();
}
/**
* {@inheritdoc}
*/
public function setContext($name, ComponentContextInterface $context) {
// Set the view mode context based on the display context.
if ($name === 'display') {
$this->setContextValue('view_mode', $context->getContextValue()->getMode());
}
parent::setContext($name, $context);
}
}

View File

@ -39,7 +39,7 @@ use Symfony\Component\Routing\RouteCollection;
* "entity" = @ContextDefinition("entity", constraints = {
* "EntityHasField" = \Drupal\layout_builder\Plugin\SectionStorage\OverridesSectionStorage::FIELD_NAME,
* }),
* "view_mode" = @ContextDefinition("string"),
* "view_mode" = @ContextDefinition("string", default_value = "default"),
* }
* )
*

View File

@ -2,6 +2,8 @@
namespace Drupal\layout_builder\Plugin\SectionStorage;
use Drupal\Core\Plugin\Context\Context;
use Drupal\Core\Plugin\Context\ContextDefinition;
use Drupal\Core\Plugin\ContextAwarePluginBase;
use Drupal\layout_builder\Routing\LayoutBuilderRoutesTrait;
use Drupal\layout_builder\Section;
@ -109,7 +111,16 @@ abstract class SectionStorageBase extends ContextAwarePluginBase implements Sect
* {@inheritdoc}
*/
public function getContextsDuringPreview() {
return $this->getContexts();
$contexts = $this->getContexts();
// view_mode is a required context, but SectionStorage plugins are not
// required to return it (for example, the layout_library plugin provided
// in the Layout Library module. In these instances, explicitly create a
// view_mode context with the value "default".
if (!isset($contexts['view_mode']) || $contexts['view_mode']->validate()->count() || !$contexts['view_mode']->getContextValue()) {
$contexts['view_mode'] = new Context(new ContextDefinition('string'), 'default');
}
return $contexts;
}
/**

View File

@ -0,0 +1,6 @@
name: 'Layout Builder Field Block Theme Suggestions Test'
type: module
description: 'Support module for testing.'
package: Testing
version: VERSION
core: 8.x

View File

@ -0,0 +1,19 @@
<?php
/**
* @file
* For testing Field Block theme suggestions.
*/
/**
* Implements hook_theme().
*/
function layout_builder_field_block_theme_suggestions_test_theme() {
// It is necessary to explicitly register the template via hook_theme()
// because it is added via a module, not a theme.
return [
'field__node__body__bundle_with_section_field__default' => [
'base hook' => 'field',
],
];
}

View File

@ -0,0 +1,5 @@
services:
layout_builder_fieldblock_test.fake_view_mode_context:
class: Drupal\layout_builder_fieldblock_test\ContextProvider\FakeViewModeContext
tags:
- { name: 'context_provider' }

View File

@ -0,0 +1,30 @@
<?php
namespace Drupal\layout_builder_fieldblock_test\ContextProvider;
use Drupal\Core\Plugin\Context\Context;
use Drupal\Core\Plugin\Context\ContextDefinition;
use Drupal\Core\Plugin\Context\ContextProviderInterface;
/**
* Provides a global context for view_mode for testing purposes.
*
* @group layout_builder
*/
class FakeViewModeContext implements ContextProviderInterface {
/**
* {@inheritdoc}
*/
public function getRuntimeContexts(array $unqualified_context_ids) {
return ['view_mode' => new Context(new ContextDefinition('string'), 'default')];
}
/**
* {@inheritdoc}
*/
public function getAvailableContexts() {
return $this->getRuntimeContexts([]);
}
}

View File

@ -0,0 +1,68 @@
<?php
namespace Drupal\Tests\layout_builder\Functional;
use Drupal\Tests\BrowserTestBase;
/**
* Tests field block template suggestions.
*
* @group layout_builder
*/
class LayoutBuilderFieldBlockThemeSuggestionsTest extends BrowserTestBase {
/**
* {@inheritdoc}
*/
public static $modules = [
'layout_builder',
'node',
'layout_builder_field_block_theme_suggestions_test',
];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->createContentType([
'type' => 'bundle_with_section_field',
'name' => 'Bundle with section field',
]);
$this->createNode([
'type' => 'bundle_with_section_field',
'title' => 'A node title',
'body' => [
[
'value' => 'This is content that the template should not render',
],
],
]);
$this->drupalLogin($this->drupalCreateUser([
'configure any layout',
'administer node display',
]));
$this->drupalGet('admin/structure/types/manage/bundle_with_section_field/display/default');
$this->drupalPostForm(NULL, ['layout[enabled]' => TRUE], 'Save');
}
/**
* Tests that of view mode specific field templates are suggested.
*/
public function testFieldBlockViewModeTemplates() {
$assert_session = $this->assertSession();
$this->drupalGet('node/1');
// Confirm that content is displayed by layout builder.
$assert_session->elementExists('css', '.block-layout-builder');
// Text that only appears in the view mode specific template.
$assert_session->pageTextContains('I am a field template for a specific view mode!');
// The content of the body field should not be visible because it is
// displayed via a template that does not render it.
$assert_session->pageTextNotContains('This is content that the template should not render');
}
}

View File

@ -2,7 +2,10 @@
namespace Drupal\Tests\layout_builder\Kernel;
use Drupal\Core\Plugin\Context\Context;
use Drupal\Core\Plugin\Context\ContextDefinition;
use Drupal\Core\Plugin\Context\EntityContext;
use Drupal\Core\Plugin\Context\EntityContextDefinition;
use Drupal\entity_test\Entity\EntityTest;
use Drupal\KernelTests\KernelTestBase;
use Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay;
@ -51,7 +54,10 @@ class DefaultsSectionStorageTest extends KernelTestBase {
$this->installEntitySchema('user');
$this->installConfig(['layout_builder_defaults_test']);
$this->plugin = DefaultsSectionStorage::create($this->container, [], 'defaults', new SectionStorageDefinition());
$definition = (new SectionStorageDefinition())
->addContextDefinition('display', EntityContextDefinition::fromEntityTypeId('entity_view_display'))
->addContextDefinition('view_mode', new ContextDefinition('string'));
$this->plugin = DefaultsSectionStorage::create($this->container, [], 'defaults', $definition);
}
/**
@ -141,8 +147,9 @@ class DefaultsSectionStorageTest extends KernelTestBase {
$context = EntityContext::fromEntity($display);
$this->plugin->setContext('display', $context);
$expected = ['display' => $context];
$this->assertSame($expected, $this->plugin->getContexts());
$result = $this->plugin->getContexts();
$this->assertSame(['view_mode', 'display'], array_keys($result));
$this->assertSame($context, $result['display']);
}
/**
@ -161,7 +168,7 @@ class DefaultsSectionStorageTest extends KernelTestBase {
$this->plugin->setContext('display', $context);
$result = $this->plugin->getContextsDuringPreview();
$this->assertEquals(['display', 'layout_builder.entity'], array_keys($result));
$this->assertSame(['view_mode', 'display', 'layout_builder.entity'], array_keys($result));
$this->assertSame($context, $result['display']);
@ -169,6 +176,10 @@ class DefaultsSectionStorageTest extends KernelTestBase {
$result_value = $result['layout_builder.entity']->getContextValue();
$this->assertInstanceOf(EntityTest::class, $result_value);
$this->assertSame('entity_test', $result_value->bundle());
$this->assertInstanceOf(Context::class, $result['view_mode']);
$result_value = $result['view_mode']->getContextValue();
$this->assertSame('default', $result_value);
}
/**
@ -203,4 +214,24 @@ class DefaultsSectionStorageTest extends KernelTestBase {
$this->assertSame('entity_test.entity_test.default', $result);
}
/**
* Tests loading given a display.
*/
public function testLoadFromDisplay() {
$display = LayoutBuilderEntityViewDisplay::create([
'targetEntityType' => 'entity_test',
'bundle' => 'entity_test',
'mode' => 'default',
'status' => TRUE,
]);
$display->save();
$contexts = [
'display' => EntityContext::fromEntity($display),
];
$section_storage_manager = $this->container->get('plugin.manager.layout_builder.section_storage');
$section_storage = $section_storage_manager->load('defaults', $contexts);
$this->assertInstanceOf(DefaultsSectionStorage::class, $section_storage);
}
}

View File

@ -10,6 +10,7 @@ use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\FormatterPluginManager;
use Drupal\Core\Plugin\Context\ContextDefinition;
use Drupal\Core\Form\EnforcedResponseException;
use Drupal\Core\Plugin\Context\EntityContextDefinition;
use Drupal\Core\Session\AccountInterface;
@ -210,6 +211,7 @@ class FieldBlockTest extends EntityKernelTestBase {
'bundles' => ['entity_test'],
'context_definitions' => [
'entity' => EntityContextDefinition::fromEntityTypeId('entity_test')->setLabel('Test'),
'view_mode' => new ContextDefinition('string'),
],
];
$formatter_manager = $this->prophesize(FormatterPluginManager::class);
@ -225,6 +227,7 @@ class FieldBlockTest extends EntityKernelTestBase {
$this->logger->reveal()
);
$block->setContextValue('entity', $entity_prophecy->reveal());
$block->setContextValue('view_mode', 'default');
return $block;
}

View File

@ -64,7 +64,7 @@ class LayoutEntityHelperTraitTest extends KernelTestBase {
],
],
],
['display'],
['display', 'view_mode'],
];
$data['fieldable entity'] = [
'entity_test',

View File

@ -2,13 +2,17 @@
namespace Drupal\Tests\layout_builder\Unit;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Entity\EntityType;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Entity\FieldableEntityInterface;
use Drupal\Core\Plugin\Context\ContextDefinition;
use Drupal\Core\Plugin\Context\ContextInterface;
use Drupal\Core\Plugin\Context\EntityContextDefinition;
use Drupal\Core\TypedData\TypedDataManagerInterface;
use Drupal\layout_builder\Entity\LayoutEntityDisplayInterface;
use Drupal\layout_builder\Entity\SampleEntityGeneratorInterface;
use Drupal\layout_builder\Plugin\SectionStorage\DefaultsSectionStorage;
@ -67,6 +71,17 @@ class DefaultsSectionStorageTest extends UnitTestCase {
* @covers ::setThirdPartySetting
*/
public function testThirdPartySettings() {
$this->entityTypeManager->getDefinition('entity_view_display')->willReturn(new EntityType(['id' => 'entity_view_display']));
$container = new ContainerBuilder();
$container->set('typed_data_manager', $this->prophesize(TypedDataManagerInterface::class)->reveal());
$container->set('entity_type.manager', $this->entityTypeManager->reveal());
\Drupal::setContainer($container);
$this->plugin->getPluginDefinition()
->addContextDefinition('display', EntityContextDefinition::fromEntityTypeId('entity_view_display'))
->addContextDefinition('view_mode', new ContextDefinition('string'));
// Set an initial value on the section list.
$section_list = $this->prophesize(LayoutEntityDisplayInterface::class);