You are here

private function ContentEntityNormalizer::denormalizeTranslation in Replication 8

Same name and namespace in other branches
  1. 8.2 src/Normalizer/ContentEntityNormalizer.php \Drupal\replication\Normalizer\ContentEntityNormalizer::denormalizeTranslation()

Parameters

$translation:

int $entity_id:

\string $entity_uuid:

string $entity_type_id:

$bundle_key:

$entity_type:

$id_key:

$context:

$rev:

array $revisions:

Return value

mixed

1 call to ContentEntityNormalizer::denormalizeTranslation()
ContentEntityNormalizer::denormalize in src/Normalizer/ContentEntityNormalizer.php
Denormalizes data back into an object of the given class.

File

src/Normalizer/ContentEntityNormalizer.php, line 321

Class

ContentEntityNormalizer

Namespace

Drupal\replication\Normalizer

Code

private function denormalizeTranslation($translation, $entity_id, $entity_uuid, $entity_type_id, $bundle_key, $entity_type, $id_key, $context, $rev = null, array $revisions = []) {

  // Add the _rev field to the $translation array.
  if (isset($rev)) {
    $translation['_rev'] = [
      [
        'value' => $rev,
      ],
    ];
  }
  if (isset($revisions['start']) && isset($revisions['ids'])) {
    $translation['_rev'][0]['revisions'] = $revisions['ids'];
  }
  if (isset($entity_uuid)) {
    $translation['uuid'][0]['value'] = $entity_uuid;
  }

  // We need to nest the data for the _deleted field in its Drupal-specific
  // structure since it's un-nested to follow the API spec when normalized.
  // @todo {@link https://www.drupal.org/node/2599938 Needs test for situation when a replication overwrites delete.}
  $deleted = isset($translation['_deleted']) ? $translation['_deleted'] : FALSE;
  $translation['_deleted'] = [
    [
      'value' => $deleted,
    ],
  ];
  if ($entity_id) {

    // @todo {@link https://www.drupal.org/node/2599938 Needs test.}
    $translation[$id_key] = [
      'value' => $entity_id,
    ];
  }
  $bundle_id = $entity_type_id;
  if ($entity_type
    ->hasKey('bundle')) {
    if (!empty($translation[$bundle_key][0]['value'])) {

      // Add bundle info when entity is not new.
      $bundle_id = $translation[$bundle_key][0]['value'];
      $translation[$bundle_key] = $bundle_id;
    }
    elseif (!empty($translation[$bundle_key][0]['target_id'])) {

      // Add bundle info when entity is new.
      $bundle_id = $translation[$bundle_key][0]['target_id'];
      $translation[$bundle_key] = $bundle_id;
    }
  }

  // Denormalize entity reference fields.
  foreach ($translation as $field_name => $field_info) {
    if (!is_array($field_info)) {
      continue;
    }
    foreach ($field_info as $delta => $item) {
      if (!is_array($item)) {
        continue;
      }
      if (isset($item['target_uuid'])) {
        $translation[$field_name][$delta] = $item;
        $fields = $this->entityManager
          ->getFieldDefinitions($entity_type_id, $bundle_id);

        // Figure out what bundle we should use when creating the stub.
        $settings = $fields[$field_name]
          ->getSettings();

        // Find the target entity type and target bundle IDs and figure out if
        // the referenced entity exists or not.
        $target_entity_uuid = $item['target_uuid'];

        // Denormalize link field type as an entity reference field if it
        // has info about 'target_uuid' and 'entity_type_id'. These are used
        // to denormalize 'uri' in formats like 'entity:ENTITY_TYPE/ID'.
        $type = $fields[$field_name]
          ->getType();
        if ($type == 'link' && isset($item['entity_type_id'])) {
          $target_entity_type_id = $item['entity_type_id'];
        }
        else {
          $target_entity_type_id = $settings['target_type'];
        }
        if ($target_entity_type_id === 'user') {
          $translation[$field_name] = $this->usersMapping
            ->mapReferenceField($translation, $field_name);
          continue;
        }
        if (isset($settings['handler_settings']['target_bundles'])) {
          $target_bundle_id = reset($settings['handler_settings']['target_bundles']);
        }
        else {

          // @todo: Update when {@link https://www.drupal.org/node/2412569
          // this setting is configurable}.
          $bundles = $this->entityManager
            ->getBundleInfo($target_entity_type_id);
          $target_bundle_id = key($bundles);
        }
        $target_entity = null;
        $uuid_index = isset($context['workspace']) && $context['workspace'] instanceof WorkspaceInterface ? $this->indexFactory
          ->get('multiversion.entity_index.uuid', $context['workspace']) : $this->indexFactory
          ->get('multiversion.entity_index.uuid');
        if ($target_entity_info = $uuid_index
          ->get($target_entity_uuid)) {
          $target_entity = $this->entityManager
            ->getStorage($target_entity_info['entity_type_id'])
            ->load($target_entity_info['entity_id']);
        }

        // Try to get real bundle.
        if (!empty($item['entity_type_id'])) {
          $bundle_key = $this->entityManager
            ->getStorage($item['entity_type_id'])
            ->getEntityType()
            ->getKey('bundle');
          if (!empty($item[$bundle_key])) {
            $target_bundle_id = $item[$bundle_key];
          }
        }

        // This set the correct uri for link field if the target entity
        // already exists.
        if ($type == 'link' && $target_entity) {
          $id = $target_entity
            ->id();
          $translation[$field_name][$delta]['uri'] = "entity:{$target_entity_type_id}/{$id}";
        }
        elseif ($target_entity) {
          $translation[$field_name][$delta]['target_id'] = $target_entity
            ->id();

          // Special handling for Entity Reference Revisions, it needs the
          // revision ID in addition to the primary entity ID.
          if ($type === 'entity_reference_revisions') {
            $revision_key = $target_entity
              ->getEntityType()
              ->getKey('revision');
            $translation[$field_name][$delta]['target_revision_id'] = $target_entity->{$revision_key}->value;
          }
        }
        else {
          $options['target_type'] = $target_entity_type_id;
          if (isset($settings['handler_settings'])) {
            $options['handler_settings'] = $settings['handler_settings'];
          }

          /** @var \Drupal\Core\Entity\EntityReferenceSelection\SelectionWithAutocreateInterface $selection_instance */
          $selection_instance = $this->selectionManager
            ->getInstance($options);

          // We use a temporary label and entity owner ID as this will be
          // backfilled later anyhow, when the real entity comes around.
          $target_entity = $selection_instance
            ->createNewEntity($target_entity_type_id, $target_bundle_id, rand(), 1);
          if (is_subclass_of($target_entity
            ->getEntityType()
            ->getStorageClass(), ContentEntityStorageInterface::class)) {

            // Set the target workspace if we have it in context.
            if (isset($context['workspace']) && $context['workspace'] instanceof WorkspaceInterface && $target_entity
              ->getEntityType()
              ->get('workspace') !== FALSE) {
              $target_entity->workspace->target_id = $context['workspace']
                ->id();
            }

            // Set the UUID to what we received to ensure it gets updated when
            // the full entity comes around later.
            $target_entity->uuid->value = $target_entity_uuid;

            // Indicate that this revision is a stub.
            $target_entity->_rev->is_stub = TRUE;
            $target_entity->langcode->value = $context['language'];

            // Populate uri and filename fields if we have the info for them
            // in the field item.
            if ($target_entity instanceof FileInterface) {
              if (isset($item['uri'])) {
                $target_entity
                  ->setFileUri($item['uri']);
              }
              if (isset($item['filename'])) {
                $target_entity
                  ->setFilename($item['filename']);
              }
              if (isset($item['filesize'])) {
                $target_entity
                  ->setSize($item['filesize']);
              }
              if (isset($item['filemime'])) {
                $target_entity
                  ->setMimeType($item['filemime']);
              }
            }

            // This will ensure that stub poll_choice entities will not be saved
            // in Drupal\poll\Entity\Poll:preSave()
            if ($target_entity_type_id === 'poll_choice') {
              $target_entity
                ->needsSaving(FALSE);
            }

            // Populate the data field.
            $translation[$field_name][$delta]['target_id'] = NULL;
            $translation[$field_name][$delta]['entity'] = $target_entity;
          }
        }
        if (isset($translation[$field_name][$delta]['entity_type_id'])) {
          unset($translation[$field_name][$delta]['entity_type_id']);
        }
        if (isset($translation[$field_name][$delta]['target_uuid'])) {
          unset($translation[$field_name][$delta]['target_uuid']);
        }
      }
    }
  }

  // Denormalize parent field for menu_link_content entity type.
  if ($entity_type_id == 'menu_link_content' && !empty($translation['parent'][0]['value'])) {
    $translation['parent'][0]['value'] = $this
      ->denormalizeMenuLinkParent($translation['parent'][0]['value'], $context, $translation['@context']['@language']);
  }

  // Unset the comment field item if CID is NULL.
  if (!empty($translation['comment']) && is_array($translation['comment'])) {
    foreach ($translation['comment'] as $delta => $item) {
      if (empty($item['cid'])) {
        unset($translation['comment'][$delta]);
      }
    }
  }

  // Exclude "name" field (the user name) for comment entity type because
  // we'll change it during replication if it's a duplicate.
  if ($entity_type_id == 'comment' && isset($translation['name'])) {
    unset($translation['name']);
  }

  // Clean-up attributes we don't needs anymore.
  // Remove changed info, otherwise we can get validation errors when the
  // 'changed' value for existing entity is higher than for the new entity (revision).
  // @see \Drupal\Core\Entity\Plugin\Validation\Constraint\EntityChangedConstraintValidator::validate().
  foreach ([
    '@context',
    '@type',
    '_id',
    '_revisions',
    'changed',
  ] as $key) {
    if (isset($translation[$key])) {
      unset($translation[$key]);
    }
  }
  return $translation;
}