Issue #2915036 by ndf, Dane Powell, tim.plunkett, Lendude, jofitz, koppie, larowlan, fubarhouse, sime, alex.skrypnyk, Joseph Zhao: Display mode configurations don't get updated with new fields
parent
608c6bc8fa
commit
49d60f113d
|
@ -11,6 +11,7 @@ use Drupal\Core\Entity\DynamicallyFieldableEntityStorageInterface;
|
||||||
use Drupal\field\ConfigImporterFieldPurger;
|
use Drupal\field\ConfigImporterFieldPurger;
|
||||||
use Drupal\field\Entity\FieldConfig;
|
use Drupal\field\Entity\FieldConfig;
|
||||||
use Drupal\field\Entity\FieldStorageConfig;
|
use Drupal\field\Entity\FieldStorageConfig;
|
||||||
|
use Drupal\field\EntityDisplayRebuilder;
|
||||||
use Drupal\field\FieldConfigInterface;
|
use Drupal\field\FieldConfigInterface;
|
||||||
use Drupal\field\FieldStorageConfigInterface;
|
use Drupal\field\FieldStorageConfigInterface;
|
||||||
use Drupal\Core\Form\FormStateInterface;
|
use Drupal\Core\Form\FormStateInterface;
|
||||||
|
@ -335,6 +336,22 @@ function field_form_config_admin_import_form_alter(&$form, FormStateInterface $f
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements hook_ENTITY_TYPE_insert() for 'field_config'.
|
||||||
|
*/
|
||||||
|
function field_field_config_insert(FieldConfigInterface $field) {
|
||||||
|
if ($field->isSyncing()) {
|
||||||
|
// Don't change anything during a configuration sync.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow other view modes to update their configuration for the new field.
|
||||||
|
// Otherwise, configuration for view modes won't get updated until the mode
|
||||||
|
// is used for the first time, creating noise in config diffs.
|
||||||
|
\Drupal::classResolver(EntityDisplayRebuilder::class)
|
||||||
|
->rebuildEntityTypeDisplays($field->getTargetEntityTypeId(), $field->getTargetBundle());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements hook_ENTITY_TYPE_update() for 'field_storage_config'.
|
* Implements hook_ENTITY_TYPE_update() for 'field_storage_config'.
|
||||||
*
|
*
|
||||||
|
|
|
@ -0,0 +1,98 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Drupal\field;
|
||||||
|
|
||||||
|
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
|
||||||
|
use Drupal\Core\Entity\EntityDisplayRepositoryInterface;
|
||||||
|
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
|
||||||
|
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||||
|
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rebuilds all form and view modes for a passed entity bundle.
|
||||||
|
*
|
||||||
|
* @see field_field_config_insert()
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
class EntityDisplayRebuilder implements ContainerInjectionInterface {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The field storage config storage.
|
||||||
|
*
|
||||||
|
* @var \Drupal\Core\Entity\EntityTypeManager
|
||||||
|
*/
|
||||||
|
protected $entityTypeManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The display repository.
|
||||||
|
*
|
||||||
|
* @var \Drupal\Core\Entity\EntityDisplayRepository
|
||||||
|
*/
|
||||||
|
protected $entityDisplayRepository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The entity type bundle info.
|
||||||
|
*
|
||||||
|
* @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
|
||||||
|
*/
|
||||||
|
protected $entityTypeBundleInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new EntityDisplayRebuilder.
|
||||||
|
*
|
||||||
|
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
|
||||||
|
* The entity manager.
|
||||||
|
* @param \Drupal\Core\Entity\EntityDisplayRepositoryInterface $entity_display_repository
|
||||||
|
* The entity display repository.
|
||||||
|
* @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_type_bundle_info
|
||||||
|
* The entity type bundle info.
|
||||||
|
*/
|
||||||
|
public function __construct(EntityTypeManagerInterface $entity_type_manager, EntityDisplayRepositoryInterface $entity_display_repository, EntityTypeBundleInfoInterface $entity_type_bundle_info) {
|
||||||
|
$this->entityTypeManager = $entity_type_manager;
|
||||||
|
$this->entityDisplayRepository = $entity_display_repository;
|
||||||
|
$this->entityTypeBundleInfo = $entity_type_bundle_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static function create(ContainerInterface $container) {
|
||||||
|
return new static(
|
||||||
|
$container->get('entity_type.manager'),
|
||||||
|
$container->get('entity_display.repository'),
|
||||||
|
$container->get('entity_type.bundle.info')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rebuild displays for single Entity Type.
|
||||||
|
*
|
||||||
|
* @param string $entity_type_id
|
||||||
|
* The entity type machine name.
|
||||||
|
*
|
||||||
|
* @param string $bundle
|
||||||
|
* The bundle we need to rebuild.
|
||||||
|
*/
|
||||||
|
public function rebuildEntityTypeDisplays($entity_type_id, $bundle) {
|
||||||
|
// Get the displays.
|
||||||
|
$view_modes = $this->entityDisplayRepository->getViewModeOptions($entity_type_id);
|
||||||
|
$form_modes = $this->entityDisplayRepository->getFormModeOptions($entity_type_id);
|
||||||
|
|
||||||
|
// Save view mode displays.
|
||||||
|
$view_mode_ids = array_map(function ($view_mode) use ($entity_type_id, $bundle) {
|
||||||
|
return "$entity_type_id.$bundle.$view_mode";
|
||||||
|
}, array_keys($view_modes));
|
||||||
|
foreach ($this->entityTypeManager->getStorage('entity_view_display')->loadMultiple($view_mode_ids) as $display) {
|
||||||
|
$display->save();
|
||||||
|
}
|
||||||
|
// Save form mode displays.
|
||||||
|
$form_mode_ids = array_map(function ($form_mode) use ($entity_type_id, $bundle) {
|
||||||
|
return "$entity_type_id.$bundle.$form_mode";
|
||||||
|
}, array_keys($form_modes));
|
||||||
|
foreach ($this->entityTypeManager->getStorage('entity_form_display')->loadMultiple($form_mode_ids) as $display) {
|
||||||
|
$display->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -86,9 +86,10 @@ class FieldImportDeleteUninstallUiTest extends FieldTestBase {
|
||||||
unset($core_extension['module']['telephone']);
|
unset($core_extension['module']['telephone']);
|
||||||
$sync->write('core.extension', $core_extension);
|
$sync->write('core.extension', $core_extension);
|
||||||
|
|
||||||
// Stage the field deletion
|
// Stage the field deletion including its dependencies.
|
||||||
$sync->delete('field.storage.entity_test.field_tel');
|
$sync->delete('field.storage.entity_test.field_tel');
|
||||||
$sync->delete('field.field.entity_test.entity_test.field_tel');
|
$sync->delete('field.field.entity_test.entity_test.field_tel');
|
||||||
|
$sync->delete('core.entity_form_display.entity_test.entity_test.default');
|
||||||
$this->drupalGet('admin/config/development/configuration');
|
$this->drupalGet('admin/config/development/configuration');
|
||||||
// Test that the message for one field being purged during a configuration
|
// Test that the message for one field being purged during a configuration
|
||||||
// synchronization is correct.
|
// synchronization is correct.
|
||||||
|
|
|
@ -713,6 +713,10 @@ class FormTest extends FieldTestBase {
|
||||||
])
|
])
|
||||||
->save();
|
->save();
|
||||||
|
|
||||||
|
// We need to rebuild hook information after setting the component through
|
||||||
|
// the API.
|
||||||
|
$this->rebuildAll();
|
||||||
|
|
||||||
$this->drupalGet('entity_test/add');
|
$this->drupalGet('entity_test/add');
|
||||||
$this->assertUniqueText("From $hook(): prefix on $field_name parent element.");
|
$this->assertUniqueText("From $hook(): prefix on $field_name parent element.");
|
||||||
if ($widget === 'test_field_widget_multiple_single_value') {
|
if ($widget === 'test_field_widget_multiple_single_value') {
|
||||||
|
|
|
@ -0,0 +1,138 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Drupal\Tests\field\Kernel;
|
||||||
|
|
||||||
|
use Drupal\Core\Entity\Entity\EntityFormDisplay;
|
||||||
|
use Drupal\Core\Entity\Entity\EntityFormMode;
|
||||||
|
use Drupal\Core\Entity\Entity\EntityViewDisplay;
|
||||||
|
use Drupal\Core\Entity\Entity\EntityViewMode;
|
||||||
|
use Drupal\field\Entity\FieldConfig;
|
||||||
|
use Drupal\field\Entity\FieldStorageConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensure display modes are updated when fields are created.
|
||||||
|
*
|
||||||
|
* @group field
|
||||||
|
*/
|
||||||
|
class DisplayModeUpdateTest extends FieldKernelTestBase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default view display name.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $defaultViewDisplayName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default form display name.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $defaultFormDisplayName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The alternate view display name.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $foobarViewDisplayName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The alternate form display name.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $foobarFormDisplayName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function setUp() {
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
// Create 'default' view-display.
|
||||||
|
$default_view_display = EntityViewDisplay::create([
|
||||||
|
'targetEntityType' => 'entity_test',
|
||||||
|
'bundle' => 'entity_test',
|
||||||
|
'mode' => 'default',
|
||||||
|
'status' => TRUE,
|
||||||
|
]);
|
||||||
|
$default_view_display->save();
|
||||||
|
$this->defaultViewDisplayName = $default_view_display->getConfigDependencyName();
|
||||||
|
|
||||||
|
// Create 'default' form-display.
|
||||||
|
$default_form_display = EntityFormDisplay::create([
|
||||||
|
'targetEntityType' => 'entity_test',
|
||||||
|
'bundle' => 'entity_test',
|
||||||
|
'mode' => 'default',
|
||||||
|
'status' => TRUE,
|
||||||
|
]);
|
||||||
|
$default_form_display->save();
|
||||||
|
$this->defaultFormDisplayName = $default_form_display->getConfigDependencyName();
|
||||||
|
|
||||||
|
// Create a view-mode 'foobar', create view-display that uses it.
|
||||||
|
EntityViewMode::create([
|
||||||
|
'id' => 'entity_test.foobar',
|
||||||
|
'targetEntityType' => 'entity_test',
|
||||||
|
'status' => TRUE,
|
||||||
|
'enabled' => TRUE,
|
||||||
|
])->save();
|
||||||
|
$foobar_view_display = EntityViewDisplay::create([
|
||||||
|
'targetEntityType' => 'entity_test',
|
||||||
|
'bundle' => 'entity_test',
|
||||||
|
'mode' => 'foobar',
|
||||||
|
'status' => TRUE,
|
||||||
|
]);
|
||||||
|
$foobar_view_display->save();
|
||||||
|
$this->foobarViewDisplayName = $foobar_view_display->getConfigDependencyName();
|
||||||
|
|
||||||
|
// Create a new form-mode 'foobar', create form-display that uses it.
|
||||||
|
EntityFormMode::create([
|
||||||
|
'id' => 'entity_test.foobar',
|
||||||
|
'targetEntityType' => 'entity_test',
|
||||||
|
'status' => TRUE,
|
||||||
|
'enabled' => TRUE,
|
||||||
|
])->save();
|
||||||
|
$foobar_form_display = EntityFormDisplay::create([
|
||||||
|
'targetEntityType' => 'entity_test',
|
||||||
|
'bundle' => 'entity_test',
|
||||||
|
'mode' => 'foobar',
|
||||||
|
'status' => TRUE,
|
||||||
|
]);
|
||||||
|
$foobar_form_display->save();
|
||||||
|
$this->foobarFormDisplayName = $foobar_form_display->getConfigDependencyName();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensure display modes are updated when fields are created.
|
||||||
|
*/
|
||||||
|
public function testDisplayModeUpdateAfterFieldCreation() {
|
||||||
|
|
||||||
|
// Sanity test: field has not been created yet, so should not exist in display.
|
||||||
|
$this->assertArrayNotHasKey('field_test', \Drupal::config($this->defaultViewDisplayName)->get('hidden'));
|
||||||
|
$this->assertArrayNotHasKey('field_test', \Drupal::config($this->defaultFormDisplayName)->get('hidden'));
|
||||||
|
$this->assertArrayNotHasKey('field_test', \Drupal::config($this->foobarViewDisplayName)->get('hidden'));
|
||||||
|
$this->assertArrayNotHasKey('field_test', \Drupal::config($this->foobarFormDisplayName)->get('hidden'));
|
||||||
|
|
||||||
|
$field_storage = FieldStorageConfig::create([
|
||||||
|
'field_name' => 'field_test',
|
||||||
|
'entity_type' => 'entity_test',
|
||||||
|
'type' => 'test_field',
|
||||||
|
'cardinality' => 1,
|
||||||
|
]);
|
||||||
|
$field_storage->save();
|
||||||
|
|
||||||
|
FieldConfig::create([
|
||||||
|
'field_storage' => $field_storage,
|
||||||
|
'bundle' => 'entity_test',
|
||||||
|
])->save();
|
||||||
|
|
||||||
|
// Ensure field is added to display modes.
|
||||||
|
$this->assertArrayHasKey('field_test', \Drupal::config($this->defaultViewDisplayName)->get('hidden'));
|
||||||
|
$this->assertArrayHasKey('field_test', \Drupal::config($this->defaultFormDisplayName)->get('hidden'));
|
||||||
|
$this->assertArrayHasKey('field_test', \Drupal::config($this->foobarViewDisplayName)->get('hidden'));
|
||||||
|
$this->assertArrayHasKey('field_test', \Drupal::config($this->foobarFormDisplayName)->get('hidden'));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -282,11 +282,9 @@ function entity_test_entity_form_mode_info_alter(&$form_modes) {
|
||||||
$entity_info = \Drupal::entityTypeManager()->getDefinitions();
|
$entity_info = \Drupal::entityTypeManager()->getDefinitions();
|
||||||
foreach ($entity_info as $entity_type => $info) {
|
foreach ($entity_info as $entity_type => $info) {
|
||||||
if ($entity_info[$entity_type]->getProvider() == 'entity_test') {
|
if ($entity_info[$entity_type]->getProvider() == 'entity_test') {
|
||||||
$form_modes[$entity_type] = [
|
$form_modes[$entity_type]['compact'] = [
|
||||||
'compact' => [
|
'label' => t('Compact version'),
|
||||||
'label' => t('Compact version'),
|
'status' => TRUE,
|
||||||
'status' => TRUE,
|
|
||||||
],
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue