class EntityContentBase
Same name in other branches
- 8.9.x core/modules/migrate/src/Plugin/migrate/destination/EntityContentBase.php \Drupal\migrate\Plugin\migrate\destination\EntityContentBase
- 10 core/modules/migrate/src/Plugin/migrate/destination/EntityContentBase.php \Drupal\migrate\Plugin\migrate\destination\EntityContentBase
- 11.x core/modules/migrate/src/Plugin/migrate/destination/EntityContentBase.php \Drupal\migrate\Plugin\migrate\destination\EntityContentBase
Provides destination class for all content entities lacking a specific class.
Available configuration keys:
- translations: (optional) Boolean, indicates if the entity is translatable, defaults to FALSE.
- overwrite_properties: (optional) A list of properties that will be overwritten if an entity with the same ID already exists. Any properties that are not listed will not be overwritten.
- validate: (optional) Boolean, indicates whether an entity should be validated, defaults to FALSE.
Example:
The example below will create a 'node' entity of content type 'article'.
The language of the source will be used because the configuration 'translations: true' was set. Without this configuration option the site's default language would be used.
The example content type has fields 'title', 'body' and 'field_example'. The text format of the body field is defaulted to 'basic_html'. The example uses the EmbeddedDataSource source plugin for the sake of simplicity.
If the migration is executed again in an update mode, any updates done in the destination Drupal site to the 'title' and 'body' fields would be overwritten with the original source values. Updates done to 'field_example' would be preserved because 'field_example' is not included in 'overwrite_properties' configuration.
id: custom_article_migration
label: Custom article migration
source:
plugin: embedded_data
data_rows:
-
id: 1
langcode: 'fi'
title: 'Sivun otsikko'
field_example: 'Huhuu'
content: '<p>Hoi maailma</p>'
ids:
id:
type: integer
process:
nid: id
langcode: langcode
title: title
field_example: field_example
'body/0/value': content
'body/0/format':
plugin: default_value
default_value: basic_html
destination:
plugin: entity:node
default_bundle: article
translations: true
overwrite_properties:
- title
- body
# Run entity and fields validation before saving an entity.
# validate: true
Hierarchy
- class \Drupal\Component\Plugin\PluginBase implements \Drupal\Component\Plugin\PluginInspectionInterface, \Drupal\Component\Plugin\DerivativeInspectionInterface
- class \Drupal\Core\Plugin\PluginBase extends \Drupal\Component\Plugin\PluginBase uses \Drupal\Core\StringTranslation\StringTranslationTrait, \Drupal\Core\DependencyInjection\DependencySerializationTrait, \Drupal\Core\Messenger\MessengerTrait
- class \Drupal\migrate\Plugin\migrate\destination\DestinationBase extends \Drupal\Core\Plugin\PluginBase implements \Drupal\migrate\Plugin\MigrateDestinationInterface, \Drupal\migrate\Plugin\RequirementsInterface
- class \Drupal\migrate\Plugin\migrate\destination\Entity extends \Drupal\migrate\Plugin\migrate\destination\DestinationBase implements \Drupal\Core\Plugin\ContainerFactoryPluginInterface, \Drupal\Component\Plugin\DependentPluginInterface uses \Drupal\Core\Entity\DependencyTrait, \Drupal\migrate\EntityFieldDefinitionTrait
- class \Drupal\migrate\Plugin\migrate\destination\EntityContentBase extends \Drupal\migrate\Plugin\migrate\destination\Entity implements \Drupal\migrate\Audit\HighestIdInterface, \Drupal\migrate\Plugin\MigrateValidatableEntityInterface
- class \Drupal\migrate\Plugin\migrate\destination\Entity extends \Drupal\migrate\Plugin\migrate\destination\DestinationBase implements \Drupal\Core\Plugin\ContainerFactoryPluginInterface, \Drupal\Component\Plugin\DependentPluginInterface uses \Drupal\Core\Entity\DependencyTrait, \Drupal\migrate\EntityFieldDefinitionTrait
- class \Drupal\migrate\Plugin\migrate\destination\DestinationBase extends \Drupal\Core\Plugin\PluginBase implements \Drupal\migrate\Plugin\MigrateDestinationInterface, \Drupal\migrate\Plugin\RequirementsInterface
- class \Drupal\Core\Plugin\PluginBase extends \Drupal\Component\Plugin\PluginBase uses \Drupal\Core\StringTranslation\StringTranslationTrait, \Drupal\Core\DependencyInjection\DependencySerializationTrait, \Drupal\Core\Messenger\MessengerTrait
Expanded class hierarchy of EntityContentBase
See also
\Drupal\Core\Entity\FieldableEntityInterface::validate()
\Drupal\migrate\Plugin\migrate\destination\Entity
\Drupal\migrate\Plugin\migrate\destination\EntityRevision
8 files declare their use of EntityContentBase
- Book.php in core/
modules/ book/ src/ Plugin/ migrate/ destination/ Book.php - DestinationCategoryTest.php in core/
modules/ migrate_drupal/ tests/ src/ Kernel/ Plugin/ migrate/ DestinationCategoryTest.php - EntityComment.php in core/
modules/ comment/ src/ Plugin/ migrate/ destination/ EntityComment.php - EntityContentBaseTest.php in core/
modules/ migrate/ tests/ src/ Unit/ Plugin/ migrate/ destination/ EntityContentBaseTest.php - Contains \Drupal\Tests\migrate\Unit\Plugin\migrate\destination\EntityContentBaseTest.
- EntityFile.php in core/
modules/ file/ src/ Plugin/ migrate/ destination/ EntityFile.php
File
-
core/
modules/ migrate/ src/ Plugin/ migrate/ destination/ EntityContentBase.php, line 94
Namespace
Drupal\migrate\Plugin\migrate\destinationView source
class EntityContentBase extends Entity implements HighestIdInterface, MigrateValidatableEntityInterface {
/**
* Field type plugin manager.
*
* @var \Drupal\Core\Field\FieldTypePluginManagerInterface
*/
protected $fieldTypeManager;
/**
* The account switcher service.
*
* @var \Drupal\Core\Session\AccountSwitcherInterface
*/
protected $accountSwitcher;
/**
* Constructs a content entity.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
* @param string $plugin_id
* The plugin ID for the plugin instance.
* @param mixed $plugin_definition
* The plugin implementation definition.
* @param \Drupal\migrate\Plugin\MigrationInterface $migration
* The migration entity.
* @param \Drupal\Core\Entity\EntityStorageInterface $storage
* The storage for this entity type.
* @param array $bundles
* The list of bundles this entity type has.
* @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager
* The entity field manager.
* @param \Drupal\Core\Field\FieldTypePluginManagerInterface $field_type_manager
* The field type plugin manager service.
* @param \Drupal\Core\Session\AccountSwitcherInterface $account_switcher
* The account switcher service.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, EntityStorageInterface $storage, array $bundles, EntityFieldManagerInterface $entity_field_manager, FieldTypePluginManagerInterface $field_type_manager, AccountSwitcherInterface $account_switcher = NULL) {
parent::__construct($configuration, $plugin_id, $plugin_definition, $migration, $storage, $bundles);
$this->entityFieldManager = $entity_field_manager;
$this->fieldTypeManager = $field_type_manager;
if ($account_switcher === NULL) {
@trigger_error('Calling ' . __NAMESPACE__ . '\\EntityContentBase::__construct() without the $account_switcher argument is deprecated in drupal:9.3.0 and will be required in drupal:10.0.0. See https://www.drupal.org/node/3142975', E_USER_DEPRECATED);
$account_switcher = \Drupal::service('account_switcher');
}
$this->accountSwitcher = $account_switcher;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration = NULL) {
$entity_type = static::getEntityTypeId($plugin_id);
return new static($configuration, $plugin_id, $plugin_definition, $migration, $container->get('entity_type.manager')
->getStorage($entity_type), array_keys($container->get('entity_type.bundle.info')
->getBundleInfo($entity_type)), $container->get('entity_field.manager'), $container->get('plugin.manager.field.field_type'), $container->get('account_switcher'));
}
/**
* {@inheritdoc}
*
* @throws \Drupal\migrate\MigrateException
* When an entity cannot be looked up.
* @throws \Drupal\migrate\Exception\EntityValidationException
* When an entity validation hasn't been passed.
*/
public function import(Row $row, array $old_destination_id_values = []) {
$this->rollbackAction = MigrateIdMapInterface::ROLLBACK_DELETE;
$entity = $this->getEntity($row, $old_destination_id_values);
if (!$entity) {
throw new MigrateException('Unable to get entity');
}
assert($entity instanceof ContentEntityInterface);
if ($this->isEntityValidationRequired($entity)) {
$this->validateEntity($entity);
}
$ids = $this->save($entity, $old_destination_id_values);
if ($this->isTranslationDestination()) {
$ids[] = $entity->language()
->getId();
}
return $ids;
}
/**
* {@inheritdoc}
*/
public function isEntityValidationRequired(FieldableEntityInterface $entity) {
// Prioritize the entity method over migration config because it won't be
// possible to save that entity unvalidated.
/* @see \Drupal\Core\Entity\ContentEntityBase::preSave() */
return $entity->isValidationRequired() || !empty($this->configuration['validate']);
}
/**
* {@inheritdoc}
*/
public function validateEntity(FieldableEntityInterface $entity) {
// Entity validation can require the user that owns the entity. Switch to
// use that user during validation.
// As an example:
// @see \Drupal\Core\Entity\Plugin\Validation\Constraint\ValidReferenceConstraint
$account = $entity instanceof EntityOwnerInterface ? $entity->getOwner() : NULL;
// Validate account exists as the owner reference could be invalid for any
// number of reasons.
if ($account) {
$this->accountSwitcher
->switchTo($account);
}
// This finally block ensures that the account is always switched back, even
// if an exception was thrown. Any validation exceptions are intentionally
// left unhandled. They should be caught and logged by a catch block
// surrounding the row import and then added to the migration messages table
// for the current row.
try {
$violations = $entity->validate();
} finally {
if ($account) {
$this->accountSwitcher
->switchBack();
}
}
if (count($violations) > 0) {
throw new EntityValidationException($violations);
}
}
/**
* Saves the entity.
*
* @param \Drupal\Core\Entity\ContentEntityInterface $entity
* The content entity.
* @param array $old_destination_id_values
* (optional) An array of destination ID values. Defaults to an empty array.
*
* @return array
* An array containing the entity ID.
*/
protected function save(ContentEntityInterface $entity, array $old_destination_id_values = []) {
$entity->save();
return [
$entity->id(),
];
}
/**
* {@inheritdoc}
*/
public function isTranslationDestination() {
return !empty($this->configuration['translations']);
}
/**
* {@inheritdoc}
*/
public function getIds() {
$ids = [];
$id_key = $this->getKey('id');
$ids[$id_key] = $this->getDefinitionFromEntity($id_key);
if ($this->isTranslationDestination()) {
$langcode_key = $this->getKey('langcode');
if (!$langcode_key) {
throw new MigrateException(sprintf('The "%s" entity type does not support translations.', $this->storage
->getEntityTypeId()));
}
$ids[$langcode_key] = $this->getDefinitionFromEntity($langcode_key);
}
return $ids;
}
/**
* Updates an entity with the new values from row.
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity to update.
* @param \Drupal\migrate\Row $row
* The row object to update from.
*
* @return \Drupal\Core\Entity\EntityInterface
* An updated entity from row values.
*/
protected function updateEntity(EntityInterface $entity, Row $row) {
$empty_destinations = $row->getEmptyDestinationProperties();
// By default, an update will be preserved.
$rollback_action = MigrateIdMapInterface::ROLLBACK_PRESERVE;
// Make sure we have the right translation.
if ($this->isTranslationDestination()) {
$property = $this->storage
->getEntityType()
->getKey('langcode');
if ($row->hasDestinationProperty($property)) {
$language = $row->getDestinationProperty($property);
if (!$entity->hasTranslation($language)) {
$entity->addTranslation($language);
// We're adding a translation, so delete it on rollback.
$rollback_action = MigrateIdMapInterface::ROLLBACK_DELETE;
}
$entity = $entity->getTranslation($language);
}
}
// If the migration has specified a list of properties to be overwritten,
// clone the row with an empty set of destination values, and re-add only
// the specified properties.
if (isset($this->configuration['overwrite_properties'])) {
$empty_destinations = array_intersect($empty_destinations, $this->configuration['overwrite_properties']);
$clone = $row->cloneWithoutDestination();
foreach ($this->configuration['overwrite_properties'] as $property) {
$clone->setDestinationProperty($property, $row->getDestinationProperty($property));
}
$row = $clone;
}
foreach ($row->getDestination() as $field_name => $values) {
$field = $entity->{$field_name};
if ($field instanceof TypedDataInterface) {
$field->setValue($values);
}
}
foreach ($empty_destinations as $field_name) {
$entity->{$field_name} = NULL;
}
$this->setRollbackAction($row->getIdMap(), $rollback_action);
// We might have a different (translated) entity, so return it.
return $entity;
}
/**
* Populates as much of the stub row as possible.
*
* @param \Drupal\migrate\Row $row
* The row of data.
*/
protected function processStubRow(Row $row) {
$bundle_key = $this->getKey('bundle');
if ($bundle_key && empty($row->getDestinationProperty($bundle_key))) {
if (empty($this->bundles)) {
throw new MigrateException('Stubbing failed, no bundles available for entity type: ' . $this->storage
->getEntityTypeId());
}
$row->setDestinationProperty($bundle_key, reset($this->bundles));
}
$bundle = $row->getDestinationProperty($bundle_key) ?? $this->storage
->getEntityTypeId();
// Populate any required fields not already populated.
$fields = $this->entityFieldManager
->getFieldDefinitions($this->storage
->getEntityTypeId(), $bundle);
foreach ($fields as $field_name => $field_definition) {
if ($field_definition->isRequired() && is_null($row->getDestinationProperty($field_name))) {
// Use the configured default value for this specific field, if any.
if ($default_value = $field_definition->getDefaultValueLiteral()) {
$values = $default_value;
}
else {
/** @var \Drupal\Core\Field\FieldItemInterface $field_type_class */
$field_type_class = $this->fieldTypeManager
->getPluginClass($field_definition->getType());
$values = $field_type_class::generateSampleValue($field_definition);
if (is_null($values)) {
// Handle failure to generate a sample value.
throw new MigrateException('Stubbing failed, unable to generate value for field ' . $field_name);
}
}
$row->setDestinationProperty($field_name, $values);
}
}
}
/**
* {@inheritdoc}
*/
public function rollback(array $destination_identifier) {
if ($this->isTranslationDestination()) {
// Attempt to remove the translation.
$entity = $this->storage
->load(reset($destination_identifier));
if ($entity && $entity instanceof TranslatableInterface) {
if ($key = $this->getKey('langcode')) {
if (isset($destination_identifier[$key])) {
$langcode = $destination_identifier[$key];
if ($entity->hasTranslation($langcode)) {
// Make sure we don't remove the default translation.
$translation = $entity->getTranslation($langcode);
if (!$translation->isDefaultTranslation()) {
$entity->removeTranslation($langcode);
$entity->save();
}
}
}
}
}
}
else {
parent::rollback($destination_identifier);
}
}
/**
* {@inheritdoc}
*/
public function getHighestId() {
$values = $this->storage
->getQuery()
->accessCheck(FALSE)
->sort($this->getKey('id'), 'DESC')
->range(0, 1)
->execute();
return (int) current($values);
}
}
Members
Title Sort descending | Modifiers | Object type | Summary | Overriden Title | Overrides |
---|---|---|---|---|---|
DependencyTrait::$dependencies | protected | property | The object's dependencies. | ||
DependencyTrait::addDependencies | protected | function | Adds multiple dependencies. | ||
DependencyTrait::addDependency | protected | function | Adds a dependency. | ||
DestinationBase::$migration | protected | property | The migration. | ||
DestinationBase::$rollbackAction | protected | property | The rollback action to be saved for the last imported item. | ||
DestinationBase::$supportsRollback | protected | property | Indicates whether the destination can be rolled back. | ||
DestinationBase::checkRequirements | public | function | Checks if requirements for this plugin are OK. | Overrides RequirementsInterface::checkRequirements | |
DestinationBase::getDestinationModule | public | function | Gets the destination module handling the destination data. | Overrides MigrateDestinationInterface::getDestinationModule | 1 |
DestinationBase::rollbackAction | public | function | The rollback action for the last imported item. | Overrides MigrateDestinationInterface::rollbackAction | |
DestinationBase::setRollbackAction | protected | function | For a destination item being updated, set the appropriate rollback action. | ||
DestinationBase::supportsRollback | public | function | Whether the destination can be rolled back or not. | Overrides MigrateDestinationInterface::supportsRollback | |
Entity::$bundles | protected | property | The list of the bundles of this entity type. | ||
Entity::$entityFieldManager | protected | property | The entity field manager. | ||
Entity::$storage | protected | property | The entity storage. | ||
Entity::calculateDependencies | public | function | Calculates dependencies for the configured plugin. | Overrides DependentPluginInterface::calculateDependencies | |
Entity::fields | public | function | Returns an array of destination fields. | Overrides MigrateDestinationInterface::fields | |
Entity::getBundle | public | function | Gets the bundle for the row taking into account the default. | ||
Entity::getEntity | protected | function | Creates or loads an entity. | 5 | |
Entity::getEntityId | protected | function | Gets the entity ID of the row. | 2 | |
Entity::getKey | protected | function | Returns a specific entity key. | ||
EntityContentBase::$accountSwitcher | protected | property | The account switcher service. | ||
EntityContentBase::$fieldTypeManager | protected | property | Field type plugin manager. | ||
EntityContentBase::create | public static | function | Creates an instance of the plugin. | Overrides Entity::create | 2 |
EntityContentBase::getHighestId | public | function | Returns the highest ID tracked by the implementing plugin. | Overrides HighestIdInterface::getHighestId | 2 |
EntityContentBase::getIds | public | function | Gets the destination IDs. | Overrides MigrateDestinationInterface::getIds | 2 |
EntityContentBase::import | public | function | Overrides MigrateDestinationInterface::import | 2 | |
EntityContentBase::isEntityValidationRequired | public | function | Returns a state of whether an entity needs to be validated before saving. | Overrides MigrateValidatableEntityInterface::isEntityValidationRequired | |
EntityContentBase::isTranslationDestination | public | function | |||
EntityContentBase::processStubRow | protected | function | Populates as much of the stub row as possible. | 3 | |
EntityContentBase::rollback | public | function | Delete the specified destination object from the target Drupal. | Overrides Entity::rollback | 1 |
EntityContentBase::save | protected | function | Saves the entity. | 3 | |
EntityContentBase::updateEntity | protected | function | Updates an entity with the new values from row. | 3 | |
EntityContentBase::validateEntity | public | function | Validates the entity. | Overrides MigrateValidatableEntityInterface::validateEntity | |
EntityContentBase::__construct | public | function | Constructs a content entity. | Overrides Entity::__construct | 3 |
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. | 3 | |
PluginInspectionInterface::getPluginDefinition | public | function | Gets the definition of the plugin implementation. | 6 | |
PluginInspectionInterface::getPluginId | public | function | Gets the plugin_id of the plugin instance. | 2 |
Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.