123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275 |
- <?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.
- */
- static 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
- */
- static public 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();
- }
- }
|