entity_api.inc in Migrate Extras 7.2
Support for entity types implementing the Entity API.
File
entity_api.incView source
<?php
/**
* @file
* Support for entity types implementing the Entity API.
*/
/**
* Destination class implementing migration into entity types.
*
* To make entity properties that correspond to columns in the entity's base
* table available as FieldMapping destinations, they must be present in Entity
* API's entity property info and have setter callbacks defined. Because the
* EntityDefaultMetadataController doesn't add setter callbacks to the default
* entity property info it produces, the custom entity needs to provide this
* either in an implementation of hook_entity_property_info(), or via EntityAPI
* in a custom metadata controller class.
*/
class MigrateDestinationEntityAPI extends MigrateDestinationEntity {
/**
* Info about the current entity type.
*
* @var array
*/
protected $info;
/**
* Name of the entity id key (for example, nid for nodes).
*
* @var string
*/
protected $id;
/**
* Name of the entity revision key (for example, vid for nodes).
*
* @var string
*/
protected $revision;
/**
* Gets the schema for the base key(s) of an entity type.
*
* @param string $entity_type
* A Drupal entity type.
*/
public function getKeySchema($entity_type = NULL) {
// Migrate UI invokes $destination->getKeySchema() without any parameters.
if (!$entity_type) {
if (isset($this)) {
if ($this instanceof MigrateDestination) {
$entity_type = $this->entityType;
}
elseif ($this instanceof Migration) {
$entity_type = $this->destination->entityType;
}
}
else {
return array();
}
}
$info = entity_get_info($entity_type);
$schema = drupal_get_schema($info['base table']);
$key = isset($info['entity keys']['name']) ? $info['entity keys']['name'] : $info['entity keys']['id'];
$key_schema = $schema['fields'][$key];
$revision_key = isset($info['entity keys']['revision']) ? $info['entity keys']['revision'] : NULL;
$revision_schema = empty($revision_key) ? NULL : $schema['fields'][$revision_key];
// We can't have any form of serial fields here, since the mapping table
// already has it's own.
$key_schema['auto_increment'] = FALSE;
if ($key_schema['type'] == 'serial') {
$key_schema['type'] = 'int';
}
$return = array(
$key => $key_schema,
);
if (!empty($revision_key)) {
$return[$revision_key] = $revision_schema;
}
return $return;
}
/**
* Return an options array (language, text_format), used for creating fields.
*
* @param string $language
* @param string $text_format
*/
public static function options($language, $text_format) {
return compact('language', 'text_format');
}
/**
* Basic initialization
*
* @param string $entity_type
* @param string $bundle
* @param array $options
* Options (language, text_format) used for creating fields.
*/
public function __construct($entity_type, $bundle, array $options = array()) {
parent::__construct($entity_type, $bundle, $options);
$this->info = entity_get_info($entity_type);
$this->id = isset($this->info['entity keys']['name']) ? $this->info['entity keys']['name'] : $this->info['entity keys']['id'];
$this->revision = isset($this->info['entity keys']['revision']) ? $this->info['entity keys']['revision'] : NULL;
}
/**
* Returns a list of fields available to be mapped for entities attached to
* a particular bundle.
*
* @param Migration $migration
* Optionally, the migration containing this destination.
* @return array
* Keys: machine names of the fields (to be passed to addFieldMapping)
* Values: Human-friendly descriptions of the fields.
*/
public function fields($migration = NULL) {
$properties = entity_get_property_info($this->entityType);
$fields = array();
foreach ($properties['properties'] as $name => $property_info) {
if (isset($property_info['setter callback'])) {
$fields[$name] = $property_info['description'];
}
}
// Then add in anything provided by handlers
$fields += migrate_handler_invoke_all('Entity', 'fields', $this->entityType, $this->bundle);
return $fields;
}
/**
* Deletes multiple entities.
*
* @param array $ids
* An array of entity ids of the entities to delete.
*/
public function bulkRollback(array $ids) {
migrate_instrument_start('entity_delete_multiple');
$this
->prepareRollback($ids);
$result = entity_delete_multiple($this->entityType, $ids);
$this
->completeRollback($ids);
migrate_instrument_stop('entity_delete_multiple');
return $result;
}
/**
* Imports a single entity.
*
* @param stdClass $entity
* Generic entity object, refilled with any fields mapped in the Migration.
* @param stdClass $row
* Raw source data object - passed through to prepare/complete handlers.
*
* @return array
* An array of key fields (entity id, and revision id if applicable) of the
* entity that was saved if successful. FALSE on failure.
*/
public function import(stdClass $entity, stdClass $row) {
$migration = Migration::currentMigration();
// Updating previously-migrated content?
if (isset($row->migrate_map_destid1)) {
if (isset($entity->{$this->id})) {
if ($entity->{$this->id} != $row->migrate_map_destid1) {
throw new MigrateException(t("Incoming id !id and map destination id !destid1 don't match", array(
'!id' => $entity->{$this->id},
'!destid1' => $row->migrate_map_destid1,
)));
}
}
else {
$entity->{$this->id} = $row->migrate_map_destid1;
}
}
elseif ($migration
->getSystemOfRecord() == Migration::SOURCE) {
unset($entity->{$this->id});
}
if (isset($row->migrate_map_destid2)) {
if (isset($entity->{$this->revision})) {
if ($entity->{$this->revision} != $row->migrate_map_destid2) {
throw new MigrateException(t("Incoming revision !id and map destination revision !destid2 don't match", array(
'!id' => $entity->{$this->revision},
'!destid2' => $row->migrate_map_destid2,
)));
}
}
else {
$entity->{$this->revision} = $row->migrate_map_destid2;
}
}
if ($migration
->getSystemOfRecord() == Migration::DESTINATION) {
if (!isset($entity->{$this->id})) {
throw new MigrateException(t('System-of-record is DESTINATION, but no destination id provided'));
}
// Load the entity that's being updated, update its values, then
// substitute the (fake) passed in entity with that one.
$old_entity = entity_load_single($this->entityType, $entity->{$this->id});
if (empty($old_entity)) {
throw new MigrateException(t("Failed to load entity of type %type and id %id", array(
'%type' => $this->entityType,
'%id' => $entity->{$this->id},
)));
}
// Prepare the entity to get the right array structure.
$this
->prepare($entity, $row);
foreach ($entity as $field => $value) {
$old_entity->{$field} = $entity->{$field};
}
$entity = $old_entity;
}
else {
// Create a real entity object, update its values with the ones we have
// and pass it along.
$new_entity = array();
if (!empty($this->bundle) && !empty($this->info['entity keys']['bundle'])) {
$new_entity[$this->info['entity keys']['bundle']] = $this->bundle;
}
$new_entity = entity_create($this->entityType, $new_entity);
foreach ($entity as $field => $value) {
$new_entity->{$field} = $entity->{$field};
}
// If a destination id exists, the entity is obviously not new.
if (!empty($new_entity->{$this->id}) && isset($new_entity->is_new)) {
unset($new_entity->is_new);
}
$entity = $new_entity;
$this
->prepare($entity, $row);
}
$updating = !empty($entity->{$this->id}) && empty($entity->is_new);
migrate_instrument_start('entity_save');
entity_save($this->entityType, $entity);
// It's probably not worth keeping the static cache around.
entity_get_controller($this->entityType)
->resetCache();
migrate_instrument_stop('entity_save');
$this
->complete($entity, $row);
if (isset($entity->{$this->id}) && $entity->{$this->id} > 0) {
if ($updating) {
$this->numUpdated++;
}
else {
$this->numCreated++;
}
$return = array(
$entity->{$this->id},
);
if (isset($entity->{$this->revision}) && $entity->{$this->revision} > 0) {
$return[] = array(
$entity->{$this->revision},
);
}
return $return;
}
return FALSE;
}
/**
* Clear the field cache after an import or rollback.
*/
public function postImport() {
field_cache_clear();
}
public function postRollback() {
field_cache_clear();
}
}
Classes
Name | Description |
---|---|
MigrateDestinationEntityAPI | Destination class implementing migration into entity types. |