You are here

class MigrateDestinationEntityAPI in Migrate Extras 7.2

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.

Hierarchy

Expanded class hierarchy of MigrateDestinationEntityAPI

File

./entity_api.inc, line 19
Support for entity types implementing the Entity API.

View source
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();
  }

}

Members

Namesort descending Modifiers Type Description Overrides
MigrateDestination::$numCreated protected property Maintain stats on the number of destination objects created or updated.
MigrateDestination::$numUpdated protected property
MigrateDestination::getCreated public function
MigrateDestination::getUpdated public function
MigrateDestination::resetStats public function Reset numCreated and numUpdated back to 0.
MigrateDestinationEntity::$bundle protected property The bundle (node type, vocabulary, etc.) of the destination.
MigrateDestinationEntity::$entityType protected property The entity type (node, user, taxonomy_term, etc.) of the destination.
MigrateDestinationEntity::$language protected property Default language for text fields in this destination.
MigrateDestinationEntity::$textFormat protected property Default input format for text fields in this destination.
MigrateDestinationEntity::array_flatten public static function Flattens an array of allowed values.
MigrateDestinationEntity::complete public function Give handlers a shot at modifying the object (or taking additional action) after saving it.
MigrateDestinationEntity::completeRollback public function Give handlers a shot at cleaning up after an entity has been rolled back.
MigrateDestinationEntity::fieldAttachValidate public static function Perform field validation against the field data in an entity. Wraps field_attach_validate to handle exceptions cleanly and provide maximum information for identifying the cause of validation errors.
MigrateDestinationEntity::getBundle public function
MigrateDestinationEntity::getEntityType public function
MigrateDestinationEntity::getLanguage public function
MigrateDestinationEntity::getTextFormat public function
MigrateDestinationEntity::prepare public function Give handlers a shot at modifying the object before saving it.
MigrateDestinationEntity::prepareRollback public function Give handlers a shot at cleaning up before an entity has been rolled back.
MigrateDestinationEntity::__toString public function Derived classes must implement __toString(). Overrides MigrateDestination::__toString
MigrateDestinationEntityAPI::$id protected property Name of the entity id key (for example, nid for nodes).
MigrateDestinationEntityAPI::$info protected property Info about the current entity type.
MigrateDestinationEntityAPI::$revision protected property Name of the entity revision key (for example, vid for nodes).
MigrateDestinationEntityAPI::bulkRollback public function Deletes multiple entities.
MigrateDestinationEntityAPI::fields public function Returns a list of fields available to be mapped for entities attached to a particular bundle. Overrides MigrateDestination::fields
MigrateDestinationEntityAPI::getKeySchema public function Gets the schema for the base key(s) of an entity type.
MigrateDestinationEntityAPI::import public function Imports a single entity. Overrides MigrateDestination::import
MigrateDestinationEntityAPI::options public static function Return an options array (language, text_format), used for creating fields.
MigrateDestinationEntityAPI::postImport public function Clear the field cache after an import or rollback.
MigrateDestinationEntityAPI::postRollback public function
MigrateDestinationEntityAPI::__construct public function Basic initialization Overrides MigrateDestinationEntity::__construct