You are here

class ContentEntityNormalizer in Content Synchronization 8.2

Same name and namespace in other branches
  1. 3.0.x src/Normalizer/ContentEntityNormalizer.php \Drupal\content_sync\Normalizer\ContentEntityNormalizer

Adds the file URI to embedded file entities.

Hierarchy

Expanded class hierarchy of ContentEntityNormalizer

1 string reference to 'ContentEntityNormalizer'
content_sync.services.yml in ./content_sync.services.yml
content_sync.services.yml
1 service uses ContentEntityNormalizer
content_sync.normalizer.content_entity in ./content_sync.services.yml
Drupal\content_sync\Normalizer\ContentEntityNormalizer

File

src/Normalizer/ContentEntityNormalizer.php, line 22

Namespace

Drupal\content_sync\Normalizer
View source
class ContentEntityNormalizer extends BaseContentEntityNormalizer {
  use SyncNormalizerDecoratorTrait;

  /**
   * @var SyncNormalizerDecoratorManager
   */
  protected $decoratorManager;

  /**
   * The entity bundle info.
   *
   * @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
   */
  protected $entityTypeBundleInfo;

  /**
   * The entity repository.
   *
   * @var \Drupal\Core\Entity\EntityRepositoryInterface
   */
  protected $entityRepository;

  /**
   * Constructs an EntityNormalizer object.
   *
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   * @param \Drupal\Core\Entity\EntityTypeRepositoryInterface $entity_type_repository
   *   The entity type repository.
   * @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager
   *   The entity field manager.
   * @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_type_bundle_info
   *   The entity bundle info.
   * @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository
   *   The entity repository.
   * @param SyncNormalizerDecoratorManager $decorator_manager
   */
  public function __construct(EntityTypeManagerInterface $entity_type_manager, EntityTypeRepositoryInterface $entity_type_repository, EntityFieldManagerInterface $entity_field_manager, EntityTypeBundleInfoInterface $entity_type_bundle_info, EntityRepositoryInterface $entity_repository, SyncNormalizerDecoratorManager $decorator_manager) {
    parent::__construct($entity_type_manager, $entity_type_repository, $entity_field_manager);
    $this->decoratorManager = $decorator_manager;
    $this->entityRepository = $entity_repository;
    $this->entityTypeBundleInfo = $entity_type_bundle_info;
  }

  /**
   * {@inheritdoc}
   */
  public function denormalize($data, $class, $format = NULL, array $context = []) {
    if (is_null($data)) {
      return NULL;
    }
    $original_data = $data;

    // Get the entity type ID while letting context override the $class param.
    $entity_type_id = !empty($context['entity_type']) ? $context['entity_type'] : $this->entityTypeRepository
      ->getEntityTypeFromClass($class);
    $bundle = FALSE;

    /** @var \Drupal\Core\Entity\EntityTypeInterface $entity_type_definition */

    // Get the entity type definition.
    $entity_type_definition = $this->entityTypeManager
      ->getDefinition($entity_type_id, FALSE);
    if ($entity_type_definition
      ->hasKey('bundle')) {
      $bundle_key = $entity_type_definition
        ->getKey('bundle');

      // Get the base field definitions for this entity type.
      $base_field_definitions = $this->entityFieldManager
        ->getBaseFieldDefinitions($entity_type_id);

      // Get the ID key from the base field definition for the bundle key or
      // default to 'value'.
      $key_id = isset($base_field_definitions[$bundle_key]) ? $base_field_definitions[$bundle_key]
        ->getFieldStorageDefinition()
        ->getMainPropertyName() : 'value';

      // Normalize the bundle if it is not explicitly set.
      $bundle = isset($data[$bundle_key][0][$key_id]) ? $data[$bundle_key][0][$key_id] : (isset($data[$bundle_key]) ? $data[$bundle_key] : NULL);
    }

    // Decorate data before denormalizing it.
    $this
      ->decorateDenormalization($data, $entity_type_id, $format, $context);

    // Resolve references
    $this
      ->fixReferences($data, $entity_type_id, $bundle);

    // Remove invalid fields
    $this
      ->cleanupData($data, $entity_type_id, $bundle);

    // Data to Entity
    $entity = parent::denormalize($data, $class, $format, $context);

    // Decorate denormalized entity before retuning it.
    $this
      ->decorateDenormalizedEntity($entity, $original_data, $format, $context);
    return $entity;
  }

