diff --git a/core/lib/Drupal/Core/Field/EntityReferenceFieldItemList.php b/core/lib/Drupal/Core/Field/EntityReferenceFieldItemList.php index a47e23b30b8ffa4f0422df8acc8dff28c6bd8637..3d1e33e8ddd458ec515a44fecc9cbef9c7c4ebed 100644 --- a/core/lib/Drupal/Core/Field/EntityReferenceFieldItemList.php +++ b/core/lib/Drupal/Core/Field/EntityReferenceFieldItemList.php @@ -23,27 +23,29 @@ public function referencedEntities() { return array(); } - // Get a list of items having non-empty target ids. - $list = array_filter($this->list, function($item) { - return (bool) $item->target_id; - }); - - $ids = array(); - foreach ($list as $delta => $item) { - $ids[$delta] = $item->target_id; - } - if (empty($ids)) { - return array(); + // Collect the IDs of existing entities to load, and directly grab the + // "autocreate" entities that are already populated in $item->entity. + $target_entities = $ids = array(); + foreach ($this->list as $delta => $item) { + if ($item->target_id !== NULL) { + $ids[$delta] = $item->target_id; + } + elseif ($item->hasNewEntity()) { + $target_entities[$delta] = $item->entity; + } } - $target_type = $this->getFieldDefinition()->getSetting('target_type'); - $entities = \Drupal::entityManager()->getStorage($target_type)->loadMultiple($ids); - - $target_entities = array(); - foreach ($ids as $delta => $target_id) { - if (isset($entities[$target_id])) { - $target_entities[$delta] = $entities[$target_id]; + // Load and add the existing entities. + if ($ids) { + $target_type = $this->getFieldDefinition()->getSetting('target_type'); + $entities = \Drupal::entityManager()->getStorage($target_type)->loadMultiple($ids); + foreach ($ids as $delta => $target_id) { + if (isset($entities[$target_id])) { + $target_entities[$delta] = $entities[$target_id]; + } } + // Ensure the returned array is ordered by deltas. + ksort($target_entities); } return $target_entities; diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EntityReferenceItem.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EntityReferenceItem.php index a14fe00b9e5cc423026cb275b3d0e9f156dc3d1f..a6c6bedf94fd613111f25207c82116baad329798 100644 --- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EntityReferenceItem.php +++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EntityReferenceItem.php @@ -8,7 +8,7 @@ namespace Drupal\Core\Field\Plugin\Field\FieldType; use Drupal\Core\Config\Entity\ConfigEntityType; -use Drupal\Core\Entity\Entity; +use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Entity\TypedData\EntityDataDefinition; use Drupal\Core\Field\FieldDefinitionInterface; @@ -166,7 +166,7 @@ public function getValue($include_computed = FALSE) { // If there is an unsaved entity, return it as part of the field item values // to ensure idempotency of getValue() / setValue(). - if ($this->hasUnsavedEntity()) { + if ($this->hasNewEntity()) { $values['entity'] = $this->entity; } return $values; @@ -191,11 +191,10 @@ public function onChange($property_name) { */ public function isEmpty() { // Avoid loading the entity by first checking the 'target_id'. - $target_id = $this->target_id; - if ($target_id !== NULL) { + if ($this->target_id !== NULL) { return FALSE; } - if ($this->entity && $this->entity instanceof Entity) { + if ($this->entity && $this->entity instanceof EntityInterface) { return FALSE; } return TRUE; @@ -205,12 +204,12 @@ public function isEmpty() { * {@inheritdoc} */ public function preSave() { - if ($this->hasUnsavedEntity()) { + if ($this->hasNewEntity()) { $this->entity->save(); } // Handle the case where an unsaved entity was directly set using the public // 'entity' property and then saved before this entity. In this case - // ::hasUnsavedEntity() will return FALSE but $this->target_id will still be + // ::hasNewEntity() will return FALSE but $this->target_id will still be // empty. if (empty($this->target_id) && $this->entity) { $this->target_id = $this->entity->id(); @@ -239,7 +238,7 @@ public static function generateSampleValue(FieldDefinitionInterface $field_defin * @return bool * TRUE if the item holds an unsaved entity. */ - public function hasUnsavedEntity() { + public function hasNewEntity() { return $this->target_id === NULL && ($entity = $this->entity) && $entity->isNew(); } diff --git a/core/modules/entity_reference/src/Plugin/Field/FieldFormatter/EntityReferenceFormatterBase.php b/core/modules/entity_reference/src/Plugin/Field/FieldFormatter/EntityReferenceFormatterBase.php index 3a32d69b14b06233f7e13e77ac1ad60d9603a1f3..153449921f82708fa2c5168a5571fe5ea0bb85d0 100644 --- a/core/modules/entity_reference/src/Plugin/Field/FieldFormatter/EntityReferenceFormatterBase.php +++ b/core/modules/entity_reference/src/Plugin/Field/FieldFormatter/EntityReferenceFormatterBase.php @@ -30,6 +30,14 @@ protected function getEntitiesToView(FieldItemListInterface $items) { $parent_entity_langcode = $items->getEntity()->language()->getId(); foreach ($items as $delta => $item) { + // The "originalEntity" property is assigned in self::prepareView() and + // its absence means that the referenced entity was neither found in the + // persistent storage nor is it a new entity (e.g. from "autocreate"). + if (!isset($item->originalEntity)) { + $item->access = FALSE; + continue; + } + if ($item->originalEntity instanceof TranslatableInterface && $item->originalEntity->hasTranslation($parent_entity_langcode)) { $entity = $item->originalEntity->getTranslation($parent_entity_langcode); } @@ -51,47 +59,38 @@ protected function getEntitiesToView(FieldItemListInterface $items) { /** * {@inheritdoc} * - * Mark the accessible IDs a user can see. We do not unset unaccessible - * values, as other may want to act on those values, even if they can - * not be accessed. + * Loads the entities referenced in that field across all the entities being + * viewed, and places them in a custom item property for getEntitiesToView(). */ public function prepareView(array $entities_items) { - $target_ids = array(); - - // Collect every possible entity attached to any of the entities. + // Load the existing (non-autocreate) entities. For performance, we want to + // use a single "multiple entity load" to load all the entities for the + // multiple "entity reference item lists" that are being displayed. We thus + // cannot use + // \Drupal\Core\Field\EntityReferenceFieldItemList::referencedEntities(). + $ids = array(); foreach ($entities_items as $items) { foreach ($items as $item) { - if (!empty($item->target_id)) { - $target_ids[] = $item->target_id; + if ($item->target_id !== NULL) { + $ids[] = $item->target_id; } } } - - $target_type = $this->getFieldSetting('target_type'); - - $target_entities = array(); - - if ($target_ids) { - $target_entities = entity_load_multiple($target_type, $target_ids); + if ($ids) { + $target_type = $this->getFieldSetting('target_type'); + $target_entities = \Drupal::entityManager()->getStorage($target_type)->loadMultiple($ids); } - // Iterate through the fieldable entities again to attach the loaded data. + // For each item, place the referenced entity where getEntitiesToView() + // reads it. foreach ($entities_items as $items) { - $rekey = FALSE; foreach ($items as $item) { - if ($item->target_id !== 0 && !isset($target_entities[$item->target_id])) { - // The entity no longer exists, so empty the item. - $item->setValue(NULL); - $rekey = TRUE; - continue; + if (isset($target_entities[$item->target_id])) { + $item->originalEntity = $target_entities[$item->target_id]; + } + elseif ($item->hasNewEntity()) { + $item->originalEntity = $item->entity; } - - $item->originalEntity = $target_entities[$item->target_id]; - } - - // Re-key the items array if needed. - if ($rekey) { - $items->filterEmptyItems(); } } } diff --git a/core/modules/entity_reference/src/Plugin/Field/FieldFormatter/EntityReferenceLabelFormatter.php b/core/modules/entity_reference/src/Plugin/Field/FieldFormatter/EntityReferenceLabelFormatter.php index 238d47b4753054741c4598728f4903388285277c..74c6bdeaf9c47cf509cf3c88fe068f52e6f7d57b 100644 --- a/core/modules/entity_reference/src/Plugin/Field/FieldFormatter/EntityReferenceLabelFormatter.php +++ b/core/modules/entity_reference/src/Plugin/Field/FieldFormatter/EntityReferenceLabelFormatter.php @@ -66,7 +66,7 @@ public function viewElements(FieldItemListInterface $items) { $label = $entity->label(); // If the link is to be displayed and the entity has a uri, display a // link. - if ($this->getSetting('link') && $uri = $entity->urlInfo()) { + if ($this->getSetting('link') && !$entity->isNew() && $uri = $entity->urlInfo()) { $elements[$delta] = [ '#type' => 'link', '#title' => $label, diff --git a/core/modules/entity_reference/src/Plugin/Field/FieldWidget/AutocompleteWidget.php b/core/modules/entity_reference/src/Plugin/Field/FieldWidget/AutocompleteWidget.php index 207910f8e57399010c8ae1c2d9c044f0cdde610e..e9a0cf89afea0ab0b17f1e2923e5914f55e5d829 100644 --- a/core/modules/entity_reference/src/Plugin/Field/FieldWidget/AutocompleteWidget.php +++ b/core/modules/entity_reference/src/Plugin/Field/FieldWidget/AutocompleteWidget.php @@ -7,7 +7,6 @@ namespace Drupal\entity_reference\Plugin\Field\FieldWidget; -use Drupal\Core\Field\FieldItemListInterface; use Drupal\Core\Form\FormStateInterface; /** @@ -43,18 +42,6 @@ public static function defaultSettings() { ) + parent::defaultSettings(); } - /** - * {@inheritdoc} - */ - protected function getEntityIds(FieldItemListInterface $items, $delta) { - // The autocomplete widget outputs one entity label per form element. - if (isset($items[$delta])) { - return array($items[$delta]->target_id); - } - - return array(); - } - /** * {@inheritdoc} */ diff --git a/core/modules/entity_reference/src/Plugin/Field/FieldWidget/AutocompleteWidgetBase.php b/core/modules/entity_reference/src/Plugin/Field/FieldWidget/AutocompleteWidgetBase.php index 975ec4f1796966330b8c97762555e350aae2ebd5..40d0aaf2099c16e6d971566a18d9dd1cbe0c87e0 100644 --- a/core/modules/entity_reference/src/Plugin/Field/FieldWidget/AutocompleteWidgetBase.php +++ b/core/modules/entity_reference/src/Plugin/Field/FieldWidget/AutocompleteWidgetBase.php @@ -8,6 +8,7 @@ namespace Drupal\entity_reference\Plugin\Field\FieldWidget; use Drupal\Component\Utility\Tags; +use Drupal\Core\Field\EntityReferenceFieldItemListInterface; use Drupal\Core\Field\FieldItemListInterface; use Drupal\Core\Field\WidgetBase; use Drupal\Core\Form\FormStateInterface; @@ -116,47 +117,32 @@ public function elementValidate($element, FormStateInterface $form_state, $form) /** * Gets the entity labels. */ - protected function getLabels(FieldItemListInterface $items, $delta) { + protected function getLabels(EntityReferenceFieldItemListInterface $items, $delta) { if ($items->isEmpty()) { return array(); } $entity_labels = array(); + $handles_multiple_values = $this->handlesMultipleValues(); + foreach ($items->referencedEntities() as $referenced_delta => $referenced_entity) { + // The autocomplete widget outputs one entity label per form element. + if (!$handles_multiple_values && $referenced_delta != $delta) { + continue; + } - // Load those entities and loop through them to extract their labels. - $entities = entity_load_multiple($this->getFieldSetting('target_type'), $this->getEntityIds($items, $delta)); + $key = $referenced_entity->label(); + + // Take into account "autocreate" items. + if (!$referenced_entity->isNew()) { + $key .= ' (' . $referenced_entity->id() . ')'; + } - foreach ($entities as $entity_id => $entity_item) { - $label = $entity_item->label(); - $key = "$label ($entity_id)"; // Labels containing commas or quotes must be wrapped in quotes. - $key = Tags::encode($key); - $entity_labels[] = $key; + $entity_labels[] = Tags::encode($key); } return $entity_labels; } - /** - * Builds an array of entity IDs for which to get the entity labels. - * - * @param \Drupal\Core\Field\FieldItemListInterface $items - * Array of default values for this field. - * @param int $delta - * The order of a field item in the array of subelements (0, 1, 2, etc). - * - * @return array - * An array of entity IDs. - */ - protected function getEntityIds(FieldItemListInterface $items, $delta) { - $entity_ids = array(); - - foreach ($items as $item) { - $entity_ids[] = $item->target_id; - } - - return $entity_ids; - } - /** * Creates a new entity from a label entered in the autocomplete input. * diff --git a/core/modules/entity_reference/src/Tests/EntityReferenceFieldTest.php b/core/modules/entity_reference/src/Tests/EntityReferenceFieldTest.php index 115998ebe666dccbe025cda87c81c6ea64ad4548..0587e931b67e88f9a5fcc3a14af92dfa480144bf 100644 --- a/core/modules/entity_reference/src/Tests/EntityReferenceFieldTest.php +++ b/core/modules/entity_reference/src/Tests/EntityReferenceFieldTest.php @@ -127,6 +127,12 @@ public function testReferencedEntitiesMultipleLoad() { $reference_field[5] = $reference_field[0]; $target_entities[5] = $target_entities[0]; + // Create a new target entity that is not saved, thus testing the + // "autocreate" feature. + $target_entity_unsaved = entity_create($this->referencedEntityType, array('type' => $this->bundle, 'name' => $this->randomString())); + $reference_field[6]['entity'] = $target_entity_unsaved; + $target_entities[6] = $target_entity_unsaved; + // Set the field value. $entity->{$this->fieldName}->setValue($reference_field); @@ -138,9 +144,16 @@ public function testReferencedEntitiesMultipleLoad() { // - Non-existent entities must not be retrieved in target entities result. foreach ($target_entities as $delta => $target_entity) { if (!empty($target_entity)) { - // There must be an entity in the loaded set having the same id for the - // same delta. - $this->assertEqual($target_entity->id(), $entities[$delta]->id()); + if (!$target_entity->isNew()) { + // There must be an entity in the loaded set having the same id for + // the same delta. + $this->assertEqual($target_entity->id(), $entities[$delta]->id()); + } + else { + // For entities that were not yet saved, there must an entity in the + // loaded set having the same label for the same delta. + $this->assertEqual($target_entity->label(), $entities[$delta]->label()); + } } else { // A non-existent or NULL entity target id must not return any item in diff --git a/core/modules/entity_reference/src/Tests/EntityReferenceFormatterTest.php b/core/modules/entity_reference/src/Tests/EntityReferenceFormatterTest.php index d51da8caefad7fe2c97bef5367c020edefa8a959..642ae9078ab1e2d697d4a89dde052c079bc520c3 100644 --- a/core/modules/entity_reference/src/Tests/EntityReferenceFormatterTest.php +++ b/core/modules/entity_reference/src/Tests/EntityReferenceFormatterTest.php @@ -8,6 +8,7 @@ namespace Drupal\entity_reference\Tests; use Drupal\Core\Cache\Cache; +use Drupal\Core\Field\FieldStorageDefinitionInterface; use Drupal\filter\Entity\FilterFormat; use Drupal\system\Tests\Entity\EntityUnitTestBase; @@ -44,7 +45,15 @@ class EntityReferenceFormatterTest extends EntityUnitTestBase { * * @var \Drupal\Core\Entity\EntityInterface */ - protected $referencedEntity = NULL; + protected $referencedEntity; + + /** + * The entity that is not yet saved to its persistent storage to be referenced + * in this test. + * + * @var \Drupal\Core\Entity\EntityInterface + */ + protected $unsavedReferencedEntity; /** * Modules to install. @@ -56,7 +65,11 @@ class EntityReferenceFormatterTest extends EntityUnitTestBase { protected function setUp() { parent::setUp(); - entity_reference_create_field($this->entityType, $this->bundle, $this->fieldName, 'Field test', $this->entityType); + // The label formatter rendering generates links, so build the router. + $this->installSchema('system', 'router'); + $this->container->get('router.builder')->rebuild(); + + entity_reference_create_field($this->entityType, $this->bundle, $this->fieldName, 'Field test', $this->entityType, 'default', array(), FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED); // Set up a field, so that the entity that'll be referenced bubbles up a // cache tag when rendering it entirely. @@ -91,6 +104,13 @@ protected function setUp() { 'format' => 'full_html', ); $this->referencedEntity->save(); + + // Create another entity to be referenced but do not save it. + $this->unsavedReferencedEntity = entity_create($this->entityType, array('name' => $this->randomMachineName())); + $this->unsavedReferencedEntity->body = array( + 'value' => '<p>Hello, unsaved world!</p>', + 'format' => 'full_html', + ); } /** @@ -130,21 +150,11 @@ public function testAccess() { */ public function testIdFormatter() { $formatter = 'entity_reference_entity_id'; - $field_name = $this->fieldName; - - // Create the entity that will have the entity reference field. - $referencing_entity = entity_create($this->entityType, array('name' => $this->randomMachineName())); - $referencing_entity->save(); - $referencing_entity->{$field_name}->entity = $this->referencedEntity; - $referencing_entity->{$field_name}->access = TRUE; - - // Build the renderable array for the entity reference field. - $items = $referencing_entity->get($field_name); - $build = $items->view(array('type' => $formatter)); - - $this->assertEqual($build[0]['#markup'], $this->referencedEntity->id(), format_string('The markup returned by the @formatter formatter is correct.', array('@formatter' => $formatter))); - $this->assertEqual($build[0]['#cache']['tags'], $this->referencedEntity->getCacheTags(), format_string('The @formatter formatter has the expected cache tags.', array('@formatter' => $formatter))); + $build = $this->buildRenderArray([$this->referencedEntity, $this->unsavedReferencedEntity], $formatter); + $this->assertEqual($build[0]['#markup'], $this->referencedEntity->id(), sprintf('The markup returned by the %s formatter is correct for an item with a saved entity.', $formatter)); + $this->assertEqual($build[0]['#cache']['tags'], $this->referencedEntity->getCacheTags(), sprintf('The %s formatter has the expected cache tags.', $formatter)); + $this->assertTrue(!isset($build[1]), sprintf('The markup returned by the %s formatter is correct for an item with a unsaved entity.', $formatter)); } /** @@ -152,25 +162,16 @@ public function testIdFormatter() { */ public function testEntityFormatter() { $formatter = 'entity_reference_entity_view'; - $field_name = $this->fieldName; - - // Create the entity that will have the entity reference field. - $referencing_entity = entity_create($this->entityType, array('name' => $this->randomMachineName())); - $referencing_entity->save(); - $referencing_entity->{$field_name}->entity = $this->referencedEntity; - $referencing_entity->{$field_name}->access = TRUE; - - // Build the renderable array for the entity reference field. - $items = $referencing_entity->get($field_name); - $build = $items->view(array('type' => $formatter)); + $build = $this->buildRenderArray([$this->referencedEntity, $this->unsavedReferencedEntity], $formatter); - $expected_rendered_name_field = '<div class="field field-entity-test--name field-name-name field-type-string field-label-hidden"> + // Test the first field item. + $expected_rendered_name_field_1 = '<div class="field field-entity-test--name field-name-name field-type-string field-label-hidden"> <div class="field-items"> <div class="field-item">' . $this->referencedEntity->label() . '</div> </div> </div> '; - $expected_rendered_body_field = '<div class="field field-entity-test--body field-name-body field-type-text field-label-above"> + $expected_rendered_body_field_1 = '<div class="field field-entity-test--body field-name-body field-type-text field-label-above"> <div class="field-label">Body</div> <div class="field-items"> <div class="field-item"><p>Hello, world!</p></div> @@ -178,13 +179,84 @@ public function testEntityFormatter() { </div> '; drupal_render($build[0]); - $this->assertEqual($build[0]['#markup'], 'default | ' . $this->referencedEntity->label() . $expected_rendered_name_field . $expected_rendered_body_field, format_string('The markup returned by the @formatter formatter is correct.', array('@formatter' => $formatter))); + $this->assertEqual($build[0]['#markup'], 'default | ' . $this->referencedEntity->label() . $expected_rendered_name_field_1 . $expected_rendered_body_field_1, sprintf('The markup returned by the %s formatter is correct for an item with a saved entity.', $formatter)); $expected_cache_tags = Cache::mergeTags( \Drupal::entityManager()->getViewBuilder($this->entityType)->getCacheTags(), $this->referencedEntity->getCacheTags(), FilterFormat::load('full_html')->getCacheTags() ); $this->assertEqual($build[0]['#cache']['tags'], $expected_cache_tags, format_string('The @formatter formatter has the expected cache tags.', array('@formatter' => $formatter))); + + // Test the second field item. + drupal_render($build[1]); + $this->assertEqual($build[1]['#markup'], $this->unsavedReferencedEntity->label(), sprintf('The markup returned by the %s formatter is correct for an item with a unsaved entity.', $formatter)); + } + + /** + * Tests the label formatter. + */ + public function testLabelFormatter() { + $formatter = 'entity_reference_label'; + + // The 'link' settings is TRUE by default. + $build = $this->buildRenderArray([$this->referencedEntity, $this->unsavedReferencedEntity], $formatter); + + $expected_item_1 = array( + '#type' => 'link', + '#title' => $this->referencedEntity->label(), + '#url' => $this->referencedEntity->urlInfo(), + '#options' => $this->referencedEntity->urlInfo()->getOptions(), + '#cache' => array( + 'tags' => $this->referencedEntity->getCacheTags(), + ), + ); + $this->assertEqual(drupal_render($build[0]), drupal_render($expected_item_1), sprintf('The markup returned by the %s formatter is correct for an item with a saved entity.', $formatter)); + + // The second referenced entity is "autocreated", therefore not saved and + // lacking any URL info. + $expected_item_2 = array( + '#markup' => $this->unsavedReferencedEntity->label(), + '#cache' => array( + 'tags' => $this->unsavedReferencedEntity->getCacheTags(), + ), + ); + $this->assertEqual($build[1], $expected_item_2, sprintf('The markup returned by the %s formatter is correct for an item with a unsaved entity.', $formatter)); + + // Test with the 'link' setting set to FALSE. + $build = $this->buildRenderArray([$this->referencedEntity, $this->unsavedReferencedEntity], $formatter, array('link' => FALSE)); + $this->assertEqual($build[0]['#markup'], $this->referencedEntity->label(), sprintf('The markup returned by the %s formatter is correct for an item with a saved entity.', $formatter)); + $this->assertEqual($build[1]['#markup'], $this->unsavedReferencedEntity->label(), sprintf('The markup returned by the %s formatter is correct for an item with a unsaved entity.', $formatter)); + } + + /** + * Sets field values and returns a render array as built by + * \Drupal\Core\Field\FieldItemListInterface::view(). + * + * @param \Drupal\Core\Entity\EntityInterface[] $referenced_entities + * An array of entity objects that will be referenced. + * @param string $formatter + * The formatted plugin that will be used for building the render array. + * @param array $formatter_options + * Settings specific to the formatter. Defaults to the formatter's default + * settings. + * + * @return array + * A render array. + */ + protected function buildRenderArray(array $referenced_entities, $formatter, $formatter_options = array()) { + // Create the entity that will have the entity reference field. + $referencing_entity = entity_create($this->entityType, array('name' => $this->randomMachineName())); + + $delta = 0; + foreach ($referenced_entities as $referenced_entity) { + $referencing_entity->{$this->fieldName}[$delta]->entity = $referenced_entity; + $referencing_entity->{$this->fieldName}[$delta++]->access = TRUE; + } + + // Build the renderable array for the entity reference field. + $items = $referencing_entity->get($this->fieldName); + + return $items->view(array('type' => $formatter, 'settings' => $formatter_options)); } } diff --git a/core/modules/entity_reference/src/Tests/EntityReferenceIntegrationTest.php b/core/modules/entity_reference/src/Tests/EntityReferenceIntegrationTest.php index 69f903133857ed2e2dd1c8e93da41216816ea8d6..6c5f8fcc43be5d410b9cb63d88c31ce113fe8d0a 100644 --- a/core/modules/entity_reference/src/Tests/EntityReferenceIntegrationTest.php +++ b/core/modules/entity_reference/src/Tests/EntityReferenceIntegrationTest.php @@ -85,7 +85,11 @@ public function testSupportedEntityTypesAndWidgets() { // Try to post the form again with no modification and check if the field // values remain the same. $entity = current(entity_load_multiple_by_properties($this->entityType, array('name' => $entity_name))); - $this->drupalPostForm($this->entityType . '/manage/' . $entity->id(), array(), t('Save')); + $this->drupalGet($this->entityType . '/manage/' . $entity->id()); + $this->assertFieldByName($this->fieldName . '[0][target_id]', $referenced_entities[0]->label() . ' (' . $referenced_entities[0]->id() . ')'); + $this->assertFieldByName($this->fieldName . '[1][target_id]', $referenced_entities[1]->label() . ' (' . $referenced_entities[1]->id() . ')'); + + $this->drupalPostForm(NULL, array(), t('Save')); $this->assertFieldValues($entity_name, $referenced_entities); // Test the 'entity_reference_autocomplete_tags' widget. @@ -107,7 +111,10 @@ public function testSupportedEntityTypesAndWidgets() { // Try to post the form again with no modification and check if the field // values remain the same. $entity = current(entity_load_multiple_by_properties($this->entityType, array('name' => $entity_name))); - $this->drupalPostForm($this->entityType . '/manage/' . $entity->id(), array(), t('Save')); + $this->drupalGet($this->entityType . '/manage/' . $entity->id()); + $this->assertFieldByName($this->fieldName . '[target_id]', $target_id . ' (' . $referenced_entities[1]->id() . ')'); + + $this->drupalPostForm(NULL, array(), t('Save')); $this->assertFieldValues($entity_name, $referenced_entities); // Test all the other widgets supported by the entity reference field. diff --git a/core/modules/taxonomy/src/Plugin/Field/FieldFormatter/TaxonomyFormatterBase.php b/core/modules/taxonomy/src/Plugin/Field/FieldFormatter/TaxonomyFormatterBase.php index 3c140cc6a465812325879ac5978195f8c409dcac..610967439f2c01a1839e5b20d4e967589d3ba3a2 100644 --- a/core/modules/taxonomy/src/Plugin/Field/FieldFormatter/TaxonomyFormatterBase.php +++ b/core/modules/taxonomy/src/Plugin/Field/FieldFormatter/TaxonomyFormatterBase.php @@ -37,7 +37,9 @@ public function prepareView(array $entities_items) { $term = $translated_term; } } - $terms[$term->id()] = $term; + if (!$term->isNew()) { + $terms[$term->id()] = $term; + } } } if ($terms) { @@ -53,7 +55,7 @@ public function prepareView(array $entities_items) { $item->entity = $terms[$item->target_id]; } // Terms to be created are not in $terms, but are still legitimate. - elseif ($item->hasUnsavedEntity()) { + elseif ($item->hasNewEntity()) { // Leave the item in place. } // Otherwise, unset the instance value, since the term does not exist.