Issue #1009708 by mikeryan: Added role destination plugin
authorMike Ryan
Wed, 11 May 2011 16:06:28 +0000 (12:06 -0400)
committerMike Ryan
Wed, 11 May 2011 16:06:28 +0000 (12:06 -0400)
CHANGELOG.txt
migrate_example/beer.inc
migrate_example/migrate_example.install
migrate_example/wine.inc
migrate_example/wine.install.inc
migrate_example/xml/positions.xml [new file with mode: 0644]
plugins/destinations/user.inc
tests/plugins/destinations/comment.test
tests/plugins/destinations/node.test
tests/plugins/destinations/user.test
tests/plugins/sources/xml.test

index 6e45e3e..714ba49 100644 (file)
@@ -11,6 +11,7 @@ should now be prepare($entity, stdClass $row).
 Features and enhancements
 - #1017246 - Added support for running migrations from the dashboard.
 - #1004812 - Added schema-driven table destination plugin.
+- #1009708 - Added role destination plugin.
 - #1005090 - Modified filefield property import to use JSON input.
 - #730980 - Added more detailed reporting on import.
 - #1142384 - Extended file field support to copy from remote URLs.
index 7aa3e24..969863d 100644 (file)
@@ -199,7 +199,7 @@ class BeerUserMigration extends BasicExampleMigration {
     // value is provided in addition to a source field, the default value will
     // be applied to any rows where the source field is empty or NULL.
     $this->addFieldMapping('roles')
-         ->defaultValue(drupal_map_assoc(array(2)));
+         ->defaultValue(2);
     $this->addFieldMapping('field_migrate_example_gender', 'sex');
 
     // The source field has beer names separated by a pipe character ('|'). By
index c2d96ec..b5328be 100644 (file)
@@ -193,3 +193,31 @@ function migrate_example_update_7006() {
   $ret[] = t('Added sample data for table destinations.');
   return $ret;
 }
+
+/**
+ * Add data for testing/demonstrating roles.
+ */
+function migrate_example_update_7007() {
+  $ret = array();
+  db_add_field('migrate_example_wine_account', 'positions', array(
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => FALSE,
+        'description' => 'Positions held',
+    )
+  );
+  $query = db_update('migrate_example_wine_account')
+    ->fields(array('positions' => '5'))
+    ->condition('accountid', 1)
+    ->execute();
+  db_update('migrate_example_wine_account')
+    ->fields(array('positions' => '18'))
+    ->condition('accountid', 3)
+    ->execute();
+  db_update('migrate_example_wine_account')
+    ->fields(array('positions' => '5,18'))
+    ->condition('accountid', 9)
+    ->execute();
+  $ret[] = t('Added positions field to migrate_example_wine_account table.');
+  return $ret;
+}
index bc92b71..305b51d 100644 (file)
@@ -179,11 +179,54 @@ class WineFileMigration extends AdvancedExampleMigration {
   }
 }
 