  /**
   * {@inheritdoc}
   */
  public function normalize($object, $format = NULL, array $context = []) {

    /* @var ContentEntityInterface $object */
    $normalized_data = parent::normalize($object, $format, $context);
    $normalized_data['_content_sync'] = $this
      ->getContentSyncMetadata($object, $context);

    /**
     * @var \Drupal\Core\Entity\ContentEntityBase $object
     */
    $referenced_entities = $object
      ->referencedEntities();

    // Add node uuid for menu link if any.
    if ($object
      ->getEntityTypeId() == 'menu_link_content') {
      if ($entity = $this
        ->getMenuLinkNodeAttached($object)) {
        $normalized_data['_content_sync']['menu_entity_link'][$entity
          ->getEntityTypeId()] = $entity
          ->uuid();
        $referenced_entities[] = $entity;
      }
    }
    if (!empty($referenced_entities)) {
      $dependencies = [];
      foreach ($referenced_entities as $entity) {
        $reflection = new \ReflectionClass($entity);
        if ($reflection
          ->implementsInterface(ContentEntityInterface::class)) {
          $ids = [
            $entity
              ->getEntityTypeId(),
            $entity
              ->bundle(),
            $entity
              ->uuid(),
          ];
          $dependency = implode(ContentSyncManager::DELIMITER, $ids);
          if (!$this
            ->inDependencies($dependency, $dependencies)) {
            $dependencies[$entity
              ->getEntityTypeId()][] = $dependency;
          }
        }
      }
      $normalized_data['_content_sync']['entity_dependencies'] = $dependencies;
    }

    // Decorate normalized entity before retuning it.
    if (is_a($object, ContentEntityInterface::class, TRUE)) {
      $this
        ->decorateNormalization($normalized_data, $object, $format, $context);
    }
    return $normalized_data;
  }

  /**
   * Checks if a dependency is in a dependencies nested array.
   *
   * @param string $dependency
   *   An entity identifier.
   * @param $dependencies
   *   A nested array of dependencies.
   *
   * @return bool
   */
  protected function inDependencies($dependency, $dependencies) {
    list($entity_type_id, $bundle, $uuid) = explode('.', $dependency);
    if (isset($dependencies[$entity_type_id])) {
      if (in_array($dependency, $dependencies[$entity_type_id])) {
        return TRUE;
      }
    }
    return FALSE;
  }

  /**
   * Gets a node attached to a menu link. The node has already been imported.
   *
   * @param \Drupal\menu_link_content\Entity\MenuLinkContent $object
   *   Menu Link Entity.
   *
   * @return \Drupal\Core\Entity\EntityInterface|null
   *   Node Entity.
   *
   */
  protected function getMenuLinkNodeAttached(MenuLinkContent $object) {
    $uri = $object
      ->get('link')
      ->getString();
    $url = Url::fromUri($uri);
    try {
      $route_parameters = $url
        ->getRouteParameters();
      if (count($route_parameters) == 1) {
        $entity_id = reset($route_parameters);
        $entity_type = key($route_parameters);
        return \Drupal::entityTypeManager()
          ->getStorage($entity_type)
          ->load($entity_id);
      }
    } catch (\Exception $e) {

      // If menu link is linked to a non-node page - just do nothing.
    }
  }

  /**
   * @inheritdoc
   */
  public function supportsNormalization($data, $format = NULL) {
    return parent::supportsNormalization($data, $format) && !empty($data->is_content_sync);
  }

  /**
   * @inheritdoc
   */
  public function supportsDenormalization($data, $type, $format = NULL) {
    return parent::supportsDenormalization($data, $type, $format);
  }

  /**
   * @param $object
   * @param array $context
   *
   * @return array
   */
  protected function getContentSyncMetadata($object, $context = []) {
    $metadata = [
      'entity_type' => $object
        ->getEntityTypeId(),
    ];
    return $metadata;
  }

  /**
   * @inheritdoc
   */
  protected function getDecoratorManager() {
    return $this->decoratorManager;
  }

  /**
   * @param array $data
   * @param $entity_type_id
   *
   * @return array
   */
  protected function fixReferences(&$data, $entity_type_id, $bundle = FALSE) {
    if ($bundle) {
      $field_definitions = $this->entityFieldManager
        ->getFieldDefinitions($entity_type_id, $bundle);
    }
    else {
      $bundles = array_keys($this->entityTypeBundleInfo
        ->getBundleInfo($entity_type_id));
      $field_definitions = [];
      foreach ($bundles as $bundle) {
        $field_definitions_bundle = $this->entityFieldManager
          ->getFieldDefinitions($entity_type_id, $bundle);
        if (is_array($field_definitions_bundle)) {
          $field_definitions += $field_definitions_bundle;
        }
      }
    }
    foreach ($field_definitions as $field_name => $field_definition) {

      // We are only interested in importing content entities.
      if (!is_a($field_definition
        ->getClass(), '\\Drupal\\Core\\Field\\EntityReferenceFieldItemList', TRUE)) {
        continue;
      }
      if (!empty($data[$field_name]) && is_array($data[$field_name])) {
        $key = $field_definition
          ->getFieldStorageDefinition()
          ->getMainPropertyName();
        foreach ($data[$field_name] as $i => &$item) {
          if (!empty($item['target_uuid'])) {
            $reference = $this->entityRepository
              ->loadEntityByUuid($item['target_type'], $item['target_uuid']);
            if ($reference) {
              $item[$key] = $reference
                ->id();
              if (is_a($reference, RevisionableInterface::class, TRUE)) {
                $item['target_revision_id'] = $reference
                  ->getRevisionId();
              }
            }
            else {
              $reflection = new \ReflectionClass($this->entityTypeManager
                ->getStorage($item['target_type'])
                ->getEntityType()
                ->getClass());
              if ($reflection
                ->implementsInterface(ContentEntityInterface::class)) {
                unset($data[$field_name][$i]);
              }
            }
          }
        }
      }
    }
    return $data;
  }

