You are here

protected function ContentEntityCdfNormalizer::addFieldsToContentHubEntity in Acquia Content Hub 8

Get fields from given entity.

Get the fields from a given entity and add them to the given content hub entity object.

Parameters

\Acquia\ContentHubClient\Entity $contenthub_entity: The Content Hub Entity that will contain all the Drupal entity fields.

\Drupal\Core\Entity\ContentEntityInterface $entity: The Drupal Entity.

string $langcode: The language that we are parsing.

array $context: Additional Context such as the account.

Return value

\Acquia\ContentHubClient\Entity The Content Hub Entity with all the data in it.

Throws

\Drupal\acquia_contenthub\ContentHubException The Exception will be thrown if something is going awol.

1 call to ContentEntityCdfNormalizer::addFieldsToContentHubEntity()
ContentEntityCdfNormalizer::normalize in src/Normalizer/ContentEntityCdfNormalizer.php
Normalizes an object into a set of arrays/scalars.

File

src/Normalizer/ContentEntityCdfNormalizer.php, line 398

Class

ContentEntityCdfNormalizer
Converts the Drupal entity object to a Acquia Content Hub CDF array.

Namespace

Drupal\acquia_contenthub\Normalizer

Code

protected function addFieldsToContentHubEntity(ContentHubEntity $contenthub_entity, ContentEntityInterface $entity, $langcode = 'und', array $context = []) {

  /** @var \Drupal\Core\Field\FieldItemListInterface[] $fields */
  $fields = $entity
    ->getFields();

  // Get our field mapping. This maps drupal field types to Content Hub
  // attribute types.
  $type_mapping = $this
    ->getFieldTypeMapping($entity);

  // Ignore the entity ID and revision ID.
  // Excluded comes here.
  $excluded_fields = $this
    ->excludedProperties($entity);
  foreach ($fields as $name => $field) {

    // Continue if this is an excluded field or the current user does not
    // have access to view it.
    if (in_array($field
      ->getFieldDefinition()
      ->getName(), $excluded_fields) || !$field
      ->access('view', $context['account'])) {
      continue;
    }

    // Get the plain version of the field in regular json.
    if ($name === 'metatag') {
      $serialized_field = $this
        ->getSerializer()
        ->normalize($field, 'json', $context);
    }
    else {
      $serialized_field = $field
        ->getValue();
    }
    $items = $serialized_field;

    // Given that vocabularies are configuration entities, they are not
    // supported in Content Hub. Instead we use the vocabulary machine name
    // as mechanism to syndicate and import them in the right vocabulary.
    if ($name === 'vid' && $entity
      ->getEntityTypeId() === 'taxonomy_term') {

      // Initialize vocabulary attribute if it doesn't exist yet.
      if (!$contenthub_entity
        ->getAttribute('vocabulary')) {
        $attribute = new Attribute(Attribute::TYPE_STRING);
        $attribute
          ->setValue($items[0]['target_id'], $langcode);
        $contenthub_entity
          ->setAttribute('vocabulary', $attribute);
      }
      else {
        $contenthub_entity
          ->setAttributeValue('vocabulary', $items[0]['target_id'], $langcode);
      }
      continue;
    }
    if ($entity
      ->get($name)
      ->getFieldDefinition()
      ->getType() === 'path' && version_compare(\Drupal::VERSION, '8.8.0', '>=')) {
      $storage = $this->entityTypeManager
        ->getStorage('path_alias');
      $aliases = $storage
        ->loadByProperties([
        'path' => "/{$entity->toUrl()->getInternalPath()}",
      ]);
      if ($aliases) {
        $alias_uuid_attribute = new Attribute(Attribute::TYPE_ARRAY_REFERENCE);
        $uuids = [];
        foreach ($aliases as $alias) {
          $uuids[$alias
            ->language()
            ->getId()][] = $alias
            ->uuid();
        }
        foreach ($uuids as $uuid_langcode => $values) {
          $alias_uuid_attribute
            ->setValue($values, $uuid_langcode);
        }
        $contenthub_entity
          ->setAttribute('path_uuid', $alias_uuid_attribute);
      }
    }

    // For path-aliases adding a UUID of the target entity.

    /** @var \Drupal\path_alias\Entity\PathAlias $entity */
    if ($name === 'path' && $entity
      ->getEntityTypeId() === 'path_alias') {

      // Extracting entities from route.
      $route_params = Url::fromUserInput($entity
        ->getPath())
        ->getRouteParameters();
      $target_entity_uuid_attribute = new Attribute(Attribute::TYPE_ARRAY_REFERENCE);
      $target_entity_type_attribute = new Attribute(Attribute::TYPE_STRING);
      foreach ($route_params as $entity_type_id => $entity_id) {
        if (!$this->entityTypeManager
          ->hasDefinition($entity_type_id)) {

          // Skip in case of unknown entity type.
          continue;
        }
        $entity_from_route = $this->entityTypeManager
          ->getStorage($entity_type_id)
          ->load($entity_id);
        if ($entity
          ->getPath() !== "/{$entity_from_route->toUrl()->getInternalPath()}") {

          // Skip mismatched entities.
          continue;
        }
        $target_entity_uuid_attribute
          ->setValue([
          $entity_from_route
            ->uuid(),
        ], $langcode);
        $target_entity_type_attribute
          ->setValue($entity_type_id, $langcode);
      }
      $contenthub_entity
        ->setAttribute('title', (new Attribute(Attribute::TYPE_STRING))
        ->setValue($entity
        ->getAlias(), $langcode));
      $contenthub_entity
        ->setAttribute('path_uuid', $target_entity_uuid_attribute);
      $contenthub_entity
        ->setAttribute('target_entity_type', $target_entity_type_attribute);
    }

    // To make it work with Paragraphs, we are converting the field
    // 'parent_id' to 'parent_uuid' because Content Hub cannot deal with
    // entity_id information.
    if ($name === 'parent_id' && $entity
      ->getEntityTypeId() === 'paragraph') {
      $attribute = new Attribute(Attribute::TYPE_STRING);
      $parent_id = $items[0]['value'];
      $parent_type = $fields['parent_type']
        ->getValue()[0]['value'];
      $parent = $this->entityTypeManager
        ->getStorage($parent_type)
        ->load($parent_id);
      $parent_uuid = $parent
        ->uuid();
      $attribute
        ->setValue($parent_uuid, $langcode);
      $contenthub_entity
        ->setAttribute('parent_uuid', $attribute);
      continue;
    }
    if ($name == 'bundle' && $entity
      ->getEntityTypeId() === 'media') {
      $attribute = new Attribute(Attribute::TYPE_ARRAY_STRING);
      $attribute
        ->setValue([
        $entity
          ->bundle(),
      ], $langcode);
      $contenthub_entity
        ->setAttribute('bundle', $attribute);
      continue;
    }

    // Try to map it to a known field type.
    $field_type = $field
      ->getFieldDefinition()
      ->getType();

    // Go to the fallback data type when the field type is not known.
    $type = $type_mapping['fallback'];
    if (isset($type_mapping[$name])) {
      $type = $type_mapping[$name];
    }
    elseif (isset($type_mapping[$field_type])) {

      // Set it to the fallback type which is string.
      $type = $type_mapping[$field_type];
    }
    if ($type == NULL) {
      continue;
    }
    $values = [];
    if ($field instanceof EntityReferenceFieldItemListInterface) {

      // Get taxonomy parent terms.
      if ($name === 'parent' && $entity
        ->getEntityTypeId() === 'taxonomy_term') {
        $storage = $this->entityTypeManager
          ->getStorage('taxonomy_term');
        $referenced_entities = $storage
          ->loadParents($entity
          ->id());
      }
      else {

        /** @var \Drupal\Core\Entity\EntityInterface[] $referenced_entities */
        $referenced_entities = $field
          ->referencedEntities();
      }
      $values[$langcode] = [];
      foreach ($referenced_entities as $key => $referenced_entity) {

        // In the case of images/files, etc... we need to add the assets.
        $file_types = [
          'image',
          'file',
          'video',
        ];
        $type_names = [
          'type',
          'bundle',
        ];

        // Special case for type as we do not want the reference for the
        // bundle. In additional to the type field a media entity has a
        // bundle field which stores a media bundle configuration entity UUID.
        if (in_array($name, $type_names, TRUE) && $referenced_entity instanceof ConfigEntityBase) {
          $values[$langcode][] = $referenced_entity
            ->id();
        }
        elseif (in_array($field_type, $file_types)) {

          // If this is a file type, then add the asset to the CDF.
          $uuid_token = '[' . $referenced_entity
            ->uuid() . ']';
          $asset_url = file_create_url($referenced_entity
            ->getFileUri());
          $asset = new Asset();
          $asset
            ->setUrl($asset_url);
          $asset
            ->setReplaceToken($uuid_token);
          $contenthub_entity
            ->addAsset($asset);

          // Now add the value.
          // Notice that we are including the "alt" and "title" attributes
          // from the file entity in the field data.
          $data = [
            'alt' => isset($items[$key]['alt']) ? $items[$key]['alt'] : '',
            'title' => isset($items[$key]['title']) ? $items[$key]['title'] : '',
            'target_uuid' => $uuid_token,
          ];
          $values[$langcode][] = json_encode($data, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT);
        }
        else {
          $values[$langcode][] = $referenced_entity
            ->uuid();
        }
      }
    }
    else {

      // If there's nothing in this field, just set it to NULL.
      if ($items == NULL) {
        $values[$langcode] = NULL;
      }
      else {

        // Only if it is a link type.
        if ($link_field = ContentHubEntityLinkFieldHandler::load($field)
          ->validate()) {
          $items = $link_field
            ->normalizeItems($items);
        }

        // Loop over the items to get the values for each field.
        foreach ($items as $item) {

          // Hotfix.
          // @todo Find a better solution for this.
          if (isset($item['_attributes'])) {
            unset($item['_attributes']);
          }
          $keys = is_array($item) ? array_keys($item) : [];
          if (count($keys) == 1 && isset($item['value'])) {
            $value = $item['value'];
          }
          else {
            if ($field instanceof PathFieldItemList) {
              $item = $field
                ->first()
                ->getValue();
              $item['pid'] = "";
              $item['source'] = "";
            }
            $value = json_encode($item, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT);
          }
          $values[$langcode][] = $value;
        }
      }
    }
    try {
      $attribute = new Attribute($type);
    } catch (\Exception $e) {
      $args['%type'] = $type;
      $message = new FormattableMarkup('No type could be registered for %type.', $args);
      throw new ContentHubException($message);
    }
    if (strstr($type, 'array')) {
      $attribute
        ->setValues($values);
    }
    else {
      $value = array_pop($values[$langcode]);
      $attribute
        ->setValue($value, $langcode);
    }

    // If attribute exists already, append to the existing values.
    if (!empty($contenthub_entity
      ->getAttribute($name))) {
      $existing_attribute = $contenthub_entity
        ->getAttribute($name);
      $this
        ->appendToAttribute($existing_attribute, $attribute
        ->getValues());
      $attribute = $existing_attribute;
    }

    // Add it to our contenthub entity.
    $contenthub_entity
      ->setAttribute($name, $attribute);
  }

  // Allow alterations of the CDF to happen.
  $context['entity'] = $entity;
  $context['langcode'] = $langcode;
  $this->moduleHandler
    ->alter('acquia_contenthub_cdf', $contenthub_entity, $context);

  // Adds the entity URL to CDF.
  $value = NULL;
  if (empty($contenthub_entity
    ->getAttribute('url'))) {
    switch ($entity
      ->getEntityTypeId()) {
      case 'file':
        $value = file_create_url($entity
          ->getFileUri());
        $filepath_attribute = new Attribute(Attribute::TYPE_STRING);
        $contenthub_entity
          ->setAttribute('_filepath', $filepath_attribute
          ->setValue($entity
          ->getFileUri()));
        break;
      default:

        // Get entity URL.
        if (!$entity
          ->isNew() && $entity
          ->hasLinkTemplate('canonical')) {
          $url = $entity
            ->toUrl();
          $url
            ->setAbsolute(TRUE);
          $value = $url
            ->toString();
        }
        break;
    }
    if (isset($value)) {
      $url_attribute = new Attribute(Attribute::TYPE_STRING);
      $contenthub_entity
        ->setAttribute('url', $url_attribute
        ->setValue($value, $langcode));
    }
  }
  return $contenthub_entity;
}