I am importing users and data from csv with a Migrate Group. The initial user creation and some additional data in other tables in working fine.
I have read everything I can find on Google about Migrate and Addressfield, and some of it is 2 years old and confusing.
I also looked at addressfield.migrate.inc but I think it's not working because my table has a custom name? field_data_field_user_address
Actually there is also a table for field_data_field_address, containing data from Location module for nodes.
Anyway, I am getting a message when I migrate (with drush)
PHP Fatal error: Call to a member function import() on a non-object in /var/www/sitename/sites/all/modules/contrib/migrate/includes/migration.inc on line 696
I put a drush_print_r on that line
drush_print_r($this->destinationValues);drush_print_r($this->sourceValues);
the output of drush_print_r just before the error is
stdClass Object
(
[bundle] => user
[delta] => 0
[entity_id] => 483
[entity_type] => user
[field_user_address] => Array
(
[arguments] => Array
(
[administrative_area] =>
[first_name] =>
[last_name] =>
[locality] =>
[postal_code] =>
[premise] =>
[thoroughfare] =>
)
)
[language] => und
[revision_id] => 483
)
stdClass Object
(
[Row] => 1
[Type] => M
[Prefix] => Miss
[FirstName] => [actual first name here]
[MiddleName] =>
[LastName] => [actual last name here]
[StaffNotes] => site_members
[ColllegeAffiliation] => Alumna/nus
[ProfessionalAffiliation] =>
[AddressLine1] => [actual address here]
[AddressLine2] =>
[City] => New York
[State] => NY
[ZipCode] => 10028
[Country] => US
[TelephoneNumber] => [actual phone number here]
[Email] => [actual email here]
[Birthday] =>
[ID] => [actual ID here]
[Descriptor] => [A] A: EN07
[GraduationYear] => 2007
[SchoolAffiliation] => EN
[csvrownum] => 1
[migrate_map_hash] =>
)
My Migrate Table Class:
<?php
class AddressMigration extends MigrateMembers_Basic_Migration {
public function __construct($arguments) {
parent::__construct($arguments);
$this->description = 'Add data to field_data_field_user_address';
$this->dependencies = array('MigrateMembers');
$table_name = 'field_data_field_user_address';
$this->source = new MigrateSourceCSV(DRUPAL_ROOT . '/' . drupal_get_path('module', 'migrate_users') . '/data_sources/drupaluser_import_with_row_number-1.csv', $columns, array('header_rows' => 1));
$this->map = new MigrateSQLMap($this->machineName,
array('Row' => array( // this field is used to connect field to row in data source
'type' => 'varchar',
'length' => 6,
'not null' => TRUE,
'description' => t('Row in data source') // description never used
)
),
MigrateDestinationTable::getKeySchema($table_name)
);
// add uid from completed MigrateMembers migration
$this->addFieldMapping('entity_id', 'Row')->sourceMigration('MigrateMembers');
$this->addFieldMapping('revision_id', 'Row')->sourceMigration('MigrateMembers');
//see https://drupal.org/node/1996546 about migrating addressfield subfields
$this->addFieldMapping('field_user_address', $row->Country);
$this->addFieldMapping('field_user_address:administrative_area', 'State')->sourceMigration('MigrateMembers');
$this->addFieldMapping('field_user_address:locality', 'City')->sourceMigration('MigrateMembers');
$this->addFieldMapping('field_user_address:postal_code', 'ZipCode')->sourceMigration('MigrateMembers');
$this->addFieldMapping('field_user_address:thoroughfare', 'AddressLine1')->sourceMigration('MigrateMembers');
$this->addFieldMapping('field_user_address:premise', 'AddressLine2')->sourceMigration('MigrateMembers');
$this->addFieldMapping('field_user_address:first_name', 'FirstName')->sourceMigration('MigrateMembers');
$this->addFieldMapping('field_user_address:last_name', 'LastName')->sourceMigration('MigrateMembers');
// set some defaults from the schema
$this->addFieldMapping('delta')
->defaultValue("0");
$this->addFieldMapping('entity_type')
->defaultValue("user");
$this->addFieldMapping('bundle')
->defaultValue("user");
$this->addFieldMapping('language')
->defaultValue("und");
// Unmapped destination fields
$this->addUnmigratedDestinations(array('field_user_address:sub_administrative_area', 'field_user_address:dependent_locality', 'field_user_address:sub_premise', 'field_user_address:organisation_name', 'field_user_address:data', 'field_user_address:name_line'));
$this->removeFieldMapping('path');
$this->removeFieldMapping('pathauto');
}
public function prepareRow($row){
// convert 3 letter codes to ISO 3166-1 standard 2 letter codes http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2#Current_codes
// TODO:
// 1 - check for full list of country codes in old data
// 2 - many records with US addresses do not have a foreing country code, not the USA country code
// 3 - What are INO SAF SWD?
switch ($row->Country)
{
case 'AUS': // Austria
$row->Country = "AT";
break;
...long list, you get the idea
default :
$row->Country = "US";
break;
}
// tried to use arguments, although colon notation for subfields is preferred;
// didn't work anyway as $this->addFieldMapping('field_user_address', $row->Country)->arguments($arguments);
if (!empty($row->AddressLine1)) {
$arguments = array(
'country' => array($row->Country),
'administrative_area' => $row->State,
'locality' => $row->City,
'postal_code' => $row->Zipcode,
'thoroughfare' => $row->AddressLine1,
'premise' => $row->AddressLine2,
);
} else {
$arguments = NULL;
}
}
}
?>
and it's registered
<?php
function migrate_users_migrate_api() {
$api = array(
'api' => 2,
'groups' => array(
'MigrateMembersGroup' => array(
'title' => t('Import Member Users'),
),
),
'migrations' => array(
'MigrateMembers' => array(
'class_name' => 'MigrateMembers',
'group_name' => 'MigrateMembersGroup',
),
'GraduationYear' => array(
'class_name' => 'GraduationYearMigration',
'group_name' => 'MigrateMembersGroup',
),
'School' => array(
'class_name' => 'SchoolMigration',
'group_name' => 'MigrateMembersGroup',
),
'ID' => array(
'class_name' => 'IDMigration',
'group_name' => 'MigrateMembersGroup',
),
'Address' => array(
'class_name' => 'AddressMigration',
'group_name' => 'MigrateMembersGroup',
),
),
);
return $api;
?>
When I was trying to use the addressfield field handler:
<?php
'Address' => array(
'class_name' => 'AddressMigration',
'group_name' => 'MigrateMembersGroup',
'field handlers' => array('MigrateAddressFieldHandler'),
),
?>
Comments
Comment #1
decibel.places CreditAttribution: decibel.places commentedComment #2
decibel.places CreditAttribution: decibel.places commentedComment #3
seanrI think you actually want something like this:
Comment #4
decibel.places CreditAttribution: decibel.places commentedComment #5
decibel.places CreditAttribution: decibel.places commented@seanr I saw that code posted and $arguments are deprecated in migrate in favor of colon notation in the field mappings for sub-fields:
I made some progress though by removing ->sourceMigration('MigrateMembers'); from the field mappings:
and adjusting prepareRow (the preparation of $row->Country in that post helped, I knew from other sources that Country needs to be an array):
Now I am getting the values in $this->sourceValues in migrate.inc
and in the $row->Country becomes
but I am still getting the error
Comment #6
tenken CreditAttribution: tenken commentedRandom thought -- if this is a drupal Field, why are you using MigrateDestinationTable ? Shouldn't you be doing an Update to an Entity that is either a User or Profile? ...
Comment #7
decibel.places CreditAttribution: decibel.places commented@tenken
The user entity migration is already done. There is chain of five migration classes in the group, and this one populates the table with the user's addressfield including the uid created in the first migration.
Comment #8
decibel.places CreditAttribution: decibel.places commented[removed post because it was an unformatted version of #9]
Comment #9
decibel.places CreditAttribution: decibel.places commentedI gave up with the Addressfield Migration Class and decided to do a db_insert -- and it worked!
Not only works, but because I register the insert in the prepare() function of class SchoolMigration (where I was already using db queries) it also rolls back!
Comment #10
seanrI'm actually going to reopen this, as we need to make sure we have working documentation for this. I couldn't figure it out either, and while decibel.places solution may work, it is less than elegant and works outside the address mapping provided by Migrate. We need a testable solution for this.
Comment #11
mikeryanMigration support for addressfield is in the Migrate Extras module.
Comment #12
decibel.places CreditAttribution: decibel.places commented@mikeryan
yes, I was using Migrate Extras, but it did not work in my case - my solution is using Miigrate, not Migrate Extras
Comment #13
kenorb CreditAttribution: kenorb commentedNote to anybody reading the above code samples. Currently using arguments is deprecated, so use subfields instead, e.g.