From fe08d93c26079b76fccb3d37aaa1e995a8b0f866 Mon Sep 17 00:00:00 2001 From: Alex Pott Date: Fri, 24 Jun 2016 15:14:18 +0200 Subject: [PATCH] Issue #2675010 by hchonov: Cloned entity will point to the same field objects if the clone was created after an entity translation has been initialized --- .../Drupal/Core/Entity/ContentEntityBase.php | 6 +++ .../Core/Entity/ContentEntityCloneTest.php | 45 +++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/core/lib/Drupal/Core/Entity/ContentEntityBase.php b/core/lib/Drupal/Core/Entity/ContentEntityBase.php index b5fccbd3694..357db0219fa 100644 --- a/core/lib/Drupal/Core/Entity/ContentEntityBase.php +++ b/core/lib/Drupal/Core/Entity/ContentEntityBase.php @@ -1012,6 +1012,12 @@ abstract class ContentEntityBase extends Entity implements \IteratorAggregate, C // adapter object. $this->typedData = NULL; $definitions = $this->getFieldDefinitions(); + + // Ensure the fields array is actually cloned by overwriting the original + // reference with one pointing to a copy of the array. + $fields = $this->fields; + $this->fields = &$fields; + foreach ($this->fields as $name => $values) { $this->fields[$name] = array(); // Untranslatable fields may have multiple references for the same field diff --git a/core/tests/Drupal/KernelTests/Core/Entity/ContentEntityCloneTest.php b/core/tests/Drupal/KernelTests/Core/Entity/ContentEntityCloneTest.php index 2a05b948fb4..0bacd458c5f 100644 --- a/core/tests/Drupal/KernelTests/Core/Entity/ContentEntityCloneTest.php +++ b/core/tests/Drupal/KernelTests/Core/Entity/ContentEntityCloneTest.php @@ -62,4 +62,49 @@ class ContentEntityCloneTest extends EntityKernelTestBase { } } + /** + * Tests if the entity fields are properly cloned. + */ + public function testClonedEntityFields() { + $user = $this->createUser(); + + // Create a test entity. + $entity = EntityTestMul::create([ + 'name' => $this->randomString(), + 'user_id' => $user->id(), + 'language' => 'en', + ]); + + $entity->addTranslation('de'); + $entity->save(); + $fields = array_keys($entity->getFieldDefinitions()); + + // Reload the entity, clone it and check that both entity objects reference + // different field instances. + $entity = $this->reloadEntity($entity); + $clone = clone $entity; + + $different_references = TRUE; + foreach ($fields as $field_name) { + if ($entity->get($field_name) === $clone->get($field_name)) { + $different_references = FALSE; + } + } + $this->assertTrue($different_references, 'The entity object and the cloned entity object reference different field item list objects.'); + + // Reload the entity, initialize one translation, clone it and check that + // both entity objects reference different field instances. + $entity = $this->reloadEntity($entity); + $entity->getTranslation('de'); + $clone = clone $entity; + + $different_references = TRUE; + foreach ($fields as $field_name) { + if ($entity->get($field_name) === $clone->get($field_name)) { + $different_references = FALSE; + } + } + $this->assertTrue($different_references, 'The entity object and the cloned entity object reference different field item list objects if the entity is cloned after an entity translation has been initialized.'); + } + }