Same name and namespace in other branches
  1. 8.9.x core/modules/migrate_drupal/src/Plugin/migrate/source/ContentEntity.php \Drupal\migrate_drupal\Plugin\migrate\source\ContentEntity
  2. 9 core/modules/migrate_drupal/src/Plugin/migrate/source/ContentEntity.php \Drupal\migrate_drupal\Plugin\migrate\source\ContentEntity

Source plugin to get content entities from the current version of Drupal.

This plugin uses the Entity API to export entity data. If the source entity type has custom field storage fields or computed fields, this class will need to be extended and the new class will need to load/calculate the values for those fields.

Available configuration keys:

  • entity_type: The entity type ID of the entities being exported. This is calculated dynamically by the deriver so it is only needed if the deriver is not utilized, i.e., a custom source plugin.
  • bundle: (optional) If the entity type is bundleable, only return entities of this bundle.
  • include_translations: (optional) Indicates if the entity translations should be included, defaults to TRUE.
  • add_revision_id: (optional) Indicates if the revision key is added to the source IDs, defaults to TRUE.

Examples:

This will return the default revision for all nodes, from every bundle and every translation. The revision key is added to the source IDs.

source:
plugin:
content_entity:
node;

This will return the default revision for all nodes, from every bundle and every translation. The revision key is not added to the source IDs.


source:
  plugin: content_entity:node
  add_revision_id: false

This will only return nodes of type 'article' in their default language.


source:
  plugin: content_entity:node
  bundle: article
  include_translations: false

For additional configuration keys, refer to the parent class:

Plugin annotation


@MigrateSource(
  id = "content_entity",
  source_module = "migrate_drupal",
  deriver = "\Drupal\migrate_drupal\Plugin\migrate\source\ContentEntityDeriver",
)

Hierarchy

Expanded class hierarchy of ContentEntity

See also

\Drupal\migrate\Plugin\migrate\source\SourcePluginBase

1 file declares its use of ContentEntity
ContentEntityConstructorTest.php in core/modules/migrate_drupal/tests/src/Kernel/Plugin/migrate/source/ContentEntityConstructorTest.php

File

core/modules/migrate_drupal/src/Plugin/migrate/source/ContentEntity.php, line 71

Namespace

Drupal\migrate_drupal\Plugin\migrate\source
View source
class ContentEntity extends SourcePluginBase implements ContainerFactoryPluginInterface {
  use EntityFieldDefinitionTrait;

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * The entity field manager.
   *
   * @var \Drupal\Core\Entity\EntityFieldManagerInterface
   */
  protected $entityFieldManager;

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

  /**
   * The entity type definition.
   *
   * @var \Drupal\Core\Entity\EntityTypeInterface
   */
  protected $entityType;

  /**
   * The plugin's default configuration.
   *
   * @var array
   */
  protected $defaultConfiguration = [
    'bundle' => NULL,
    'include_translations' => TRUE,
    'add_revision_id' => TRUE,
  ];

