Unverified Commit 89a7f66b authored by alexpott's avatar alexpott

Issue #2966137 by vaplas, tim.plunkett: Circular entity references cause...

Issue #2966137 by vaplas, tim.plunkett: Circular entity references cause infinite loop in EntityReferenceItem::generateSampleValue()
parent 75850cdd
......@@ -272,6 +272,10 @@ public function preSave() {
* {@inheritdoc}
*/
public static function generateSampleValue(FieldDefinitionInterface $field_definition) {
// An associative array keyed by the reference type, target type, and
// bundle.
static $recursion_tracker = [];
$manager = \Drupal::service('plugin.manager.entity_reference_selection');
// Instead of calling $manager->getSelectionHandler($field_definition)
......@@ -300,9 +304,25 @@ public static function generateSampleValue(FieldDefinitionInterface $field_defin
// Attempt to create a sample entity, avoiding recursion.
$entity_storage = \Drupal::entityTypeManager()->getStorage($options['target_type']);
if ($options['target_type'] !== $field_definition->getTargetEntityTypeId() && $entity_storage instanceof ContentEntityStorageInterface) {
if ($entity_storage instanceof ContentEntityStorageInterface) {
$bundle = static::getRandomBundle($entity_type, $options['handler_settings']);
$values['entity'] = $entity_storage->createWithSampleValues($bundle);
// Track the generated entity by reference type, target type, and bundle.
$key = $field_definition->getTargetEntityTypeId() . ':' . $options['target_type'] . ':' . $bundle;
// If entity generation was attempted but did not finish, do not continue.
if (isset($recursion_tracker[$key])) {
return [];
}
// Mark this as an attempt at generation.
$recursion_tracker[$key] = TRUE;
// Mark the sample entity as being a preview.
$values['entity'] = $entity_storage->createWithSampleValues($bundle, ['in_preview' => TRUE]);
// Remove the indicator once the entity is successfully generated.
unset($recursion_tracker[$key]);
return $values;
}
}
......
......@@ -3,6 +3,7 @@
namespace Drupal\Tests\field\Kernel\EntityReference;
use Drupal\comment\Entity\Comment;
use Drupal\comment\Entity\CommentType;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\FieldItemInterface;
......@@ -14,6 +15,7 @@
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\field\Tests\EntityReference\EntityReferenceTestTrait;
use Drupal\node\Entity\NodeType;
use Drupal\node\NodeInterface;
use Drupal\taxonomy\TermInterface;
use Drupal\Tests\field\Kernel\FieldKernelTestBase;
......@@ -89,6 +91,14 @@ protected function setUp() {
]);
$this->term->save();
NodeType::create([
'type' => $this->randomMachineName(),
])->save();
CommentType::create([
'id' => $this->randomMachineName(),
'target_entity_type_id' => 'node',
])->save();
$this->entityStringId = EntityTestStringId::create([
'id' => $this->randomMachineName(),
]);
......@@ -102,6 +112,7 @@ protected function setUp() {
$this->createEntityReferenceField('entity_test', 'entity_test', 'field_test_user', 'Test user entity reference', 'user');
$this->createEntityReferenceField('entity_test', 'entity_test', 'field_test_comment', 'Test comment entity reference', 'comment');
$this->createEntityReferenceField('entity_test', 'entity_test', 'field_test_file', 'Test file entity reference', 'file');
$this->createEntityReferenceField('entity_test_string_id', 'entity_test_string_id', 'field_test_entity_test', 'Test content entity reference with string ID', 'entity_test');
}
/**
......@@ -211,6 +222,19 @@ public function testGenerateSampleValue() {
$this->entityValidateAndSave($entity);
}
/**
* Tests the ::generateSampleValue() method when it has a circular reference.
*/
public function testGenerateSampleValueCircularReference() {
// Delete the existing entity.
$this->entityStringId->delete();
$entity_storage = \Drupal::entityTypeManager()->getStorage('entity_test');
$entity = $entity_storage->createWithSampleValues('entity_test');
$this->assertInstanceOf(EntityTestStringId::class, $entity->field_test_entity_test_string_id->entity);
$this->assertInstanceOf(EntityTest::class, $entity->field_test_entity_test_string_id->entity->field_test_entity_test->entity);
}
/**
* Tests referencing content entities with string IDs.
*/
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment