Clone entity data into existing entities in Drupal 8

30 Mar 2018

Creating a duplicate of an entity

Creating a duplicate of an entity is easily done via the entity API method Entity::createDuplicate(). This is a convenient method if the goal is to clone an entity into a new entity, as all identifiers of the previous entity get unset when using this method.

  1. $nid = 5;
  2. $entity = \Drupal::service('entity_type.manager')->getStorage('node')->load($nid); // Use dependency injection instead if in class context.
  3. $duplicate = $entity->createDuplicate();
  4. $duplicate->save();

Cloning data into an existing entity

However partially or fully cloning data into an existing entity is less straight forward (and rightfully so). Still, the ability to do so can be useful

  • in custom migration scripts where we want to overwrite old entities without creating new ones,
  • in cases where we need to overwrite the old entity as other internal or external data may reference it and creating a new entity would break these references.

The second case could be an entity reference field referencing the old entity in question (this could be technically solved by reassigning the reference), but it could also be 3rd party software referencing the old entity, which would complicate things.

This article is going to demonstrate a couple of possible ways of cloning entity data into existing entities.

Cloning field data 1:1

  1. $source_nid = 5;
  2. $destination_nid = 6;
  3.  
  4. // Use dependency injection in class context instead.
  5. $source = \Drupal::service('entity_type.manager')->getStorage('node')->load($source_nid);
  6. $destination = \Drupal::service('entity_type.manager')->getStorage('node')->load($destination_nid);
  7.  
  8. foreach ($source->getFields() as $name => $field) {
  9. $destination->set($name, $field->getValue());
  10. }
  11. $destination->save();

Importing new data only

To import new field data without overwriting existing data, just check if the destination field is empty before cloning into it like so:

  1. foreach ($source->getFields() as $name => $field) {
  2. if ($destination->get($name)->isEmpty()) {
  3. $destination->set($name, $field->getValue());
  4. }
  5. }

Putting it all together

A nifty method that could be used to clone field data of entities into other existing entitites could look like this:

  1. /**
  2.  * @param \Drupal\Core\Entity\Entity $source
  3.  * @param \Drupal\Core\Entity\Entity $destination
  4.  * @param string $mode
  5.  * Can be 'keep', 'overwrite' and 'clone'.
  6.  * @param array $skip_fields
  7.  * An array of fields not to be cloned into the destination entity.
  8.  */
  9. public function cloneFields(Entity $source, Entity &$destination, $mode, $skip_fields = []) {
  10. foreach ($source->getFields() as $name => $field) {
  11.  
  12. // In this case clone only fields and leave out properties like title.
  13. if (strpos($name, 'field') === 0
  14.  
  15. // Leave out certain fields.
  16. && !in_array($name, $skip_fields)) {
  17.  
  18. switch ($mode) {
  19.  
  20. // Import only those fields from source that are empty in destination.
  21. case 'keep':
  22. default:
  23. if (!$destination->get($name)->isEmpty()) {
  24. continue 2;
  25. }
  26. break;
  27.  
  28. // Import field data from source overwriting all destination fields.
  29. // Do not empty fields in destination if they are empty in source.
  30. case 'overwrite':
  31. if ($source->get($name)->isEmpty()) {
  32. continue 2;
  33. }
  34. break;
  35.  
  36. // Import field data from source overwriting all destination fields.
  37. // Empty fields in destination if they are empty in source.
  38. case 'clone':
  39. break;
  40. }
  41. $destination->set($name, $field->getValue());
  42. }
  43. }
  44. $destination->save();
  45. }

There you go. Make sure to comment below in case of questions or if you know a better way of doing the above.

Leave a comment

Leaving new comments is temporarily disabled. Please leave your comments and ask questions via the contact page.

Get a quote in 24 hours

Wether a huge commerce system, or a small business website, we will quote the project within 24h of you pressing the following button: Get quote