NULL, 'include_translations' => 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']); } return $query; } /** * {@inheritdoc} */ 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 -1; } /** * {@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->entityType->isTranslatable()) { $langcode_key = $this->entityType->getKey('langcode'); $ids[$langcode_key] = $this->getDefinitionFromEntity($langcode_key); } return $ids; } /** * Gets the field definition from a specific entity base field. * * @param string $key * The field ID key. * * @return array * An associative array with a structure that contains the field type, keyed * as 'type', together with field storage settings as they are returned by * FieldStorageDefinitionInterface::getSettings(). * * @see \Drupal\migrate\Plugin\migrate\destination\EntityContentBase::getDefinitionFromEntity() */ protected function getDefinitionFromEntity($key) { /** @var \Drupal\Core\Field\FieldDefinitionInterface $field_definition */ $field_definition = $this->entityFieldManager->getBaseFieldDefinitions($this->entityType->id())[$key]; return [ 'type' => $field_definition->getType(), ] + $field_definition->getSettings(); } }