diff --git a/core/config/schema/core.entity.schema.yml b/core/config/schema/core.entity.schema.yml index df2a2fd..b89bc26 100644 --- a/core/config/schema/core.entity.schema.yml +++ b/core/config/schema/core.entity.schema.yml @@ -362,3 +362,19 @@ field.formatter.settings.entity_reference_label: type: boolean label: 'Link label to the referenced entity' +field.formatter.settings.entity_reference_field: + type: mapping + label: 'Rendered field from referenced entity settings' + mapping: + field_name: + label: 'Machine name of the field' + type: string + type: + label: 'Machine name of the formatter' + type: string + settings: + label: 'Formatter settings' + type: field.formatter.settings.[type] + label: + label: 'Target field label visibility setting' + type: string diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/EntityReferenceFieldFormatter.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/EntityReferenceFieldFormatter.php new file mode 100644 index 0000000..0937d01 --- /dev/null +++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/EntityReferenceFieldFormatter.php @@ -0,0 +1,448 @@ + label). + * + * @var array + */ + protected $availableFieldOptions; + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + return new static( + $plugin_id, + $plugin_definition, + $configuration['field_definition'], + $configuration['settings'], + $configuration['label'], + $configuration['view_mode'], + $configuration['third_party_settings'], + $container->get('entity_field.manager'), + $container->get('plugin.manager.field.formatter'), + $container->get('entity_type.manager'), + $container->get('entity_type.bundle.info') + ); + } + + /** + * Constructs a EntityReferenceReferencedEntityFieldFormatter object. + * + * @param string $plugin_id + * The plugin_id for the formatter. + * @param mixed $plugin_definition + * The plugin implementation definition. + * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition + * The definition of the field to which the formatter is associated. + * @param array $settings + * The formatter settings. + * @param string $label + * The formatter label display setting. + * @param string $view_mode + * The view mode. + * @param array $third_party_settings + * Any third party settings. + * @param \Drupal\Core\Entity\EntityFieldManager $entity_field_manager + * The entity field manager. + * @param \Drupal\Core\Field\FormatterPluginManager $formatter_plugin_manager + * The formatter plugin 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($plugin_id, $plugin_definition, FieldDefinitionInterface $field_definition, array $settings, $label, $view_mode, array $third_party_settings, EntityFieldManager $entity_field_manager, FormatterPluginManager $formatter_plugin_manager, EntityTypeManagerInterface $entity_type_manager, EntityTypeBundleInfoInterface $entity_type_bundle_info) { + parent::__construct($plugin_id, $plugin_definition, $field_definition, $settings, $label, $view_mode, $third_party_settings); + $this->entityFieldManager = $entity_field_manager; + $this->formatterPluginManager = $formatter_plugin_manager; + $this->entityTypeManager = $entity_type_manager; + $this->entityTypeBundleInfo = $entity_type_bundle_info; + } + + /** + * {@inheritdoc} + */ + public static function defaultSettings() { + return [ + 'field_name' => '', + 'type' => '', + 'settings' => [], + 'label' => 'hidden', + ]; + } + + /** + * {@inheritdoc} + */ + public function viewElements(FieldItemListInterface $items, $langcode) { + /** @var \Drupal\Core\Entity\FieldableEntityInterface $entity */ + $entities = $this->getEntitiesToView($items, $langcode); + + $field_name = $this->getFieldName()['machine_name']; + $formatter_type = $this->getFormatterType($field_name)['machine_name']; + $formatter_settings = [ + 'type' => $formatter_type, + 'settings' => $this->getSetting('settings'), + 'label' => $this->getSetting('label'), + ]; + + $build = []; + foreach ($entities as $delta => $entity) { + if ($entity->hasField($field_name)) { + $build[$delta] = $this->entityTypeManager->getViewBuilder($entity->getEntityTypeId())->viewField($entity->get($field_name), array_filter($formatter_settings)); + } + } + return $build; + } + + /** + * Gets a list of supported fields. + * + * @return array + * An associative array of supported fields, where keys are machine names + * and values are human-readable field labels. + */ + protected function getAvailableFieldOptions() { + if ($this->availableFieldOptions) { + return $this->availableFieldOptions; + } + + $entity_type_id = $this->fieldDefinition->getSetting('target_type'); + $entity_type = $this->entityTypeManager->getDefinition($entity_type_id); + // We always show the entity label as an option to be selected. + if ($entity_type->hasKey('label')) { + $label_key = $entity_type->getKey('label'); + $field_names = [ + // Example: 'title' => 'Title'. + $label_key => $this->entityFieldManager->getBaseFieldDefinitions($entity_type_id)[$label_key]->getLabel(), + ]; + } + else { + $field_names = []; + } + + $target_bundles = empty($this->fieldDefinition->getSetting('handler_settings')['target_bundles']) ? array_keys($this->entityTypeBundleInfo->getBundleInfo($entity_type_id)) : $this->fieldDefinition->getSetting('handler_settings')['target_bundles']; + foreach ($target_bundles as $bundle) { + $bundle_field_names = []; + /** @var \Drupal\Core\Field\FieldDefinitionInterface $field_definition */ + foreach ($this->entityFieldManager->getFieldDefinitions($entity_type_id, $bundle) as $field_machine_name => $field_definition) { + if ($field_definition->isDisplayConfigurable('view')) { + $bundle_field_names[$field_machine_name] = $field_definition->getLabel(); + } + } + $field_names = array_merge($field_names, $bundle_field_names); + } + + $this->availableFieldOptions = $field_names; + return $field_names; + } + + /** + * Get all available formatters for a field storage definition. + * + * @param \Drupal\Core\Field\FieldStorageDefinitionInterface $field_storage_definition + * The field storage definition. + * + * @return string[] + * The field formatter labels keys by plugin ID. + */ + protected function getAvailableFormatterOptions(FieldStorageDefinitionInterface $field_storage_definition) { + $field_definition = BaseFieldDefinition::createFromFieldStorageDefinition($field_storage_definition); + $formatters = $this->formatterPluginManager->getOptions($field_storage_definition->getType()); + $options = []; + foreach ($formatters as $formatter_id => $formatter_options) { + $formatter_definition = $this->formatterPluginManager->getDefinition($formatter_id); + /** @var \Drupal\Core\Field\FormatterInterface $formatter_class */ + $formatter_class = $formatter_definition['class']; + if ($formatter_class::isApplicable($field_definition)) { + $options[$formatter_id] = $formatter_definition['label']; + } + } + return $options; + } + + /** + * Ajax callback for field name change. + */ + public static function onFieldNameChange(array $form, FormStateInterface $form_state) { + return $form['fields'][$form_state->get('plugin_settings_edit')]['plugin']['settings_edit_form']['settings']; + } + + /** + * Ajax callback for formatter type change. + */ + public static function onFormatterTypeChange(array $form, FormStateInterface $form_state) { + return $form['fields'][$form_state->get('plugin_settings_edit')]['plugin']['settings_edit_form']['settings']['settings']; + } + + /** + * Rebuilds the form on select submit. + */ + public static function rebuildSubmit(array &$form, FormStateInterface $form_state) { + $form_state->setRebuild(TRUE); + } + + /** + * {@inheritdoc} + */ + public function settingsForm(array $form, FormStateInterface $form_state) { + $form = parent::settingsForm($form, $form_state); + $target_entity_type_id = $this->fieldDefinition->getSetting('target_type'); + $field_name_options = $this->getAvailableFieldOptions(); + $field_storage_definitions = $this->entityFieldManager->getFieldStorageDefinitions($target_entity_type_id); + // Field on the target entity this formatter is currently displaying. + $selected_field_name = $this->getSetting('field_name', $form_state); + if (!$selected_field_name) { + // The first field is used as default in case of no value set. + $selected_field_name = array_keys($field_name_options)[0]; + } + $field_storage = $field_storage_definitions[$selected_field_name]; + + $form['#prefix'] = '
'; + $form['#suffix'] = '
'; + + $form['field_name'] = [ + '#type' => 'select', + '#title' => $this->t('Field name'), + '#default_value' => $selected_field_name, + '#options' => $field_name_options, + '#ajax' => [ + 'callback' => [static::class, 'onFieldNameChange'], + 'wrapper' => 'field-formatter-ajax', + 'method' => 'replace', + ], + '#submit' => [[static::class, 'rebuildSubmit']], + '#executes_submit_callback' => TRUE, + ]; + + $form['label'] = [ + '#type' => 'select', + '#title' => $this->t('Label'), + '#options' => EntityViewDisplayEditForm::getFieldLabelOptions(), + '#default_value' => $this->getSetting('label', $form_state), + ]; + + if ($selected_field_name) { + $formatter_options = $this->getAvailableFormatterOptions($field_storage); + $formatter_type = $this->getSetting('type', $form_state); + $settings = $this->getSetting('settings', $form_state); + if (!isset($formatter_options[$formatter_type])) { + $formatter_type = array_keys($formatter_options)[0]; + $settings = []; + } + + $form['type'] = [ + '#type' => 'select', + '#title' => $this->t('Formatter'), + '#options' => $formatter_options, + '#default_value' => $formatter_type, + '#ajax' => [ + 'callback' => [static::class, 'onFormatterTypeChange'], + 'wrapper' => 'field-formatter-settings-ajax', + 'method' => 'replace', + ], + '#submit' => [[static::class, 'rebuildSubmit']], + '#executes_submit_callback' => TRUE, + ]; + + $options = [ + 'field_definition' => BaseFieldDefinition::createFromFieldStorageDefinition($field_storage), + 'configuration' => [ + 'type' => $formatter_type, + 'settings' => $settings, + 'label' => '', + 'weight' => 0, + ], + 'view_mode' => EntityDisplayBase::CUSTOM_MODE, + ]; + + // Get the formatter settings form. + $settings_form = ['#value' => []]; + if ($formatter = $this->formatterPluginManager->getInstance($options)) { + $settings_form = $formatter->settingsForm([], $form_state); + } + $form['settings'] = $settings_form; + $form['settings']['#prefix'] = '
'; + $form['settings']['#suffix'] = '
'; + } + + return $form; + } + + /** + * {@inheritdoc} + */ + public function settingsSummary() { + $summary = parent::settingsSummary(); + $field_storage_definitions = NULL; + + $field_name = $this->getFieldName(); + if ($this->getSetting('field_name')) { + $summary[] = $this->t('Field "%field_name" displayed.', ['%field_name' => $field_name['label']]); + } + else { + $summary[] = $this->t('The field "%field_name" will be used by default.', ['%field_name' => $field_name['label']]); + } + + $formatter_type = $this->getFormatterType($field_name['machine_name']); + if ($this->getSetting('type')) { + $summary[] = $this->t('Formatter "%type" used.', ['%type' => $formatter_type['label']]); + } + else { + $summary[] = $this->t('The "%type" formatter will be used by default.', ['%type' => $formatter_type['label']]); + } + + return $summary; + } + + /** + * Wrapper around ::getSetting() to carry over values from the form state. + * + * @param string $key + * The setting name. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The form state. + * + * @return mixed|null + * The value of the setting, or NULL if absent. + */ + public function getSetting($key, FormStateInterface $form_state = NULL) { + if (!$form_state) { + return parent::getSetting($key); + } + + $field_name = $this->fieldDefinition->getName(); + if ($form_state->hasValue([ + 'fields', + $field_name, + 'settings_edit_form', + 'settings', + $key, + ])) { + return $form_state->getValue([ + 'fields', + $field_name, + 'settings_edit_form', + 'settings', + $key, + ]); + } + + return parent::getSetting($key); + } + + /** + * Gets the field to be used in this formatter. + * + * @return array + * An associative array containing: + * - machine_name: The field machine name. + * - label: The field's human-readable label. + * If no field was configured yet, will try to return the first field + * available on the target entity. + * + * @see \Drupal\Core\Field\Plugin\Field\FieldFormatter\EntityReferenceReferencedEntityFieldFormatter::getAvailableFieldOptions() + */ + protected function getFieldName() { + $field_name_options = $this->getAvailableFieldOptions(); + if (!$field_name = $this->getSetting('field_name')) { + $field_name = array_keys($field_name_options)[0]; + } + $field['machine_name'] = $field_name; + $field['label'] = $field_name_options[$field_name]; + return $field; + } + + /** + * Gets the target formatter to be used in this formatter. + * + * @param string $field_name + * The machine name of the target field. + * + * @return array + * An associative array containing: + * - machine_name: The formatter machine name. + * - label: The formatter's human-readable label + * If nothing was configured yet, will try to return the first formatter + * available on the target entity. + * + * @see \Drupal\Core\Field\Plugin\Field\FieldFormatter\EntityReferenceReferencedEntityFieldFormatter::getAvailableFormatterOptions() + */ + protected function getFormatterType($field_name) { + $formatter = [ + 'machine_name' => NULL, + 'label' => NULL, + ]; + if (!$formatter_type = $this->getSetting('type')) { + $target_entity_type_id = $this->fieldDefinition->getSetting('target_type'); + $field_storage_definitions = $this->entityFieldManager->getFieldStorageDefinitions($target_entity_type_id); + if (empty($field_storage_definitions[$field_name])) { + return $formatter; + } + $formatter_options = $this->getAvailableFormatterOptions($field_storage_definitions[$field_name]); + $formatter_type = array_keys($formatter_options)[0]; + } + $formatter['machine_name'] = $formatter_type; + $formatter['label'] = $this->formatterPluginManager->getDefinition($formatter_type)['label']; + return $formatter; + } + +} diff --git a/core/modules/field/src/Tests/EntityReference/EntityReferenceAdminTest.php b/core/modules/field/src/Tests/EntityReference/EntityReferenceAdminTest.php index fa68cb6..d3d3bc0 100644 --- a/core/modules/field/src/Tests/EntityReference/EntityReferenceAdminTest.php +++ b/core/modules/field/src/Tests/EntityReference/EntityReferenceAdminTest.php @@ -373,6 +373,7 @@ public function testAvailableFormatters() { $this->assertFieldSelectOptions('fields[field_' . $taxonomy_term_field_name . '][type]', [ 'entity_reference_label', 'entity_reference_entity_id', + 'entity_reference_field', 'entity_reference_rss_category', 'entity_reference_entity_view', ]); @@ -384,6 +385,7 @@ public function testAvailableFormatters() { 'author', 'entity_reference_entity_id', 'entity_reference_entity_view', + 'entity_reference_field', 'entity_reference_label', ]); @@ -393,6 +395,7 @@ public function testAvailableFormatters() { 'entity_reference_label', 'entity_reference_entity_id', 'entity_reference_entity_view', + 'entity_reference_field', ]); // Test if Date Format Reference Field has the correct formatters. @@ -401,6 +404,7 @@ public function testAvailableFormatters() { $this->assertFieldSelectOptions('fields[field_' . $date_format_field_name . '][type]', [ 'entity_reference_label', 'entity_reference_entity_id', + 'entity_reference_field', ]); } diff --git a/core/modules/field/src/Tests/EntityReference/EntityReferenceTestTrait.php b/core/modules/field/src/Tests/EntityReference/EntityReferenceTestTrait.php index 568cd4d..80d38bc 100644 --- a/core/modules/field/src/Tests/EntityReference/EntityReferenceTestTrait.php +++ b/core/modules/field/src/Tests/EntityReference/EntityReferenceTestTrait.php @@ -11,15 +11,15 @@ trait EntityReferenceTestTrait { /** - * Creates a field of an entity reference field storage on the specified bundle. + * Creates a field of an entity reference field storage on a given bundle. * * @param string $entity_type * The type of entity the field will be attached to. * @param string $bundle * The bundle name of the entity the field will be attached to. * @param string $field_name - * The name of the field; if it already exists, a new instance of the existing - * field will be created. + * The name of the field; if it already exists, a new instance of the + * existing field will be created. * @param string $field_label * The label of the field. * @param string $target_entity_type diff --git a/core/modules/field/tests/src/Kernel/EntityReference/EntityReferenceFormatterTest.php b/core/modules/field/tests/src/Kernel/EntityReference/EntityReferenceFormatterTest.php index 1473375..8a0a91d 100644 --- a/core/modules/field/tests/src/Kernel/EntityReference/EntityReferenceFormatterTest.php +++ b/core/modules/field/tests/src/Kernel/EntityReference/EntityReferenceFormatterTest.php @@ -4,8 +4,10 @@ use Drupal\Core\Cache\Cache; use Drupal\Core\Cache\CacheableMetadata; +use Drupal\Core\Entity\Entity\EntityViewDisplay; use Drupal\Core\Field\FieldStorageDefinitionInterface; use Drupal\Core\Field\Plugin\Field\FieldFormatter\EntityReferenceEntityFormatter; +use Drupal\entity_test\Entity\EntityTest; use Drupal\field\Entity\FieldConfig; use Drupal\field\Entity\FieldStorageConfig; use Drupal\field\Tests\EntityReference\EntityReferenceTestTrait; @@ -60,6 +62,9 @@ class EntityReferenceFormatterTest extends EntityKernelTestBase { */ protected $unsavedReferencedEntity; + /** + * {@inheritdoc} + */ protected function setUp() { parent::setUp(); @@ -402,6 +407,125 @@ public function testLabelFormatter() { } /** + * Tests entity_reference_field formatter output. + * + * @param string|null $label_option + * The value for the "label" formatter option. + * @param string $expected_output + * The expected output. + * + * @dataProvider providerTestRenderFieldFormatter + */ + public function testRenderFieldFormatter($label_option, $expected_output) { + FieldStorageConfig::create([ + 'field_name' => 'test_er_field', + 'entity_type' => 'entity_test', + 'type' => 'entity_reference', + 'settings' => [ + 'target_type' => 'entity_test', + ], + ])->save(); + + FieldConfig::create([ + 'field_name' => 'test_er_field', + 'entity_type' => 'entity_test', + 'bundle' => 'entity_test', + ])->save(); + + $parent_entity_view_display = EntityViewDisplay::load('entity_test.entity_test.default'); + $parent_entity_view_display->setComponent('test_er_field', [ + 'type' => 'entity_reference_field', + 'settings' => [ + 'field_name' => 'name', + 'type' => 'string', + 'settings' => [], + 'label' => $label_option, + ], + ])->save(); + + $child_entity = EntityTest::create([ + 'name' => ['child name'], + ]); + $child_entity->save(); + + $entity = EntityTest::create([ + 'test_er_field' => [[ + 'target_id' => $child_entity->id(), + ], + ], + ]); + $entity->save(); + + $build = $parent_entity_view_display->build($entity); + + $this->container->get('renderer')->renderRoot($build); + + $this->assertEquals($expected_output, $build['test_er_field']['#markup']); + } + + /** + * Data provider for ::testRenderFieldFormatter(). + */ + public function providerTestRenderFieldFormatter() { + $output_with_label = << +
test_er_field
+
+
+
Name
+
child name
+
+
+ + +EXPECTED; + $output_with_label_inline = << +
test_er_field
+
+
+
Name
+
child name
+
+
+ + +EXPECTED; + $output_label_hidden = << +
test_er_field
+
+
child name
+
+ + +EXPECTED; + $output_label_visually_hidden = << +
test_er_field
+
+
+
Name
+
child name
+
+
+ + +EXPECTED; + + return [ + ['above', $output_with_label], + ['inline', $output_with_label_inline], + ['hidden', $output_label_hidden], + ['visually_hidden', $output_label_visually_hidden], + ]; + } + + /** * Sets field values and returns a render array as built by * \Drupal\Core\Field\FieldItemListInterface::view(). * diff --git a/core/modules/field_ui/src/Form/EntityViewDisplayEditForm.php b/core/modules/field_ui/src/Form/EntityViewDisplayEditForm.php index c27f3d4..6b970d2 100644 --- a/core/modules/field_ui/src/Form/EntityViewDisplayEditForm.php +++ b/core/modules/field_ui/src/Form/EntityViewDisplayEditForm.php @@ -44,7 +44,7 @@ protected function buildFieldRow(FieldDefinitionInterface $field_definition, arr '#type' => 'select', '#title' => $this->t('Label display for @title', ['@title' => $field_definition->getLabel()]), '#title_display' => 'invisible', - '#options' => $this->getFieldLabelOptions(), + '#options' => static::getFieldLabelOptions(), '#default_value' => $display_options ? $display_options['label'] : 'above', ], ]; @@ -149,12 +149,12 @@ protected function getOverviewUrl($mode) { * @return array * An array of visibility options. */ - protected function getFieldLabelOptions() { + public static function getFieldLabelOptions() { return [ - 'above' => $this->t('Above'), - 'inline' => $this->t('Inline'), - 'hidden' => '- ' . $this->t('Hidden') . ' -', - 'visually_hidden' => '- ' . $this->t('Visually Hidden') . ' -', + 'above' => t('Above'), + 'inline' => t('Inline'), + 'hidden' => '- ' . t('Hidden') . ' -', + 'visually_hidden' => '- ' . t('Visually Hidden') . ' -', ]; } diff --git a/core/tests/Drupal/FunctionalJavascriptTests/EntityReference/EntityReferenceFieldFormatterTest.php b/core/tests/Drupal/FunctionalJavascriptTests/EntityReference/EntityReferenceFieldFormatterTest.php new file mode 100644 index 0000000..3f1c64d --- /dev/null +++ b/core/tests/Drupal/FunctionalJavascriptTests/EntityReference/EntityReferenceFieldFormatterTest.php @@ -0,0 +1,145 @@ +drupalCreateUser([ + 'bypass node access', + 'administer node display', + ]); + $this->drupalLogin($user); + + $this->createContentType(['type' => 'page']); + $field_name = 'field_related_content'; + $this->createEntityReferenceField('node', 'page', $field_name, 'Related Content', 'node', 'default', ['target_bundles' => ['page']]); + EntityViewDisplay::load('node.page.default') + ->setComponent($field_name, [ + 'type' => 'entity_reference_label', + ])->save(); + + $this->testChildNode = $this->createNode([ + 'title' => 'Child test node', + 'body' => [ + [ + 'value' => 'Lorem ipsum dolor sit', + 'format' => filter_default_format(), + ], + ], + ]); + + $this->testParentNode = $this->createNode([ + 'title' => 'Parent test node', + 'field_related_content' => [[ + 'target_id' => $this->testChildNode->id(), + ], + ], + ]); + } + + /** + * Tests the Referenced Entity Field formatter configuration. + */ + public function testEntityReferenceFieldFormatter() { + $page = $this->getSession()->getPage(); + $assert_session = $this->assertSession(); + + // Visit the display config page. + $this->drupalGet('/admin/structure/types/manage/page/display'); + $page->selectFieldOption('fields[field_related_content][type]', 'entity_reference_field'); + $result = $assert_session->waitForElementVisible('css', '.field-plugin-summary-cell .ajax-new-content'); + $this->assertNotEmpty($result); + $assert_session->pageTextContains('The field "Title" will be used by default.'); + $assert_session->pageTextContains('The "Plain text" formatter will be used by default.'); + + // Save without choosing anything and verify that the child title is shown + // by default. + $page->pressButton('Save'); + $this->drupalGet('/node/' . $this->testParentNode->id()); + $assert_session->elementTextContains('css', '.field--name-field-related-content .field__item .field--name-title.field--label-hidden', 'Child test node'); + $assert_session->pageTextNotContains('Lorem ipsum dolor sit'); + + // Open the formatter settings, really choose the title field and save. + $this->drupalGet('/admin/structure/types/manage/page/display'); + $page->find('css', 'input[data-drupal-selector="edit-fields-field-related-content-settings-edit"]')->click(); + $assert_session->assertWaitOnAjaxRequest(); + $assert_session->selectExists('fields[field_related_content][settings_edit_form][settings][field_name]'); + $assert_session->selectExists('fields[field_related_content][settings_edit_form][settings][label]'); + $assert_session->selectExists('fields[field_related_content][settings_edit_form][settings][type]'); + $assert_session->optionNotExists('fields[field_related_content][settings_edit_form][settings][type]', 'entity_reference_entity_id'); + $assert_session->checkboxNotChecked('fields[field_related_content][settings_edit_form][settings][settings][link_to_entity]'); + $page->pressButton('Update'); + $assert_session->assertWaitOnAjaxRequest(); + $page->pressButton('Save'); + $this->drupalGet('/node/' . $this->testParentNode->id()); + $assert_session->elementTextContains('css', '.field--name-field-related-content .field__item .field--name-title.field--label-hidden', 'Child test node'); + $assert_session->pageTextNotContains('Lorem ipsum dolor sit'); + + // Test the body field of the child entity. + $this->drupalGet('/admin/structure/types/manage/page/display'); + $page->find('css', 'input[data-drupal-selector="edit-fields-field-related-content-settings-edit"]')->click(); + $assert_session->assertWaitOnAjaxRequest(); + $page->selectFieldOption('fields[field_related_content][settings_edit_form][settings][field_name]', 'body'); + $assert_session->assertWaitOnAjaxRequest(); + $page->selectFieldOption('fields[field_related_content][settings_edit_form][settings][type]', 'text_default'); + $assert_session->assertWaitOnAjaxRequest(); + $page->pressButton('Update'); + $result = $assert_session->waitForElementVisible('css', '.field-plugin-summary-cell .ajax-new-content'); + $this->assertNotEmpty($result); + $assert_session->pageTextContains('Field "Body" displayed.'); + $assert_session->pageTextContains('Formatter "Default" used.'); + $page->pressButton('Save'); + + $this->drupalGet('/node/' . $this->testParentNode->id()); + $assert_session->elementTextContains('css', '.field--name-field-related-content .field__item .field--name-body.field--label-hidden', 'Lorem ipsum dolor sit'); + $assert_session->pageTextNotContains('Child test node'); + } + +}