  /**
   * @param $data
   * @param $entity_type_id
   */
  protected function cleanupData(&$data, $entity_type_id, $bundle = FALSE) {
    if ($bundle) {
      $field_definitions = $this->entityFieldManager
        ->getFieldDefinitions($entity_type_id, $bundle);
    }
    else {
      $bundles = array_keys($this->entityTypeBundleInfo
        ->getBundleInfo($entity_type_id));
      $field_definitions = [];
      foreach ($bundles as $bundle) {
        $field_definitions_bundle = $this->entityFieldManager
          ->getFieldDefinitions($entity_type_id, $bundle);
        if (is_array($field_definitions_bundle)) {
          $field_definitions += $field_definitions_bundle;
        }
      }
    }
    $field_names = array_keys($field_definitions);
    foreach ($data as $field_name => $field_data) {
      if (!in_array($field_name, $field_names)) {
        unset($data[$field_name]);
      }
    }
  }

}

Members

Namesort descending Modifiers Type Description Overrides
CacheableNormalizerInterface::SERIALIZATION_CONTEXT_CACHEABILITY constant Name of key for bubbling cacheability metadata via serialization context.
ContentEntityNormalizer::$decoratorManager protected property
ContentEntityNormalizer::$entityRepository protected property The entity repository.
ContentEntityNormalizer::$entityTypeBundleInfo protected property The entity bundle info.
ContentEntityNormalizer::$supportedInterfaceOrClass protected property The interface or class that this Normalizer supports. Overrides EntityNormalizer::$supportedInterfaceOrClass
ContentEntityNormalizer::cleanupData protected function
ContentEntityNormalizer::denormalize public function Denormalizes data back into an object of the given class. Overrides EntityNormalizer::denormalize 2
ContentEntityNormalizer::fixReferences protected function
ContentEntityNormalizer::getContentSyncMetadata protected function 1
ContentEntityNormalizer::getDecoratorManager protected function @inheritdoc Overrides SyncNormalizerDecoratorTrait::getDecoratorManager
ContentEntityNormalizer::getMenuLinkNodeAttached protected function Gets a node attached to a menu link. The node has already been imported.
ContentEntityNormalizer::inDependencies protected function Checks if a dependency is in a dependencies nested array.
ContentEntityNormalizer::normalize public function Normalizes an object into a set of arrays/scalars. Overrides ContentEntityNormalizer::normalize 2
ContentEntityNormalizer::supportsDenormalization public function @inheritdoc Overrides NormalizerBase::supportsDenormalization
ContentEntityNormalizer::supportsNormalization public function @inheritdoc Overrides NormalizerBase::supportsNormalization
ContentEntityNormalizer::__construct public function Constructs an EntityNormalizer object. Overrides EntityNormalizer::__construct 1
FieldableEntityNormalizerTrait::$entityFieldManager protected property The entity field manager.
FieldableEntityNormalizerTrait::$entityTypeManager protected property The entity type manager. 1
FieldableEntityNormalizerTrait::$entityTypeRepository protected property The entity type repository.
FieldableEntityNormalizerTrait::constructValue protected function Build the field item value using the incoming data. 7
FieldableEntityNormalizerTrait::denormalizeFieldData protected function Denormalizes entity data by denormalizing each field individually.
FieldableEntityNormalizerTrait::determineEntityTypeId protected function Determines the entity type ID to denormalize as.
FieldableEntityNormalizerTrait::extractBundleData protected function Denormalizes the bundle property so entity creation can use it.
FieldableEntityNormalizerTrait::getEntityFieldManager protected function Returns the entity field manager.
FieldableEntityNormalizerTrait::getEntityTypeDefinition protected function Gets the entity type definition.
FieldableEntityNormalizerTrait::getEntityTypeManager protected function Returns the entity type manager.
FieldableEntityNormalizerTrait::getEntityTypeRepository protected function Returns the entity type repository.
NormalizerBase::$format protected property List of formats which supports (de-)normalization. 3
NormalizerBase::addCacheableDependency protected function Adds cacheability if applicable.
NormalizerBase::checkFormat protected function Checks if the provided format is supported by this normalizer. 2
SyncNormalizerDecoratorTrait::decorateDenormalization protected function
SyncNormalizerDecoratorTrait::decorateDenormalizedEntity protected function
SyncNormalizerDecoratorTrait::decorateNormalization protected function