diff --git a/config/schema/dynamic_entity_reference.schema.yml b/config/schema/dynamic_entity_reference.schema.yml
index fe29f09..1e6c4b3 100644
--- a/config/schema/dynamic_entity_reference.schema.yml
+++ b/config/schema/dynamic_entity_reference.schema.yml
@@ -46,15 +46,18 @@ field.value.dynamic_entity_reference:
label: 'Type of item to reference'
field.formatter.settings.dynamic_entity_reference_entity_view:
- type: mapping
+ type: sequence
label: 'Dynamic entity reference rendered entity display format settings'
- mapping:
- view_mode:
- type: string
- label: 'View mode'
- link:
- type: boolean
- label: 'Show links'
+ sequence:
+ type: mapping
+ label: 'Entity Type ID'
+ mapping:
+ view_mode:
+ type: string
+ label: 'View modes'
+ link:
+ type: boolean
+ label: 'Show links'
field.formatter.settings.dynamic_entity_reference_entity_id:
type: mapping
diff --git a/src/Plugin/Field/FieldFormatter/DynamicEntityReferenceEntityFormatter.php b/src/Plugin/Field/FieldFormatter/DynamicEntityReferenceEntityFormatter.php
index 6ef1d5a..f0b11e6 100644
--- a/src/Plugin/Field/FieldFormatter/DynamicEntityReferenceEntityFormatter.php
+++ b/src/Plugin/Field/FieldFormatter/DynamicEntityReferenceEntityFormatter.php
@@ -3,7 +3,10 @@
namespace Drupal\dynamic_entity_reference\Plugin\Field\FieldFormatter;
use Drupal\Core\Field\FieldDefinitionInterface;
+use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\Plugin\Field\FieldFormatter\EntityReferenceEntityFormatter;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\dynamic_entity_reference\Plugin\Field\FieldType\DynamicEntityReferenceItem;
/**
* Plugin implementation of the 'rendered entity' formatter.
@@ -28,4 +31,112 @@ class DynamicEntityReferenceEntityFormatter extends EntityReferenceEntityFormatt
return TRUE;
}
+ /**
+ * {@inheritdoc}
+ */
+ public static function defaultSettings() {
+ $labels = \Drupal::service('entity_type.repository')->getEntityTypeLabels(TRUE);
+ $options = array_keys($labels[(string) t('Content', [], ['context' => 'Entity type group'])]);
+ return array_fill_keys($options, ['view_mode' => 'default', 'link' => FALSE]);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function settingsSummary() {
+ $labels = \Drupal::service('entity_type.repository')->getEntityTypeLabels(TRUE);
+ $options = $labels[(string) t('Content', [], ['context' => 'Entity type group'])];
+ $entity_type_ids = DynamicEntityReferenceItem::getTargetTypes($this->getFieldSettings());
+ $available = [];
+ foreach ($this->getSettings() as $key => $value) {
+ if (in_array($key, array_values($entity_type_ids))) {
+ $available[$key] = $value;
+ }
+ }
+ if (!empty($available)) {
+ return array_map(function ($entity_type_id, $settings) use ($options) {
+ return t('Rendered %entity as view mode: @mode', [
+ '%entity' => $options[$entity_type_id],
+ '@mode' => $settings['view_mode'],
+ ]);
+ }, array_keys($available), $available);
+ }
+ else {
+ return [];
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function settingsForm(array $form, FormStateInterface $form_state) {
+ $labels = \Drupal::service('entity_type.repository')->getEntityTypeLabels(TRUE);
+ $options = $labels[(string) t('Content', [], ['context' => 'Entity type group'])];
+ $entity_type_ids = DynamicEntityReferenceItem::getTargetTypes($this->getFieldSettings());
+ $elements['view_mode'] = [];
+
+ foreach ($entity_type_ids as $entity_type_id) {
+ $elements[$entity_type_id] = [
+ '#type' => 'container',
+ ];
+ $elements[$entity_type_id]['view_mode'] = [
+ '#type' => 'select',
+ '#options' => $this->entityDisplayRepository->getViewModeOptions($entity_type_id),
+ '#title' => t('View mode for %entity', ['%entity' => $options[$entity_type_id]]),
+ '#default_value' => $this->getSetting($entity_type_id)['view_mode'],
+ '#required' => TRUE,
+ ];
+ }
+
+ return $elements;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function viewElements(FieldItemListInterface $items, $langcode) {
+ $elements = [];
+
+ foreach ($this->getEntitiesToView($items, $langcode) as $delta => $entity) {
+ // Due to render caching and delayed calls, the viewElements() method
+ // will be called later in the rendering process through a '#pre_render'
+ // callback, so we need to generate a counter that takes into account
+ // all the relevant information about this field and the referenced
+ // entity that is being rendered.
+ $recursive_render_id = $items->getFieldDefinition()->getTargetEntityTypeId()
+ . $items->getFieldDefinition()->getTargetBundle()
+ . $items->getName()
+ . $entity->id();
+
+ if (isset(static::$recursiveRenderDepth[$recursive_render_id])) {
+ static::$recursiveRenderDepth[$recursive_render_id]++;
+ }
+ else {
+ static::$recursiveRenderDepth[$recursive_render_id] = 1;
+ }
+
+ // Protect ourselves from recursive rendering.
+ if (static::$recursiveRenderDepth[$recursive_render_id] > static::RECURSIVE_RENDER_LIMIT) {
+ $this->loggerFactory->get('entity')->error('Recursive rendering detected when rendering entity %entity_type: %entity_id, using the %field_name field on the %bundle_name bundle. Aborting rendering.', [
+ '%entity_type' => $entity->getEntityTypeId(),
+ '%entity_id' => $entity->id(),
+ '%field_name' => $items->getName(),
+ '%bundle_name' => $items->getFieldDefinition()->getTargetBundle(),
+ ]);
+ return $elements;
+ }
+ $entity_type_id = $entity->getEntityTypeId();
+ $view_builder = $this->entityTypeManager->getViewBuilder($entity_type_id);
+ $elements[$delta] = $view_builder->view($entity, $this->getSetting($entity_type_id)['view_mode'], $entity->language()->getId());
+ // Add a resource attribute to set the mapping property's value to the
+ // entity's url. Since we don't know what the markup of the entity will
+ // be, we shouldn't rely on it for structured data such as RDFa.
+ if (!empty($items[$delta]->_attributes) && !$entity->isNew() && $entity->hasLinkTemplate('canonical')) {
+ $items[$delta]->_attributes += array('resource' => $entity->toUrl()->toString());
+ }
+ }
+
+ return $elements;
+ }
+
}
diff --git a/tests/src/FunctionalJavascript/DynamicEntityReferenceTest.php b/tests/src/FunctionalJavascript/DynamicEntityReferenceTest.php
index df92b06..7c5849f 100644
--- a/tests/src/FunctionalJavascript/DynamicEntityReferenceTest.php
+++ b/tests/src/FunctionalJavascript/DynamicEntityReferenceTest.php
@@ -56,6 +56,7 @@ class DynamicEntityReferenceTest extends JavascriptTestBase {
'field_ui',
'dynamic_entity_reference',
'entity_test',
+ 'node',
];
/**
@@ -68,6 +69,8 @@ class DynamicEntityReferenceTest extends JavascriptTestBase {
'view test entity',
'administer entity_test fields',
'administer entity_test content',
+ 'administer node fields',
+ 'administer node display',
'access user profiles',
];
@@ -187,6 +190,76 @@ class DynamicEntityReferenceTest extends JavascriptTestBase {
}
/**
+ * Tests view modes in formatter of dynamic entity reference field.
+ */
+ public function testFieldFormatterViewModes() {
+ $assert_session = $this->assertSession();
+ $this->drupalLogin($this->adminUser);
+ $this->drupalCreateContentType(['type' => 'test_content']);
+ $this->drupalGet('/admin/structure/types/manage/test_content/fields/add-field');
+ $edit = [
+ 'label' => 'Foobar',
+ 'field_name' => 'foobar',
+ 'new_storage_type' => 'dynamic_entity_reference',
+ ];
+ $this->submitForm($edit, t('Save and continue'), 'field-ui-field-storage-add-form');
+ $page = $this->getSession()->getPage();
+ $entity_type_ids_select = $assert_session->selectExists('settings[entity_type_ids][]', $page);
+ $entity_type_ids_select->selectOption('user');
+ $assert_session->selectExists('cardinality', $page)
+ ->selectOption(FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED);
+ $page->uncheckField('settings[exclude_entity_types]');
+ $this->submitForm([], t('Save field settings'), 'field-storage-config-edit-form');
+ $this->drupalGet('admin/structure/types/manage/test_content/display');
+ $page = $this->getSession()->getPage();
+ $formats = $assert_session->selectExists('fields[field_foobar][type]', $page);
+ $formats->selectOption('dynamic_entity_reference_entity_view');
+ $assert_session->assertWaitOnAjaxRequest();
+ $page->pressButton('Edit');
+ $assert_session->assertWaitOnAjaxRequest();
+ $page = $this->getSession()->getPage();
+ $assert_session->selectExists('fields[field_foobar][settings_edit_form][settings][user][view_mode]', $page);
+ $assert_session->optionExists('fields[field_foobar][settings_edit_form][settings][user][view_mode]', 'compact', $page);
+ $assert_session->optionExists('fields[field_foobar][settings_edit_form][settings][user][view_mode]', 'full', $page);
+ // Edit field, turn on exclude entity types and check display again.
+ $this->drupalGet('admin/structure/types/manage/test_content/fields/node.test_content.field_foobar/storage');
+ $page->checkField('settings[exclude_entity_types]');
+ $this->submitForm([], t('Save field settings'), 'field-storage-config-edit-form');
+ $this->drupalGet('admin/structure/types/manage/test_content/display');
+ $page = $this->getSession()->getPage();
+ $formats = $assert_session->selectExists('fields[field_foobar][type]', $page);
+ $formats->selectOption('dynamic_entity_reference_entity_view');
+ $assert_session->assertWaitOnAjaxRequest();
+ // Assert node view mode is set on default.
+ $assert_session->responseContains("Rendered Content as view mode: default");
+ $page->pressButton('Edit');
+ $assert_session->assertWaitOnAjaxRequest();
+ $page = $this->getSession()->getPage();
+ // Assert we have multi select form items for view mode settings.
+ $assert_session->selectExists('fields[field_foobar][settings_edit_form][settings][entity_test_with_bundle][view_mode]', $page);
+ $assert_session->responseContains("View mode for Test entity with bundle");
+ $assert_session->optionExists('fields[field_foobar][settings_edit_form][settings][entity_test_with_bundle][view_mode]', 'default', $page);
+ $assert_session->optionNotExists('fields[field_foobar][settings_edit_form][settings][entity_test_with_bundle][view_mode]', 'rss', $page);
+ $node_view_modes = $assert_session->selectExists('fields[field_foobar][settings_edit_form][settings][node][view_mode]', $page);
+ $assert_session->responseContains("View mode for Content");
+ $assert_session->optionExists('fields[field_foobar][settings_edit_form][settings][node][view_mode]', 'default', $page);
+ $assert_session->optionExists('fields[field_foobar][settings_edit_form][settings][node][view_mode]', 'full', $page);
+ $assert_session->optionExists('fields[field_foobar][settings_edit_form][settings][node][view_mode]', 'rss', $page);
+ $assert_session->optionExists('fields[field_foobar][settings_edit_form][settings][node][view_mode]', 'teaser', $page);
+ // Select different select options and assert summary is changed properly.
+ $node_view_modes->selectOption('teaser');
+ $page->pressButton('Update');
+ $assert_session->assertWaitOnAjaxRequest();
+ $assert_session->responseContains("Rendered Content as view mode: teaser");
+ $page->pressButton('Edit');
+ $assert_session->assertWaitOnAjaxRequest();
+ $node_view_modes->selectOption('rss');
+ $page->pressButton('Update');
+ $assert_session->assertWaitOnAjaxRequest();
+ $assert_session->responseContains("Rendered Content as view mode: rss");
+ }
+
+ /**
* Creates auto complete path for the given target type.
*
* @param string $target_type
diff --git a/tests/src/Kernel/DynamicEntityReferenceFormatterTest.php b/tests/src/Kernel/DynamicEntityReferenceFormatterTest.php
index b5bd51f..87fca8f 100644
--- a/tests/src/Kernel/DynamicEntityReferenceFormatterTest.php
+++ b/tests/src/Kernel/DynamicEntityReferenceFormatterTest.php
@@ -182,6 +182,7 @@ class DynamicEntityReferenceFormatterTest extends EntityKernelTestBase {
entity_get_display($this->entityType, $this->bundle, 'default')
->setComponent($field_name, [
'type' => $formatter,
+ 'settings' => $formatter == 'dynamic_entity_reference_entity_view' ? ['view_mode' => [$referencing_entity->getEntityTypeId() => 'default']] : [],
])
->save();
@@ -212,7 +213,16 @@ class DynamicEntityReferenceFormatterTest extends EntityKernelTestBase {
/** @var \Drupal\Core\Render\RendererInterface $renderer */
$renderer = $this->container->get('renderer');
$formatter = 'dynamic_entity_reference_entity_view';
- $build = $this->buildRenderArray([$this->referencedEntity, $this->unsavedReferencedEntity], $formatter);
+ $build = $this->buildRenderArray([$this->referencedEntity, $this->unsavedReferencedEntity], $formatter, [
+ $this->referencedEntity->getEntityTypeId() => [
+ 'view_mode' => 'default',
+ 'link' => FALSE,
+ ],
+ $this->unsavedReferencedEntity->getEntityTypeId() => [
+ 'view_mode' => 'default',
+ 'link' => FALSE,
+ ],
+ ]);
// Test the first field item.
$expected_rendered_name_field_1 = '
diff --git a/tests/src/Kernel/DynamicEntityReferenceSchemaTest.php b/tests/src/Kernel/DynamicEntityReferenceSchemaTest.php
index 696bd68..07e6647 100644
--- a/tests/src/Kernel/DynamicEntityReferenceSchemaTest.php
+++ b/tests/src/Kernel/DynamicEntityReferenceSchemaTest.php
@@ -142,8 +142,10 @@ class DynamicEntityReferenceSchemaTest extends EntityKernelTestBase {
'type' => 'dynamic_entity_reference_entity_view',
'label' => 'above',
'settings' => [
- 'view_mode' => 'default',
- 'link' => FALSE,
+ $referenced_entity->getEntityTypeId() => [
+ 'view_mode' => 'default',
+ 'link' => FALSE,
+ ],
],
'third_party_settings' => [],
])->save();