  /**
   * {@inheritdoc}
   */
  public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, EntityTypeBundleInfoInterface $entity_type_bundle_info) {
    if (empty($plugin_definition['entity_type'])) {
      throw new InvalidPluginDefinitionException($plugin_id, 'Missing required "entity_type" definition.');
    }
    $this->entityTypeManager = $entity_type_manager;
    $this->entityFieldManager = $entity_field_manager;
    $this->entityTypeBundleInfo = $entity_type_bundle_info;
    $this->entityType = $this->entityTypeManager
      ->getDefinition($plugin_definition['entity_type']);
    if (!$this->entityType instanceof ContentEntityTypeInterface) {
      throw new InvalidPluginDefinitionException($plugin_id, sprintf('The entity type (%s) is not supported. The "content_entity" source plugin only supports content entities.', $plugin_definition['entity_type']));
    }
    if (!empty($configuration['bundle'])) {
      if (!$this->entityType
        ->hasKey('bundle')) {
        throw new \InvalidArgumentException(sprintf('A bundle was provided but the entity type (%s) is not bundleable.', $plugin_definition['entity_type']));
      }
      $bundle_info = array_keys($this->entityTypeBundleInfo
        ->getBundleInfo($this->entityType
        ->id()));
      if (!in_array($configuration['bundle'], $bundle_info, TRUE)) {
        throw new \InvalidArgumentException(sprintf('The provided bundle (%s) is not valid for the (%s) entity type.', $configuration['bundle'], $plugin_definition['entity_type']));
      }
    }
    parent::__construct($configuration + $this->defaultConfiguration, $plugin_id, $plugin_definition, $migration);
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration = NULL) {
    return new static($configuration, $plugin_id, $plugin_definition, $migration, $container
      ->get('entity_type.manager'), $container
      ->get('entity_field.manager'), $container
      ->get('entity_type.bundle.info'));
  }

  /**
   * {@inheritdoc}
   */
  public function __toString() {
    return (string) $this->entityType
      ->getPluralLabel();
  }

  /**
   * Initializes the iterator with the source data.
   *
   * @return \Generator
   *   A data generator for this source.
   */
  protected function initializeIterator() {
    $ids = $this
      ->query()
      ->execute();
    return $this
      ->yieldEntities($ids);
  }

  /**
   * Loads and yields entities, one at a time.
   *
   * @param array $ids
   *   The entity IDs.
   *
   * @return \Generator
   *   An iterable of the loaded entities.
   */
  protected function yieldEntities(array $ids) {
    $storage = $this->entityTypeManager
      ->getStorage($this->entityType
      ->id());
    foreach ($ids as $id) {

      /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
      $entity = $storage
        ->load($id);
      (yield $this
        ->toArray($entity));
      if ($this->configuration['include_translations']) {
        foreach ($entity
          ->getTranslationLanguages(FALSE) as $language) {
          (yield $this
            ->toArray($entity
            ->getTranslation($language
            ->getId())));
        }
      }
    }
  }

  /**
   * Converts an entity to an array.
   *
   * Makes all IDs into flat values. All other values are returned as per
   * $entity->toArray(), which is a nested array.
   *
   * @param \Drupal\Core\Entity\ContentEntityInterface $entity
   *   The entity to convert.
   *
   * @return array
   *   The entity, represented as an array.
   */
  protected function toArray(ContentEntityInterface $entity) {
    $return = $entity
      ->toArray();

    // This is necessary because the IDs must be flat. They cannot be nested for
    // the ID map.
    foreach (array_keys($this
      ->getIds()) as $id) {

      /** @var \Drupal\Core\TypedData\Plugin\DataType\ItemList $value */
      $value = $entity
        ->get($id);

      // Force the IDs on top of the previous values.
      $return[$id] = $value
        ->first()
        ->getString();
    }
    return $return;
  }

  /**
   * Query to retrieve the entities.
   *
   * @return \Drupal\Core\Entity\Query\QueryInterface
   *   The query.
   */
  public function query() {
    $query = $this->entityTypeManager
      ->getStorage($this->entityType
      ->id())
      ->getQuery()
      ->accessCheck(FALSE);
    if (!empty($this->configuration['bundle'])) {
      $query
        ->condition($this->entityType
        ->getKey('bundle'), $this->configuration['bundle']);
    }

    // Exclude anonymous user account.
    if ($this->entityType
      ->id() === 'user' && !empty($this->entityType
      ->getKey('id'))) {
      $query
        ->condition($this->entityType
        ->getKey('id'), 0, '>');
    }
    return $query;
  }

  /**
   * {@inheritdoc}
   */

  #[\ReturnTypeWillChange]
  public function count($refresh = FALSE) {

    // If no translations are included, then a simple query is possible.
    if (!$this->configuration['include_translations']) {
      return parent::count($refresh);
    }

    // @TODO: Determine a better way to retrieve a valid count for translations.
    // https://www.drupal.org/project/drupal/issues/2937166
    return MigrateSourceInterface::NOT_COUNTABLE;
  }

  /**
   * {@inheritdoc}
   */
  protected function doCount() {
    return $this
      ->query()
      ->count()
      ->execute();
  }

  /**
   * {@inheritdoc}
   */
  public function fields() {

    // Retrieving fields from a non-fieldable content entity will throw a
    // LogicException. Return an empty list of fields instead.
    if (!$this->entityType
      ->entityClassImplements('Drupal\\Core\\Entity\\FieldableEntityInterface')) {
      return [];
    }
    $field_definitions = $this->entityFieldManager
      ->getBaseFieldDefinitions($this->entityType
      ->id());
    if (!empty($this->configuration['bundle'])) {
      $field_definitions += $this->entityFieldManager
        ->getFieldDefinitions($this->entityType
        ->id(), $this->configuration['bundle']);
    }
    $fields = array_map(function ($definition) {
      return (string) $definition
        ->getLabel();
    }, $field_definitions);
    return $fields;
  }

  /**
   * {@inheritdoc}
   */
  public function getIds() {
    $id_key = $this->entityType
      ->getKey('id');
    $ids[$id_key] = $this
      ->getDefinitionFromEntity($id_key);
    if ($this->configuration['add_revision_id'] && $this->entityType
      ->isRevisionable()) {
      $revision_key = $this->entityType
        ->getKey('revision');
      $ids[$revision_key] = $this
        ->getDefinitionFromEntity($revision_key);
    }
    if ($this->entityType
      ->isTranslatable()) {
      $langcode_key = $this->entityType
        ->getKey('langcode');
      $ids[$langcode_key] = $this
        ->getDefinitionFromEntity($langcode_key);
    }
    return $ids;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
ContentEntity::$defaultConfiguration protected property The plugin's default configuration.
ContentEntity::$entityFieldManager protected property The entity field manager.
ContentEntity::$entityType protected property The entity type definition.
ContentEntity::$entityTypeBundleInfo protected property The entity type bundle info service.
ContentEntity::$entityTypeManager protected property The entity type manager.
ContentEntity::count public function Overrides SourcePluginBase::count
ContentEntity::create public static function Creates an instance of the plugin. Overrides ContainerFactoryPluginInterface::create
ContentEntity::doCount protected function Gets the source count checking if the source is countable or using the iterator_count function. Overrides SourcePluginBase::doCount
ContentEntity::fields public function Returns available fields on the source. Overrides MigrateSourceInterface::fields
ContentEntity::getIds public function Defines the source fields uniquely identifying a source row. Overrides MigrateSourceInterface::getIds
ContentEntity::initializeIterator protected function Initializes the iterator with the source data. Overrides SourcePluginBase::initializeIterator
ContentEntity::query public function Query to retrieve the entities.
ContentEntity::toArray protected function Converts an entity to an array.
ContentEntity::yieldEntities protected function Loads and yields entities, one at a time.
ContentEntity::__construct public function Constructs a \Drupal\Component\Plugin\PluginBase object. Overrides SourcePluginBase::__construct
ContentEntity::__toString public function Allows class to decide how it will react when it is treated like a string. Overrides MigrateSourceInterface::__toString
DependencySerializationTrait::$_entityStorages protected property
DependencySerializationTrait::$_serviceIds protected property
DependencySerializationTrait::__sleep public function 2
DependencySerializationTrait::__wakeup public function 2
EntityFieldDefinitionTrait::getDefinitionFromEntity protected function Gets the field definition from a specific entity base field.
EntityFieldDefinitionTrait::getEntityTypeId protected static function Finds the entity type from configuration or plugin ID.
MessengerTrait::$messenger protected property The messenger. 10
MessengerTrait::messenger public function Gets the messenger. 10
MessengerTrait::setMessenger public function Sets the messenger.
MigrateSourceInterface::NOT_COUNTABLE constant Indicates that the source is not countable.
PluginBase::$configuration protected property Configuration information passed into the plugin. 1
PluginBase::$pluginDefinition protected property The plugin implementation definition. 1
PluginBase::$pluginId protected property The plugin_id.
PluginBase::DERIVATIVE_SEPARATOR constant A string which is used to separate base plugin IDs from the derivative ID.
PluginBase::getBaseId public function Gets the base_plugin_id of the plugin instance. Overrides DerivativeInspectionInterface::getBaseId
PluginBase::getDerivativeId public function Gets the derivative_id of the plugin instance. Overrides DerivativeInspectionInterface::getDerivativeId
PluginBase::getPluginDefinition public function Gets the definition of the plugin implementation. Overrides PluginInspectionInterface::getPluginDefinition 2
PluginBase::getPluginId public function Gets the plugin_id of the plugin instance. Overrides PluginInspectionInterface::getPluginId
PluginBase::isConfigurable public function Determines if the plugin is configurable.
SourcePluginBase::$cache protected property The backend cache.
SourcePluginBase::$cacheCounts protected property Whether this instance should cache the source count. 1
SourcePluginBase::$cacheKey protected property Key to use for caching counts.
SourcePluginBase::$currentRow protected property The current row from the query.
SourcePluginBase::$currentSourceIds protected property The primary key of the current row.
SourcePluginBase::$highWaterProperty protected property Information on the property used as the high-water mark.
SourcePluginBase::$highWaterStorage protected property The key-value storage for the high-water value.
SourcePluginBase::$idMap protected property The migration ID map.
SourcePluginBase::$iterator protected property The iterator to iterate over the source rows.
SourcePluginBase::$mapRowAdded protected property Flags whether source plugin will read the map row and add to data row.
SourcePluginBase::$migration protected property The entity migration object.
SourcePluginBase::$moduleHandler protected property The module handler service. 2
SourcePluginBase::$originalHighWater protected property The high water mark at the beginning of the import operation.
SourcePluginBase::$skipCount protected property Whether this instance should not attempt to count the source. 1
SourcePluginBase::$trackChanges protected property Flags whether to track changes to incoming data. 1
SourcePluginBase::aboveHighWater protected function Check if the incoming data is newer than what we've previously imported.
SourcePluginBase::current public function
SourcePluginBase::fetchNextRow protected function Position the iterator to the following row. 1
SourcePluginBase::getCache protected function Gets the cache object.
SourcePluginBase::getCurrentIds public function Gets the currentSourceIds data member.
SourcePluginBase::getHighWater protected function The current value of the high water mark.
SourcePluginBase::getHighWaterField protected function Get the name of the field used as the high watermark.
SourcePluginBase::getHighWaterProperty protected function Get information on the property used as the high watermark.
SourcePluginBase::getHighWaterStorage protected function Get the high water storage object.
SourcePluginBase::getIterator protected function Returns the iterator that will yield the row arrays to be processed.
SourcePluginBase::getModuleHandler protected function Gets the module handler.
SourcePluginBase::getSourceModule public function Gets the source module providing the source data. Overrides MigrateSourceInterface::getSourceModule
SourcePluginBase::key public function
SourcePluginBase::next public function
SourcePluginBase::postRollback public function Performs post-rollback tasks. Overrides RollbackAwareInterface::postRollback
SourcePluginBase::prepareRow public function Adds additional data to the row. Overrides MigrateSourceInterface::prepareRow 49
SourcePluginBase::preRollback public function Performs pre-rollback tasks. Overrides RollbackAwareInterface::preRollback
SourcePluginBase::rewind public function 1
SourcePluginBase::rowChanged protected function Checks if the incoming row has changed since our last import.
SourcePluginBase::saveHighWater protected function Save the new high water mark.
SourcePluginBase::valid public function
StringTranslationTrait::$stringTranslation protected property The string translation service. 3
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 1
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.