You are here

public function ContentEntityBase::__clone in Drupal 9

Same name and namespace in other branches
  1. 8 core/lib/Drupal/Core/Entity/ContentEntityBase.php \Drupal\Core\Entity\ContentEntityBase::__clone()

Magic method: Implements a deep clone.

File

core/lib/Drupal/Core/Entity/ContentEntityBase.php, line 1160

Class

ContentEntityBase
Implements Entity Field API specific enhancements to the Entity class.

Namespace

Drupal\Core\Entity

Code

public function __clone() {

  // Avoid deep-cloning when we are initializing a translation object, since
  // it will represent the same entity, only with a different active language.
  if ($this->translationInitialize) {
    return;
  }

  // The translation is a different object, and needs its own TypedData
  // adapter object.
  $this->typedData = NULL;
  $definitions = $this
    ->getFieldDefinitions();

  // The translation cache has to be cleared before cloning the fields
  // below so that the call to getTranslation() does not re-use the
  // translation objects of the old entity but instead creates new
  // translation objects from the newly cloned entity. Otherwise the newly
  // cloned field item lists would hold references to the old translation
  // objects in their $parent property after the call to setContext().
  $this
    ->clearTranslationCache();

  // Because the new translation objects that are created below are
  // themselves created by *cloning* the newly cloned entity we need to
  // make sure that the references to property values are properly cloned
  // before cloning the fields. Otherwise calling
  // $items->getEntity()->isNew(), for example, would return the
  // $enforceIsNew value of the old entity.
  // Ensure the translations array is actually cloned by overwriting the
  // original reference with one pointing to a copy of the array.
  $translations = $this->translations;
  $this->translations =& $translations;

  // Ensure that the following properties are actually cloned by
  // overwriting the original references with ones pointing to copies of
  // them: enforceIsNew, newRevision, loadedRevisionId, fields, entityKeys,
  // translatableEntityKeys, values, isDefaultRevision and
  // enforceRevisionTranslationAffected.
  $enforce_is_new = $this->enforceIsNew;
  $this->enforceIsNew =& $enforce_is_new;
  $new_revision = $this->newRevision;
  $this->newRevision =& $new_revision;
  $original_revision_id = $this->loadedRevisionId;
  $this->loadedRevisionId =& $original_revision_id;
  $fields = $this->fields;
  $this->fields =& $fields;
  $entity_keys = $this->entityKeys;
  $this->entityKeys =& $entity_keys;
  $translatable_entity_keys = $this->translatableEntityKeys;
  $this->translatableEntityKeys =& $translatable_entity_keys;
  $values = $this->values;
  $this->values =& $values;
  $default_revision = $this->isDefaultRevision;
  $this->isDefaultRevision =& $default_revision;
  $is_revision_translation_affected_enforced = $this->enforceRevisionTranslationAffected;
  $this->enforceRevisionTranslationAffected =& $is_revision_translation_affected_enforced;
  $is_syncing = $this->isSyncing;
  $this->isSyncing =& $is_syncing;
  foreach ($this->fields as $name => $fields_by_langcode) {
    $this->fields[$name] = [];

    // Untranslatable fields may have multiple references for the same field
    // object keyed by language. To avoid creating different field objects
    // we retain just the original value, as references will be recreated
    // later as needed.
    if (!$definitions[$name]
      ->isTranslatable() && count($fields_by_langcode) > 1) {
      $fields_by_langcode = array_intersect_key($fields_by_langcode, [
        LanguageInterface::LANGCODE_DEFAULT => TRUE,
      ]);
    }
    foreach ($fields_by_langcode as $langcode => $items) {
      $this->fields[$name][$langcode] = clone $items;
      $this->fields[$name][$langcode]
        ->setContext($name, $this
        ->getTranslation($langcode)
        ->getTypedData());
    }
  }
}