Issue #2953656 by tedbow, tim.plunkett, diqidoq, phenaproxima, sarahjean, mglaman, xjm: No ability to control "extra fields" with Layout Builder
parent
2f08f6de5e
commit
045fcb5d44
|
@ -12,6 +12,10 @@ use Drupal\field\FieldConfigInterface;
|
|||
use Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay;
|
||||
use Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplayStorage;
|
||||
use Drupal\layout_builder\Form\LayoutBuilderEntityViewDisplayForm;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
|
||||
use Drupal\layout_builder\Entity\LayoutEntityDisplayInterface;
|
||||
use Drupal\layout_builder\Plugin\Block\ExtraFieldBlock;
|
||||
|
||||
/**
|
||||
* Implements hook_help().
|
||||
|
@ -81,3 +85,52 @@ function layout_builder_field_config_delete(FieldConfigInterface $field_config)
|
|||
$sample_entity_generator->delete($field_config->getTargetEntityTypeId(), $field_config->getTargetBundle());
|
||||
\Drupal::service('plugin.manager.block')->clearCachedDefinitions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_entity_view_alter().
|
||||
*
|
||||
* ExtraFieldBlock block plugins add placeholders for each extra field which is
|
||||
* configured to be displayed. Those placeholders are replaced by this hook.
|
||||
* Modules that implement hook_entity_extra_field_info() use their
|
||||
* implementations of hook_entity_view_alter() to add the rendered output of
|
||||
* the extra fields they provide, so we cannot get the rendered output of extra
|
||||
* fields before this point in the view process.
|
||||
* layout_builder_module_implements_alter() moves this implementation of
|
||||
* hook_entity_view_alter() to the end of the list.
|
||||
*
|
||||
* @see \Drupal\layout_builder\Plugin\Block\ExtraFieldBlock::build()
|
||||
* @see layout_builder_module_implements_alter()
|
||||
*/
|
||||
function layout_builder_entity_view_alter(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display) {
|
||||
if ($display instanceof LayoutEntityDisplayInterface) {
|
||||
/** @var \Drupal\Core\Entity\EntityFieldManagerInterface $field_manager */
|
||||
$field_manager = \Drupal::service('entity_field.manager');
|
||||
$extra_fields = $field_manager->getExtraFields($entity->getEntityTypeId(), $entity->bundle());
|
||||
if (!empty($extra_fields['display'])) {
|
||||
foreach ($extra_fields['display'] as $field_name => $extra_field) {
|
||||
// If the extra field is not set replace with an empty array to avoid
|
||||
// the placeholder text from being rendered.
|
||||
$replacement = isset($build[$field_name]) ? $build[$field_name] : [];
|
||||
ExtraFieldBlock::replaceFieldPlaceholder($build, $replacement, $field_name);
|
||||
// After the rendered field in $build has been copied over to the
|
||||
// ExtraFieldBlock block we must remove it from its original location or
|
||||
// else it will be rendered twice.
|
||||
unset($build[$field_name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_builder_module_implements_alter().
|
||||
*/
|
||||
function layout_builder_module_implements_alter(&$implementations, $hook) {
|
||||
if ($hook === 'entity_view_alter') {
|
||||
// Ensure that this module's implementation of hook_entity_view_alter() runs
|
||||
// last so that other modules that use this hook to render extra fields will
|
||||
// run before it.
|
||||
$group = $implementations['layout_builder'];
|
||||
unset($implementations['layout_builder']);
|
||||
$implementations['layout_builder'] = $group;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
* Post update functions for Layout Builder.
|
||||
*/
|
||||
|
||||
use Drupal\Core\Config\Entity\ConfigEntityUpdater;
|
||||
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
|
||||
|
||||
/**
|
||||
* Rebuild plugin dependencies for all entity view displays.
|
||||
*/
|
||||
|
@ -24,3 +27,30 @@ function layout_builder_post_update_rebuild_plugin_dependencies(&$sandbox = NULL
|
|||
|
||||
$sandbox['#finished'] = empty($sandbox['ids']) ? 1 : ($sandbox['count'] - count($sandbox['ids'])) / $sandbox['count'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure all extra fields are properly stored on entity view displays.
|
||||
*
|
||||
* Previously
|
||||
* \Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay::setComponent()
|
||||
* was not correctly setting the configuration for extra fields. This function
|
||||
* calls setComponent() for all extra field components to ensure the updated
|
||||
* logic is invoked on all extra fields to correct the settings.
|
||||
*/
|
||||
function layout_builder_post_update_add_extra_fields(&$sandbox = NULL) {
|
||||
$entity_field_manager = \Drupal::service('entity_field.manager');
|
||||
\Drupal::classResolver(ConfigEntityUpdater::class)->update($sandbox, 'entity_view_display', function (EntityViewDisplayInterface $display) use ($entity_field_manager) {
|
||||
$extra_fields = $entity_field_manager->getExtraFields($display->getTargetEntityTypeId(), $display->getTargetBundle());
|
||||
$components = $display->getComponents();
|
||||
// Sort the components to avoid them being reordered by setComponent().
|
||||
uasort($components, 'Drupal\Component\Utility\SortArray::sortByWeightElement');
|
||||
$result = FALSE;
|
||||
foreach ($components as $name => $component) {
|
||||
if (isset($extra_fields['display'][$name])) {
|
||||
$display->setComponent($name, $component);
|
||||
$result = TRUE;
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -25,6 +25,24 @@ class LayoutBuilderEntityViewDisplay extends BaseEntityViewDisplay implements La
|
|||
|
||||
use SectionStorageTrait;
|
||||
|
||||
/**
|
||||
* The entity field manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityFieldManagerInterface
|
||||
*/
|
||||
protected $entityFieldManager;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct(array $values, $entity_type) {
|
||||
// Set $entityFieldManager before calling the parent constructor because the
|
||||
// constructor will call init() which then calls setComponent() which needs
|
||||
// $entityFieldManager.
|
||||
$this->entityFieldManager = \Drupal::service('entity_field.manager');
|
||||
parent::__construct($values, $entity_type);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -258,13 +276,21 @@ class LayoutBuilderEntityViewDisplay extends BaseEntityViewDisplay implements La
|
|||
$options = $this->content[$name];
|
||||
// Provide backwards compatibility by converting to a section component.
|
||||
$field_definition = $this->getFieldDefinition($name);
|
||||
if ($field_definition && $field_definition->isDisplayConfigurable('view') && isset($options['type'])) {
|
||||
$configuration = [];
|
||||
$configuration['id'] = 'field_block:' . $this->getTargetEntityTypeId() . ':' . $this->getTargetBundle() . ':' . $name;
|
||||
$configuration['label_display'] = FALSE;
|
||||
$keys = array_flip(['type', 'label', 'settings', 'third_party_settings']);
|
||||
$configuration['formatter'] = array_intersect_key($options, $keys);
|
||||
$configuration['context_mapping']['entity'] = 'layout_builder.entity';
|
||||
$extra_fields = $this->entityFieldManager->getExtraFields($this->getTargetEntityTypeId(), $this->getTargetBundle());
|
||||
$is_view_configurable_non_extra_field = $field_definition && $field_definition->isDisplayConfigurable('view') && isset($options['type']);
|
||||
if ($is_view_configurable_non_extra_field || isset($extra_fields['display'][$name])) {
|
||||
$configuration = [
|
||||
'label_display' => '0',
|
||||
'context_mapping' => ['entity' => 'layout_builder.entity'],
|
||||
];
|
||||
if ($is_view_configurable_non_extra_field) {
|
||||
$configuration['id'] = 'field_block:' . $this->getTargetEntityTypeId() . ':' . $this->getTargetBundle() . ':' . $name;
|
||||
$keys = array_flip(['type', 'label', 'settings', 'third_party_settings']);
|
||||
$configuration['formatter'] = array_intersect_key($options, $keys);
|
||||
}
|
||||
else {
|
||||
$configuration['id'] = 'extra_field_block:' . $this->getTargetEntityTypeId() . ':' . $this->getTargetBundle() . ':' . $name;
|
||||
}
|
||||
|
||||
$section = $this->getDefaultSection();
|
||||
$region = isset($options['region']) ? $options['region'] : $section->getDefaultRegion();
|
||||
|
|
|
@ -0,0 +1,174 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\layout_builder\Plugin\Block;
|
||||
|
||||
use Drupal\Core\Block\BlockBase;
|
||||
use Drupal\Core\Cache\CacheableMetadata;
|
||||
use Drupal\Core\Entity\EntityFieldManagerInterface;
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\Core\Plugin\ContextAwarePluginInterface;
|
||||
use Drupal\Core\Render\Element;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\Core\StringTranslation\TranslatableMarkup;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides a block that renders an extra field from an entity.
|
||||
*
|
||||
* This block handles fields that are provided by implementations of
|
||||
* hook_entity_extra_field_info().
|
||||
*
|
||||
* @see \Drupal\layout_builder\Plugin\Block\FieldBlock
|
||||
* This block plugin handles all other field entities not provided by
|
||||
* hook_entity_extra_field_info().
|
||||
*
|
||||
* @Block(
|
||||
* id = "extra_field_block",
|
||||
* deriver = "\Drupal\layout_builder\Plugin\Derivative\ExtraFieldBlockDeriver",
|
||||
* )
|
||||
*
|
||||
* @internal
|
||||
* Plugin classes are internal.
|
||||
*/
|
||||
class ExtraFieldBlock extends BlockBase implements ContextAwarePluginInterface, ContainerFactoryPluginInterface {
|
||||
|
||||
/**
|
||||
* The entity field manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityFieldManagerInterface
|
||||
*/
|
||||
protected $entityFieldManager;
|
||||
|
||||
/**
|
||||
* The field name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $fieldName;
|
||||
|
||||
/**
|
||||
* The entity type manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
|
||||
*/
|
||||
protected $entityTypeManager;
|
||||
|
||||
/**
|
||||
* Constructs a new ExtraFieldBlock.
|
||||
*
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin ID for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
|
||||
* The entity type manager.
|
||||
* @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager
|
||||
* The entity field manager.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager) {
|
||||
$this->entityTypeManager = $entity_type_manager;
|
||||
$this->entityFieldManager = $entity_field_manager;
|
||||
// Get field name from the plugin ID.
|
||||
list (, , , $field_name) = explode(static::DERIVATIVE_SEPARATOR, $plugin_id, 4);
|
||||
assert(!empty($field_name));
|
||||
$this->fieldName = $field_name;
|
||||
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function defaultConfiguration() {
|
||||
return [
|
||||
'label_display' => FALSE,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$container->get('entity_type.manager'),
|
||||
$container->get('entity_field.manager')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the entity that has the field.
|
||||
*
|
||||
* @return \Drupal\Core\Entity\FieldableEntityInterface
|
||||
* The entity.
|
||||
*/
|
||||
protected function getEntity() {
|
||||
return $this->getContextValue('entity');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function build() {
|
||||
$entity = $this->getEntity();
|
||||
// Add a placeholder to replace after the entity view is built.
|
||||
// @see layout_builder_entity_view_alter().
|
||||
$extra_fields = $this->entityFieldManager->getExtraFields($entity->getEntityTypeId(), $entity->bundle());
|
||||
if (!isset($extra_fields['display'][$this->fieldName])) {
|
||||
$build = [];
|
||||
}
|
||||
else {
|
||||
$build = [
|
||||
'#extra_field_placeholder_field_name' => $this->fieldName,
|
||||
// Always provide a placeholder. The Layout Builder will NOT invoke
|
||||
// hook_entity_view_alter() so extra fields will not be added to the
|
||||
// render array. If the hook is invoked the placeholder will be
|
||||
// replaced.
|
||||
// @see ::replaceFieldPlaceholder()
|
||||
'#markup' => new TranslatableMarkup('Placeholder for the "@field" field', ['@field' => $extra_fields['display'][$this->fieldName]['label']]),
|
||||
];
|
||||
}
|
||||
CacheableMetadata::createFromObject($this)->applyTo($build);
|
||||
return $build;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces all placeholders for a given field.
|
||||
*
|
||||
* @param array $build
|
||||
* The built render array for the elements.
|
||||
* @param array $built_field
|
||||
* The render array to replace the placeholder.
|
||||
* @param string $field_name
|
||||
* The field name.
|
||||
*
|
||||
* @see ::build()
|
||||
*/
|
||||
public static function replaceFieldPlaceholder(array &$build, array $built_field, $field_name) {
|
||||
foreach (Element::children($build) as $child) {
|
||||
if (isset($build[$child]['#extra_field_placeholder_field_name']) && $build[$child]['#extra_field_placeholder_field_name'] === $field_name) {
|
||||
$placeholder_cache = CacheableMetadata::createFromRenderArray($build[$child]);
|
||||
$built_cache = CacheableMetadata::createFromRenderArray($built_field);
|
||||
$merged_cache = $placeholder_cache->merge($built_cache);
|
||||
$build[$child] = $built_field;
|
||||
$merged_cache->applyTo($build);
|
||||
}
|
||||
else {
|
||||
static::replaceFieldPlaceholder($build[$child], $built_field, $field_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function blockAccess(AccountInterface $account) {
|
||||
return $this->getEntity()->access('view', $account, TRUE);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\layout_builder\Plugin\Derivative;
|
||||
|
||||
use Drupal\Component\Plugin\Derivative\DeriverBase;
|
||||
use Drupal\Component\Plugin\PluginBase;
|
||||
use Drupal\Core\Entity\EntityFieldManagerInterface;
|
||||
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
use Drupal\Core\Entity\FieldableEntityInterface;
|
||||
use Drupal\Core\Plugin\Context\EntityContextDefinition;
|
||||
use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
|
||||
use Drupal\Core\StringTranslation\StringTranslationTrait;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides entity field block definitions for every field.
|
||||
*
|
||||
* @internal
|
||||
* Layout Builder is currently experimental and should only be leveraged by
|
||||
* experimental modules and development releases of contributed modules.
|
||||
* See https://www.drupal.org/core/experimental for more information.
|
||||
*/
|
||||
class ExtraFieldBlockDeriver extends DeriverBase implements ContainerDeriverInterface {
|
||||
|
||||
use StringTranslationTrait;
|
||||
|
||||
/**
|
||||
* The entity field manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityFieldManagerInterface
|
||||
*/
|
||||
protected $entityFieldManager;
|
||||
|
||||
/**
|
||||
* The entity type manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
|
||||
*/
|
||||
protected $entityTypeManager;
|
||||
|
||||
/**
|
||||
* The entity type bundle info.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
|
||||
*/
|
||||
protected $entityTypeBundleInfo;
|
||||
|
||||
/**
|
||||
* Constructs new FieldBlockDeriver.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager
|
||||
* The entity field manager.
|
||||
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
|
||||
* The entity type manager.
|
||||
* @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_type_bundle_info
|
||||
* The entity type bundle info.
|
||||
*/
|
||||
public function __construct(EntityFieldManagerInterface $entity_field_manager, EntityTypeManagerInterface $entity_type_manager, EntityTypeBundleInfoInterface $entity_type_bundle_info) {
|
||||
$this->entityFieldManager = $entity_field_manager;
|
||||
$this->entityTypeManager = $entity_type_manager;
|
||||
$this->entityTypeBundleInfo = $entity_type_bundle_info;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, $base_plugin_id) {
|
||||
return new static(
|
||||
$container->get('entity_field.manager'),
|
||||
$container->get('entity_type.manager'),
|
||||
$container->get('entity_type.bundle.info')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDerivativeDefinitions($base_plugin_definition) {
|
||||
foreach ($this->entityTypeManager->getDefinitions() as $entity_type_id => $entity_type) {
|
||||
// Only process fieldable entity types.
|
||||
if (!$entity_type->entityClassImplements(FieldableEntityInterface::class)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$bundles = $this->entityTypeBundleInfo->getBundleInfo($entity_type_id);
|
||||
foreach ($bundles as $bundle_id => $bundle) {
|
||||
$extra_fields = $this->entityFieldManager->getExtraFields($entity_type_id, $bundle_id);
|
||||
// Skip bundles without any extra fields.
|
||||
if (empty($extra_fields['display'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($extra_fields['display'] as $extra_field_id => $extra_field) {
|
||||
$derivative = $base_plugin_definition;
|
||||
|
||||
$derivative['category'] = $entity_type->getLabel();
|
||||
|
||||
$derivative['admin_label'] = $extra_field['label'];
|
||||
|
||||
$context_definition = EntityContextDefinition::fromEntityType($entity_type)
|
||||
->addConstraint('Bundle', [$bundle_id]);
|
||||
$derivative['context'] = [
|
||||
'entity' => $context_definition,
|
||||
];
|
||||
|
||||
$derivative_id = $entity_type_id . PluginBase::DERIVATIVE_SEPARATOR . $bundle_id . PluginBase::DERIVATIVE_SEPARATOR . $extra_field_id;
|
||||
$this->derivatives[$derivative_id] = $derivative;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $this->derivatives;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Test fixture.
|
||||
*/
|
||||
|
||||
use Drupal\Core\Database\Database;
|
||||
|
||||
$connection = Database::getConnection();
|
||||
|
||||
// Update core.extension.
|
||||
$extensions = $connection->select('config')
|
||||
->fields('config', ['data'])
|
||||
->condition('collection', '')
|
||||
->condition('name', 'core.extension')
|
||||
->execute()
|
||||
->fetchField();
|
||||
$extensions = unserialize($extensions);
|
||||
$extensions['module']['layout_builder'] = 0;
|
||||
$extensions['module']['layout_discovery'] = 0;
|
||||
$extensions['module']['layout_test'] = 0;
|
||||
$connection->update('config')
|
||||
->fields([
|
||||
'data' => serialize($extensions),
|
||||
'collection' => '',
|
||||
'name' => 'core.extension',
|
||||
])
|
||||
->condition('collection', '')
|
||||
->condition('name', 'core.extension')
|
||||
->execute();
|
|
@ -9,27 +9,6 @@ use Drupal\Core\Database\Database;
|
|||
|
||||
$connection = Database::getConnection();
|
||||
|
||||
// Update core.extension.
|
||||
$extensions = $connection->select('config')
|
||||
->fields('config', ['data'])
|
||||
->condition('collection', '')
|
||||
->condition('name', 'core.extension')
|
||||
->execute()
|
||||
->fetchField();
|
||||
$extensions = unserialize($extensions);
|
||||
$extensions['module']['layout_builder'] = 0;
|
||||
$extensions['module']['layout_discovery'] = 0;
|
||||
$extensions['module']['layout_test'] = 0;
|
||||
$connection->update('config')
|
||||
->fields([
|
||||
'data' => serialize($extensions),
|
||||
'collection' => '',
|
||||
'name' => 'core.extension',
|
||||
])
|
||||
->condition('collection', '')
|
||||
->condition('name', 'core.extension')
|
||||
->execute();
|
||||
|
||||
// Add a layout plugin with a dependency to an existing entity view display.
|
||||
$display = $connection->select('config')
|
||||
->fields('config', ['data'])
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
* Provides hook implementations for Layout Builder tests.
|
||||
*/
|
||||
|
||||
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
|
||||
/**
|
||||
* Implements hook_plugin_filter_TYPE__CONSUMER_alter().
|
||||
*/
|
||||
|
@ -32,3 +35,26 @@ function layout_builder_test_plugin_filter_block__layout_builder_alter(array &$d
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_entity_extra_field_info().
|
||||
*/
|
||||
function layout_builder_test_entity_extra_field_info() {
|
||||
$extra['node']['bundle_with_section_field']['display']['layout_builder_test'] = [
|
||||
'label' => t('Extra label'),
|
||||
'description' => t('Extra description'),
|
||||
'weight' => 0,
|
||||
];
|
||||
return $extra;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_entity_node_view().
|
||||
*/
|
||||
function layout_builder_test_node_view(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display, $view_mode) {
|
||||
if ($display->getComponent('layout_builder_test')) {
|
||||
$build['layout_builder_test'] = [
|
||||
'#markup' => 'Extra, Extra read all about it.',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,8 +83,25 @@ class LayoutBuilderTest extends BrowserTestBase {
|
|||
$assert_session->linkExists('Manage layout');
|
||||
$this->clickLink('Manage layout');
|
||||
$assert_session->addressEquals("$field_ui_prefix/display-layout/default");
|
||||
// The body field is present.
|
||||
$assert_session->elementExists('css', '.field--name-body');
|
||||
// The body field is only present once.
|
||||
$assert_session->elementsCount('css', '.field--name-body', 1);
|
||||
// The extra field is only present once.
|
||||
$this->assertTextAppearsOnce('Placeholder for the "Extra label" field');
|
||||
// Save the defaults.
|
||||
$assert_session->linkExists('Save Layout');
|
||||
$this->clickLink('Save Layout');
|
||||
$assert_session->addressEquals("$field_ui_prefix/display/default");
|
||||
|
||||
// Load the default layouts again after saving to confirm fields are only
|
||||
// added on new layouts.
|
||||
$this->drupalGet("$field_ui_prefix/display/default");
|
||||
$assert_session->linkExists('Manage layout');
|
||||
$this->clickLink('Manage layout');
|
||||
$assert_session->addressEquals("$field_ui_prefix/display-layout/default");
|
||||
// The body field is only present once.
|
||||
$assert_session->elementsCount('css', '.field--name-body', 1);
|
||||
// The extra field is only present once.
|
||||
$this->assertTextAppearsOnce('Placeholder for the "Extra label" field');
|
||||
|
||||
// Add a new block.
|
||||
$assert_session->linkExists('Add Block');
|
||||
|
@ -107,6 +124,8 @@ class LayoutBuilderTest extends BrowserTestBase {
|
|||
$this->drupalGet('node/1');
|
||||
$assert_session->pageTextContains('The first node body');
|
||||
$assert_session->pageTextContains('Powered by Drupal');
|
||||
$assert_session->pageTextContains('Extra, Extra read all about it.');
|
||||
$assert_session->pageTextNotContains('Placeholder for the "Extra label" field');
|
||||
$assert_session->linkNotExists('Layout');
|
||||
|
||||
// Enable overrides.
|
||||
|
@ -116,6 +135,7 @@ class LayoutBuilderTest extends BrowserTestBase {
|
|||
// Remove the section from the defaults.
|
||||
$assert_session->linkExists('Layout');
|
||||
$this->clickLink('Layout');
|
||||
$assert_session->pageTextContains('Placeholder for the "Extra label" field');
|
||||
$assert_session->linkExists('Remove section');
|
||||
$this->clickLink('Remove section');
|
||||
$page->pressButton('Remove');
|
||||
|
@ -128,6 +148,8 @@ class LayoutBuilderTest extends BrowserTestBase {
|
|||
$this->clickLink('Save Layout');
|
||||
$assert_session->pageTextNotContains('The first node body');
|
||||
$assert_session->pageTextNotContains('Powered by Drupal');
|
||||
$assert_session->pageTextNotContains('Extra, Extra read all about it.');
|
||||
$assert_session->pageTextNotContains('Placeholder for the "Extra label" field');
|
||||
|
||||
// Assert that overrides cannot be turned off while overrides exist.
|
||||
$this->drupalGet("$field_ui_prefix/display/default");
|
||||
|
@ -149,12 +171,16 @@ class LayoutBuilderTest extends BrowserTestBase {
|
|||
$assert_session->pageTextContains('The second node title');
|
||||
$assert_session->pageTextContains('The second node body');
|
||||
$assert_session->pageTextContains('Powered by Drupal');
|
||||
$assert_session->pageTextContains('Extra, Extra read all about it.');
|
||||
$assert_session->pageTextNotContains('Placeholder for the "Extra label" field');
|
||||
|
||||
// The overridden node does not pick up the changes to defaults.
|
||||
$this->drupalGet('node/1');
|
||||
$assert_session->elementNotExists('css', '.field--name-title');
|
||||
$assert_session->pageTextNotContains('The first node body');
|
||||
$assert_session->pageTextNotContains('Powered by Drupal');
|
||||
$assert_session->pageTextNotContains('Extra, Extra read all about it.');
|
||||
$assert_session->pageTextNotContains('Placeholder for the "Extra label" field');
|
||||
$assert_session->linkExists('Layout');
|
||||
|
||||
// Reverting the override returns it to the defaults.
|
||||
|
@ -166,6 +192,7 @@ class LayoutBuilderTest extends BrowserTestBase {
|
|||
$assert_session->elementExists('css', '.field--name-title');
|
||||
$assert_session->pageTextContains('The first node body');
|
||||
$assert_session->pageTextContains('Powered by Drupal');
|
||||
$assert_session->pageTextContains('Placeholder for the "Extra label" field');
|
||||
|
||||
// Assert that overrides can be turned off now that all overrides are gone.
|
||||
$this->drupalPostForm("$field_ui_prefix/display/default", ['layout[allow_custom]' => FALSE], 'Save');
|
||||
|
@ -407,4 +434,14 @@ class LayoutBuilderTest extends BrowserTestBase {
|
|||
$assert_session->pageTextNotContains('Test Block View');
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that a text string only appears once on the page.
|
||||
*
|
||||
* @param string $needle
|
||||
* The string to look for.
|
||||
*/
|
||||
protected function assertTextAppearsOnce($needle) {
|
||||
$this->assertEquals(1, substr_count($this->getSession()->getPage()->getContent(), $needle), "'$needle' only appears once on the page.");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\layout_builder\Functional\Update;
|
||||
|
||||
use Drupal\Core\Entity\Entity\EntityViewDisplay;
|
||||
use Drupal\FunctionalTests\Update\UpdatePathTestBase;
|
||||
|
||||
/**
|
||||
* Tests the upgrade path for Layout Builder extra fields.
|
||||
*
|
||||
* @group layout_builder
|
||||
* @group legacy
|
||||
*/
|
||||
class ExtraFieldUpdatePathTest extends UpdatePathTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setDatabaseDumpFiles() {
|
||||
$this->databaseDumpFiles = [
|
||||
__DIR__ . '/../../../../../system/tests/fixtures/update/drupal-8.4.0.bare.standard.php.gz',
|
||||
__DIR__ . '/../../../fixtures/update/layout-builder.php',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the upgrade path for Layout Builder extra fields.
|
||||
*/
|
||||
public function testRunUpdates() {
|
||||
$data = EntityViewDisplay::load('node.article.teaser')->toArray();
|
||||
$this->assertArrayNotHasKey('third_party_settings', $data);
|
||||
|
||||
$this->runUpdates();
|
||||
|
||||
$data = EntityViewDisplay::load('node.article.teaser')->toArray();
|
||||
$components = $data['third_party_settings']['layout_builder']['sections'][0]->getComponents();
|
||||
$component = reset($components);
|
||||
$this->assertSame('extra_field_block:node:article:links', $component->getPluginId());
|
||||
}
|
||||
|
||||
}
|
|
@ -19,6 +19,7 @@ class SectionDependenciesUpdatePathTest extends UpdatePathTestBase {
|
|||
protected function setDatabaseDumpFiles() {
|
||||
$this->databaseDumpFiles = [
|
||||
__DIR__ . '/../../../../../system/tests/fixtures/update/drupal-8.4.0.bare.standard.php.gz',
|
||||
__DIR__ . '/../../../fixtures/update/layout-builder.php',
|
||||
__DIR__ . '/../../../fixtures/update/section-dependencies.php',
|
||||
];
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue