OK, I moved this out from migrate_points and removed the submodule. I did not add this to hook_migrate_api() because it is still waiting on a userpoints patch from april. If people could help test that and get it committed, we'll test this and finish it up.

#441678: Use drupal_write_record(). Needed to be able to import transactions with migrate_extras

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

mikeryan’s picture

Version: master » 7.x-2.x-dev
Component: migrate_extras » Migrate Extras Features
Status: Postponed » Active

Moving request to V2.

Fidelix’s picture

+1.
I'm gonna need this ^^

StuartDH’s picture

Frankcarey, could you link to the April patch that needs testing, if it still needs testing, or are userpoints now ready to go?

Thanks

Stuart

mototribe’s picture

frankcarey, that's a patch from April of 2009?! Does that even apply to the D7 version?

Any other way to get the userpoints imported?

thanks

UWE

Andrey Zakharov’s picture

And there is no any chance to get this working?

mototribe’s picture

I ended up writing a custom script that would used the userpoints_userpointsapi() function to "import" the points.

Fidelix’s picture

mototribe, can you share?

mototribe’s picture



	//retrieve points from your import table
	$result = mysql_query("SELECT uid, points FROM ...", $con);


	if (!$result) {
		die('Invalid query: ' . mysql_error());
	}
	
	//loop over the results
	while ($row = mysql_fetch_array($result, MYSQL_BOTH)) {
		$uid = $row['uid'];
		$points = $row['points'];

		$params = array (
		  'uid' => $uid,
		  'points' => $points,
		  'description' => '....'
		);
		$ret = userpoints_userpointsapi($params); 
	}

charliekolev’s picture

Please, somebody to help me.
I whant to migrate XML content to custom nodes. It's ok. The question is how to get the id whitch is an atribute.
xml: (i put () instad of angle brackets)
(main)
(aaa id='1')
(bbb)...(/bbb)
(ccc)...(/ccc)
(/aaa)
(/main)

what about:
$item_xpath = '/main/aaa';
$item_ID_xpath = '@id ';
$items_class = new MigrateItemsXML($items_url, $item_xpath, $item_ID_xpath);

also:

$this->map = new MigrateSQLMap($this->machineName,
array(
'id' => array( //****WHAT TO DO WITH THE ID
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
)
),
MigrateDestinationRole::getKeySchema()
);

HEEEELP!

mikeryan’s picture

Title: Userpoints Integration » Migration support for User Points
Project: Migrate Extras » User Points
Component: Migrate Extras Features » Code: userpoints

Migration support for a contrib module would best go into that module.

derhasi’s picture

Version: 7.x-2.x-dev » 7.x-1.0
Assigned: frankcarey » Unassigned
Status: Active » Needs review
FileSize
5.34 KB

I needed migration support for a project of mine, so I wrote a patch implementing basic migration for Userpoints 1.0

Patch attached ;)

Berdir’s picture

Version: 7.x-1.0 » 7.x-1.x-dev

Thanks, looks good, can you improve these comments a bit and then I'm happy to commit this.

+++ b/userpoints.migrate.incundefined
@@ -0,0 +1,145 @@
+  public function __toString() {
+    return t('userpoints');

I'm not exactly sure where this is displayed, be we usually use 'User Points' in user facing strings.

Also, this and the one below should have a simple docblock. According to the current coding standards, that would be Overrides/Implements Class/Interface::method().

+++ b/userpoints.migrate.incundefined
@@ -0,0 +1,145 @@
+   * Importing given item as userpoints transaction.
+   *
+   * @param stdClass $entity
+   * @param stdClass $row
+   * @return array|bool
+   */
+  function import(stdClass $entity, stdClass $row) {

I assume this is the implementation of a interface method, then the @params and @return isn't necessary and it should just state Implements ... as described above.

Same for those below.

MXT’s picture

Any news on this?

marcus178’s picture

I have applied this patch but the migration doesn't appear in the Migrate UI. Is there something else that needs doing for this to work?

scottsawyer’s picture

I am attempting to migrate user points with the method described by @mototribe, but it's not working for me. I am on 7.x-1.0, I have a function that is called in my complete() for the user migration class that ( successfully ) pulls the user's points from my D6 userpoints_txn table, sets the parameters for each record in an array.

However, as soon as I loop over my array of user points and call userpoints_userpointsapi($params), it completely fails. It stops the foreach, gives no error or message.

This is what my setup looks like:

function mymigration_userpoints($new_uid, $old_uid) {
  $query = Database::getConnection('default', 'for_migration') // this is the connection to my old db, this part works.
    ->select('userpoints_txn', 'up')
    ->fields('up', array('points', 'time_stamp', 'description', 'tid'))
    ->condition('up.uid', $old_uid, '=')
    ->condition('up.status', '0', '=');
    $points_result = $query->execute()->fetchAll();  // so far so good, I am getting my old records just fine.
   //print_r($points_result);  // when uncommented, it gives an array of results that look correct
   // now I want to loop over the results
  foreach ($points_result as $points_data) {
      $time_stamp = $points_data->time_stamp;
      $points = $points_data->points;
      $description = $points_data->description;
      $tid = mapValues('points', $points_data->tid);  // this is supurfluous, it merely maps the old tid to my new tid, works.
        $params = array(
          'uid' => $new_uid,
          'points' => $points,
          'description' => t('Migrated Giving Points'),
          'tid' => $tid,
           'moderate' => FALSE,
        );
        // print_r($params);  // when uncommented, gives only the first result in the loop, because it dies when the next part is called
        $ret = userpoints_userpointsapi($params);       
  }
    
  return;
}

I have attempted to break down my params array to the bear minimum, even just 'uid' and 'points', but it still fails, and fails hard.

$params = array(
  'uid' => $new_uid,
 'points' => 10,
);

I am using very similar code in another module, for scoring Quiz ( I needed some more flexibility for the points ). I use the same params array, the same call to userpoints_userpointsapi($params). I even tried hard coding the values in the array. Nothing works for me.

To summarize, in my custom migration, anytime I call userpoints_userpointsapi(), it completely stops propagation, does not add points, does not pass "Go", does not collect $200. Using 7.x-1.0. Works in other modules.

Any ideas of how I am doing this wrong?

hussainweb’s picture

Issue summary: View changes
FileSize
2.13 KB
5.57 KB

The patch in #11 works, for the most part. I am able to import and rollback userpoints transactions fine with two issues.

  • MigrateDestinationUserpoints::complete is defined but never called. This results in any complete callback in the migration class itself to not be called.
  • The rollback would delete the rows in userpoints_txn table but not update userpoints or userpoints_total tables.

Both of the issues are fixed in the attached patch.

To address @Berdir's comments in #12:

  1. Regarding __toString(): The convention across many of the destination handlers is to use the lowercase representation of the type being imported. e.g. node (article) or comment (comment_node_event) or votingapi.
  2. Regarding coding standards: I have improved the docblock just a little. Can you give me a link to the coding standards you are referring to so that I can take a quick look and check if this applies here? I ask because the convention in other MigrateDestination classes is to give a description (since it could be importing anything).
hussainweb’s picture

FileSize
6.34 KB

I'm updating the patch with support to import updates. The previous patch will not process updates correctly, creating new point transactions even for updates.

estoyausente’s picture

Status: Needs review » Reviewed & tested by the community

I used it for migrate 17k of user points in different categories (between two drupal 7 sites) and it run perfectly.

It is my migration code and it worked perfectly:

class CustomUserpointMigration extends Migration {

  public function __construct($arguments){
    parent::__construct($arguments);
    $this->dependencies = array('User');

/** Source fields */
    $query = Database::getConnection('default', $arguments['source_connection'])
      ->select('userpoints_txn', 'up')
      ->fields('up', array('txn_id', 'uid', 'points', 'description','tid', 'operation', 'entity_type'));

    $this->source = new MigrateSourceSQL($query);

/** destination */
    $this->destination = new MigrateDestinationUserpoints(
      $arguments['destination_type'],
      array('host_entity_type' => 'node')
    ); 

    $this->map = new MigrateSQLMap($this->machineName,
      array(
        'txn_id' => array(
          'type' => 'int',
          'not null' => true,
        ),
      ),
      MigrateDestinationUserpoints::getKeySchema()
    );

/** Basic fields */
    $unchangedFields = array(
      'operation',
      'description',
      'points',
      'entity_type',
    );

    $this->addSimpleMappings($unchangedFields);

/** Fields with relationships */
    $this->addFieldMapping('uid', 'uid')
      ->sourceMigration('User');

    $this->addFieldMapping('tid', 'tid')
      ->sourceMigration('Userpoints_taxonomy');

//In this case, any userpoint value has expiry date.
    $this->addFieldMapping('expirydate')
      ->defaultValue(0);
  }

}

I tested rollback process and it works ok too.

heddn’s picture

RTBC yet again.

The example in #17 didn't quite work for me. I'm migrating from a separate D6 source DB. So I used d2d as a dependency and add map_joinable => TRUE to avoid PDO exceptions.

class ExampleUserpointsMigration extends DrupalMigration {

  public function __construct($arguments){
    parent::__construct($arguments);
    $this->dependencies = array(
      'CommonsUser',
    );

    $this->softDependencies = array(
      'UserPointsTaxonomy',
    );

    $fields = array(
      'operation',
      'description',
      'points',
      'entity_type',
      'entity_id',
      'time_stamp',
      'expirydate',
      'reference',
    );

    // Source fields.
    $this->source = new MigrateSourceSQL($this->query(), $fields + array('uid', 'tid'), NULL, array('map_joinable' => FALSE));

    // Destination.
    $this->destination = new MigrateDestinationUserpoints();

    $this->map = new MigrateSQLMap($this->machineName,
      array(
        'txn_id' => array(
          'type' => 'int',
          'not null' => true,
        ),
      ),
      MigrateDestinationUserpoints::getKeySchema()
    );

    // Basic fields.
    $this->addSimpleMappings($fields);

    // Fields with source migrations.
    $this->addFieldMapping('uid', 'uid')
      ->sourceMigration('CommonsUser');

    $this->addFieldMapping('tid', 'tid')
      ->sourceMigration('UserPointsTaxonomy');
  }

  /**
   * Query for userpoints.
   *
   * @return QueryConditionInterface
   */
  protected function query() {
    $query = Database::getConnection('default', $this->sourceConnection)
      ->select('userpoints_txn', 'up')
      ->fields('up');

    return $query;
  }
}
function example_migrate_api() {
$api['migrations']['ExampleUserpoints'] = array(
    'class_name' => 'ExampleUserpointsMigration',
    'description' => t('Migration of userpoints'),
    'source_connection' => 'legacy',
    'source_version' => 6,
    'group_name' => 'example',
  );

  return $api;
}

  • Berdir committed 80e04e7 on 7.x-1.x
    Issue #689702 by hussainweb, derhasi: Migration support for User Points
    
Berdir’s picture

Version: 7.x-1.x-dev » 7.x-2.x-dev

Thanks, committed and pushed. Needs to be ported to 7.x-2.x.

Berdir’s picture

Status: Reviewed & tested by the community » Patch (to be ported)
Media Crumb’s picture

@heddn

Is there anyway you can provide your code as a release? I have a project that requires a migrations from D6 to D7 and Im also using the d2d module along with the d2d UI. Would love any help or guidance on the steps needed to make this happen