Newer
Older
Dries Buytaert
committed
<?php
namespace Drupal\migrate\Plugin\migrate\destination;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityInterface;
Alex Pott
committed
use Drupal\Core\Entity\EntityManagerInterface;
catch
committed
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Field\FieldTypePluginManagerInterface;
use Drupal\Core\TypedData\TranslatableInterface;
Dries Buytaert
committed
use Drupal\Core\TypedData\TypedDataInterface;
use Drupal\migrate\Plugin\MigrationInterface;
use Drupal\migrate\MigrateException;
Angie Byron
committed
use Drupal\migrate\Plugin\MigrateIdMapInterface;
Dries Buytaert
committed
use Drupal\migrate\Row;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* The destination class for all content entities lacking a specific class.
*/
class EntityContentBase extends Entity {
/**
Alex Pott
committed
* Entity manager.
*
* @var \Drupal\Core\Entity\EntityManagerInterface
Dries Buytaert
committed
*/
Alex Pott
committed
protected $entityManager;
Dries Buytaert
committed
/**
* Field type plugin manager.
*
* @var \Drupal\Core\Field\FieldTypePluginManagerInterface
*/
protected $fieldTypeManager;
Dries Buytaert
committed
/**
* 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
Dries Buytaert
committed
* The plugin implementation definition.
* @param \Drupal\migrate\Plugin\MigrationInterface $migration
Dries Buytaert
committed
* The migration entity.
catch
committed
* @param \Drupal\Core\Entity\EntityStorageInterface $storage
* The storage for this entity type.
Dries Buytaert
committed
* @param array $bundles
* The list of bundles this entity type has.
Alex Pott
committed
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
* The entity manager service.
* @param \Drupal\Core\Field\FieldTypePluginManagerInterface $field_type_manager
* The field type plugin manager service.
Dries Buytaert
committed
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, EntityStorageInterface $storage, array $bundles, EntityManagerInterface $entity_manager, FieldTypePluginManagerInterface $field_type_manager) {
catch
committed
parent::__construct($configuration, $plugin_id, $plugin_definition, $migration, $storage, $bundles);
Alex Pott
committed
$this->entityManager = $entity_manager;
$this->fieldTypeManager = $field_type_manager;
Dries Buytaert
committed
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration = NULL) {
Dries Buytaert
committed
$entity_type = static::getEntityTypeId($plugin_id);
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$migration,
catch
committed
$container->get('entity.manager')->getStorage($entity_type),
Dries Buytaert
committed
array_keys($container->get('entity.manager')->getBundleInfo($entity_type)),
$container->get('entity.manager'),
$container->get('plugin.manager.field.field_type')
Dries Buytaert
committed
);
}
/**
* {@inheritdoc}
*/
public function import(Row $row, array $old_destination_id_values = []) {
Angie Byron
committed
$this->rollbackAction = MigrateIdMapInterface::ROLLBACK_DELETE;
Dries Buytaert
committed
$entity = $this->getEntity($row, $old_destination_id_values);
Angie Byron
committed
if (!$entity) {
throw new MigrateException('Unable to get entity');
}
$ids = $this->save($entity, $old_destination_id_values);
if (!empty($this->configuration['translations'])) {
$ids[] = $entity->language()->getId();
}
return $ids;
Dries Buytaert
committed
}
/**
* Saves the entity.
Dries Buytaert
committed
*
* @param \Drupal\Core\Entity\ContentEntityInterface $entity
* The content entity.
* @param array $old_destination_id_values
catch
committed
* (optional) An array of destination ID values. Defaults to an empty array.
Dries Buytaert
committed
*
* @return array
catch
committed
* An array containing the entity ID.
Dries Buytaert
committed
*/
protected function save(ContentEntityInterface $entity, array $old_destination_id_values = []) {
Dries Buytaert
committed
$entity->save();
return [$entity->id()];
Dries Buytaert
committed
}
/**
* Get whether this destination is for translations.
*
* @return bool
* Whether this destination is for translations.
*/
protected function isTranslationDestination() {
return !empty($this->configuration['translations']);
}
Dries Buytaert
committed
/**
* {@inheritdoc}
*/
public function getIds() {
$id_key = $this->getKey('id');
$ids[$id_key] = $this->getDefinitionFromEntity($id_key);
if ($this->isTranslationDestination()) {
if (!$langcode_key = $this->getKey('langcode')) {
throw new MigrateException('This entity type does not support translation.');
}
$ids[$langcode_key] = $this->getDefinitionFromEntity($langcode_key);
}
Dries Buytaert
committed
return $ids;
}
/**
* Updates an entity with the new values from row.
Dries Buytaert
committed
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity to update.
* @param \Drupal\migrate\Row $row
* The row object to update from.
*
Alex Pott
committed
* @return \Drupal\Core\Entity\EntityInterface|null
* An updated entity, or NULL if it's the same as the one passed in.
Dries Buytaert
committed
*/
protected function updateEntity(EntityInterface $entity, Row $row) {
// 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'])) {
$clone = $row->cloneWithoutDestination();
foreach ($this->configuration['overwrite_properties'] as $property) {
$clone->setDestinationProperty($property, $row->getDestinationProperty($property));
}
$row = $clone;
}
Dries Buytaert
committed
foreach ($row->getDestination() as $field_name => $values) {
$field = $entity->$field_name;
if ($field instanceof TypedDataInterface) {
$field->setValue($values);
}
}
Angie Byron
committed
$this->setRollbackAction($row->getIdMap(), $rollback_action);
// We might have a different (translated) entity, so return it.
return $entity;
Dries Buytaert
committed
}
/**
* 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());
}
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
$row->setDestinationProperty($bundle_key, reset($this->bundles));
}
// Populate any required fields not already populated.
$fields = $this->entityManager
->getFieldDefinitions($this->storage->getEntityTypeId(), $bundle_key);
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 {
// Otherwise, ask the field type to generate a sample value.
$field_type = $field_definition->getType();
/** @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);
}
}
}
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
/**
* {@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);
}
}
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
/**
* Gets the field definition from a specific entity base field.
*
* The method takes the field ID as an argument and returns the field storage
* definition to be used in getIds() by querying the destination entity base
* field definition.
*
* @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\Core\Field\FieldStorageDefinitionInterface::getSettings()
*/
protected function getDefinitionFromEntity($key) {
$entity_type_id = static::getEntityTypeId($this->getPluginId());
/** @var \Drupal\Core\Field\FieldStorageDefinitionInterface[] $definitions */
$definitions = $this->entityManager->getBaseFieldDefinitions($entity_type_id);
$field_definition = $definitions[$key];
return [
'type' => $field_definition->getType(),
] + $field_definition->getSettings();
}