+class WineRoleMigration extends XMLMigration {
+  public function __construct() {
+    parent::__construct();
+    $this->description = t('XML feed (multi items) of roles (positions)');
+    $this->softDependencies = array('WineFile');
+
+    // There isn't a consistent way to automatically identify appropriate "fields"
+    // from an XML feed, so we pass an explicit list of source fields
+    $fields = array(
+      'name' => t('Position name'),
+    );
+
+    // The source ID here is the one retrieved from each data item in the XML file, and
+    // used to identify specific items
+    $this->map = new MigrateSQLMap($this->machineName,
+      array(
+        'sourceid' => array(
+          'type' => 'int',
+          'unsigned' => TRUE,
+          'not null' => TRUE,
+        )
+      ),
+      MigrateDestinationRole::getKeySchema()
+    );
+
+    // This can also be an URL instead of a file path.
+    $xml_folder = DRUPAL_ROOT . '/' . drupal_get_path('module', 'migrate_example') . '/xml/';
+    $items_url = $xml_folder . 'positions.xml';
+    $item_xpath = '/positions/position';  // relative to document
+    $item_ID_xpath = 'sourceid';         // relative to item_xpath and gets assembled
+                                         // into full path /producers/producer/sourceid
+
+    $items_class = new MigrateItemsXML($items_url, $item_xpath, $item_ID_xpath);
+    $this->source = new MigrateSourceMultiItems($items_class, $fields);
+
+    $this->destination = new MigrateDestinationRole();
+
+    $this->addFieldMapping('name', 'name')
+         ->xpath('name');
+    $this->addUnmigratedDestinations(array('weight'));
+  }
+}
+
 class WineUserMigration extends AdvancedExampleMigration {
   public function __construct() {
     parent::__construct();
     $this->description = t('Wine Drinkers of the world');
-    $this->dependencies = array('WinePrep', 'WineFile');
+    $this->dependencies = array('WinePrep', 'WineFile', 'WineRole');
     $this->map = new MigrateSQLMap($this->machineName,
         array('accountid' => array(
                 'type' => 'int',
@@ -197,7 +240,7 @@ class WineUserMigration extends AdvancedExampleMigration {
     $query = db_select('migrate_example_wine_account', 'wa')
              ->fields('wa', array('accountid', 'status', 'posted', 'name',
                 'password', 'mail', 'last_access', 'last_login',
-                'original_mail', 'sig', 'sex', 'imageid'));
+                'original_mail', 'sig', 'sex', 'imageid', 'positions'));
     $this->source = new MigrateSourceSQL($query);
     $this->destination = new MigrateDestinationUser();
 
@@ -210,8 +253,9 @@ class WineUserMigration extends AdvancedExampleMigration {
     $this->addFieldMapping('login', 'last_login')
          ->description('See prepare method');
     $this->addFieldMapping('pass', 'password');
-    $this->addFieldMapping('roles')
-         ->defaultValue(drupal_map_assoc(array(2)));
+    $this->addFieldMapping('roles', 'positions')
+         ->separator(',')
+         ->sourceMigration('WineRole');
     $this->addFieldMapping('signature', 'sig');
     $this->addFieldMapping('signature_format')
          ->defaultValue($this->basicFormat->format);
index 0f3d260..f62aaaa 100644 (file)
@@ -513,6 +513,12 @@ function migrate_example_wine_schema_account() {
         'not null' => FALSE,
         'description' => 'Image ID',
       ),
+      'positions' => array(
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => FALSE,
+        'description' => 'Positions held',
+      ),
     ),
     'primary key' => array('accountid'),
   );
@@ -1002,19 +1008,19 @@ function migrate_example_wine_data_producer() {
 
 function migrate_example_wine_data_account() {
   $fields = array('accountid', 'status', 'posted', 'last_access', 'last_login',
-    'name', 'sex', 'password', 'mail', 'original_mail', 'sig', 'imageid');
+    'name', 'sex', 'password', 'mail', 'original_mail', 'sig', 'imageid', 'positions');
   $query = db_insert('migrate_example_wine_account')
     ->fields($fields);
   $data = array(
     array(1, 1, '2010-03-30 10:31:05', '2010-04-30 18:25:24', '2010-04-30 14:01:02',
       'darren', 'M', 'dpass', 'ddarren@example.com', 'darren@example.com',
-      'All about the Australians', NULL),
+      'All about the Australians', NULL, '5'),
     array(3, 0, '2007-03-15 10:31:05', '2007-06-10 04:11:38', '2007-06-10 04:11:38',
       'emily', 'F', 'insecure', 'emily@example.com', 'emily@example.com',
-      'Sommelier to the stars', NULL),
+      'Sommelier to the stars', NULL, '18'),
     array(9, 1, '2004-02-29 10:31:05', '2004-02-29 10:31:05', '2004-02-29 10:31:05',
       'fonzie', NULL, 'bike', 'thefonz@example.com', 'arthur@example.com',
-      'Aaay!', 1),
+      'Aaay!', 1, '5,18'),
   );
   foreach ($data as $row) {
     $query->values(array_combine($fields, $row));
diff --git a/migrate_example/xml/positions.xml b/migrate_example/xml/positions.xml
new file mode 100644 (file)
index 0000000..bd6517c
--- /dev/null
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<positions>
+  <position>
+    <sourceid>5</sourceid>
+    <name>Taster</name>
+  </position>
+  <position>
+    <sourceid>18</sourceid>
+    <name>Vintner</name>
+  </position>
+</positions>
index e291499..2e2b7ce 100644 (file)
@@ -129,6 +129,12 @@ class MigrateDestinationUser extends MigrateDestinationEntity {
       $old_account = $account;
     }
 
+    // Role arrays need to be keyed by the role id, which isn't how the data
+    // naturally comes in. Fix them up.
+    if (is_array($account->roles)) {
+      $account->roles = drupal_map_assoc($account->roles);
+    }
+
     $this->prepare($account, $row);
 
     if (isset($account->uid) && !(isset($account->is_new) && $account->is_new)) {
@@ -157,3 +163,13 @@ class MigrateDestinationUser extends MigrateDestinationEntity {
     return $return;
   }
 }
+
+class MigrateDestinationRole extends MigrateDestinationTable {
+  public function __construct() {
+    parent::__construct('role');
+  }
+
+  static public function getKeySchema() {
+    return MigrateDestinationTable::getKeySchema('role');
+  }
+}
index d69ae62..6c971f7 100644 (file)
@@ -33,6 +33,14 @@ class MigrateCommentUnitTest extends DrupalWebTestCase {
     $result = $migration->processImport();
     $this->assertEqual($result, Migration::RESULT_COMPLETED,
       t('File import returned RESULT_COMPLETED'));
+    $migration = Migration::getInstance('WineRole');
+    $result = $migration->processImport();
+    $this->assertEqual($result, Migration::RESULT_COMPLETED,
+      t('Role import returned RESULT_COMPLETED'));
+    $migration = Migration::getInstance('WineRole');
+    $result = $migration->processImport();
+    $this->assertEqual($result, Migration::RESULT_COMPLETED,
+      t('Role import returned RESULT_COMPLETED'));
     $migration = Migration::getInstance('WineUser');
     $result = $migration->processImport();
     $this->assertEqual($result, Migration::RESULT_COMPLETED,
index f9d65cd..5e445fc 100644 (file)
@@ -33,6 +33,10 @@ class MigrateNodeUnitTest extends DrupalWebTestCase {
     $result = $migration->processImport();
     $this->assertEqual($result, Migration::RESULT_COMPLETED,
       t('File import returned RESULT_COMPLETED'));
+    $migration = Migration::getInstance('WineRole');
+    $result = $migration->processImport();
+    $this->assertEqual($result, Migration::RESULT_COMPLETED,
+      t('Role import returned RESULT_COMPLETED'));
     $migration = Migration::getInstance('WineUser');
     $result = $migration->processImport();
     $this->assertEqual($result, Migration::RESULT_COMPLETED,
index 2021814..de0c132 100644 (file)
@@ -24,6 +24,20 @@ class MigrateUserUnitTest extends DrupalWebTestCase {
     $result = $migration->processImport();
     $this->assertEqual($result, Migration::RESULT_COMPLETED,
       t('File import returned RESULT_COMPLETED'));
+    $migration = Migration::getInstance('WineRole');
+    $result = $migration->processImport();
+    $this->assertEqual($result, Migration::RESULT_COMPLETED,
+      t('Role import returned RESULT_COMPLETED'));
+    // Confirm both roles were successfully imported
+    $result = db_select('role', 'r')
+                ->fields('r', array('rid', 'name'))
+                ->condition('name', array('Taster', 'Vintner'), 'IN')
+                ->execute();
+    $roles = array();
+    foreach ($result as $row) {
+      $roles[$row->name] = $row->rid;
+    }
+    $this->assertEqual(count($roles), 2, t('Both roles imported'));
     $migration = Migration::getInstance('WineUser');
     $result = $migration->processImport();
     $this->assertEqual($result, Migration::RESULT_COMPLETED,
@@ -62,6 +76,8 @@ class MigrateUserUnitTest extends DrupalWebTestCase {
     $this->assertEqual($users['darren']->status, $rows['darren']->status,
       t('Statuses match'));
     $this->assertNotNull($users['darren']->roles[2], t('Authenticated role'));
+    $this->assertNotNull($users['darren']->roles[$roles['Taster']], t('Taster role'));
+    $this->assertFalse(isset($users['darren']->roles[$roles['Vintner']]), t('No Vintner role'));
     $this->assertEqual($users['darren']->created, strtotime($rows['darren']->posted),
       t('Created times match'));
     $this->assertEqual($users['darren']->access, strtotime($rows['darren']->last_access),
@@ -85,6 +101,8 @@ class MigrateUserUnitTest extends DrupalWebTestCase {
     $this->assert(is_object($users['fonzie']->picture) &&
                   $users['fonzie']->picture->filename == 'DA-individual.thumbnail.png',
       t('Picture migrated'));
+    $this->assertNotNull($users['fonzie']->roles[$roles['Taster']], t('Taster role'));
+    $this->assertNotNull($users['fonzie']->roles[$roles['Vintner']], t('Vintner role'));
 
     // TODO: Theme, timezone, language
 
index f5ba918..833936d 100644 (file)
@@ -25,6 +25,10 @@ class MigrateXMLUnitTest extends DrupalWebTestCase {
     $result = $migration->processImport();
     $this->assertEqual($result, Migration::RESULT_COMPLETED,
       t('File import returned RESULT_COMPLETED'));
+    $migration = Migration::getInstance('WineRole');
+    $result = $migration->processImport();
+    $this->assertEqual($result, Migration::RESULT_COMPLETED,
+      t('Role import returned RESULT_COMPLETED'));
     $migration = Migration::getInstance('WineUser');
     $result = $migration->processImport();
     $this->assertEqual($result, Migration::RESULT_COMPLETED,