wine.inc in Migrate 6.2
Same filename and directory in other branches
Advanced migration examples. These serve two purposes:
1. To demonstrate some of the more advanced usages of the Migrate module. Search for "TIP:" below for features not found in the basic example. 2. To provide thorough test cases for the simpletest suite.
File
migrate_example/wine.incView source
<?php
/**
* @file
* Advanced migration examples. These serve two purposes:
*
* 1. To demonstrate some of the more advanced usages of the Migrate module.
* Search for "TIP:" below for features not found in the basic example.
* 2. To provide thorough test cases for the simpletest suite.
*
*/
/**
* Abstract intermediate class holding common settings.
*/
abstract class AdvancedExampleMigration extends DynamicMigration {
public $basicFormat;
public function __construct() {
// TIP: Migrations can be organized into groups. In this case, all the migrations
// derived from AdvancedExampleMigration will be part of the 'wine' group.
// This enables us to easily run just the wine example migrations:
// drush migrate-import --group=wine
// The second argument to MigrateGroup::getInstance is an array of groups
// which should come before this when viewing migration statuses, or running
// migration operations using --all. Since the beer migrations in this module
// did not specify a group, it is in the 'default' group, so this constructor
// indicates that the wine migrations come after the beer migrations.
parent::__construct(MigrateGroup::getInstance('wine', array(
'default',
)));
$this->team = array(
new MigrateTeamMember('Jack Kramer', 'jkramer@example.com', t('Taster')),
new MigrateTeamMember('Linda Madison', 'lmadison@example.com', t('Winemaker')),
);
$this->issuePattern = 'http://drupal.org/node/:id';
// A format of our own, for testing migration of formats
$formats = filter_formats();
foreach ($formats as $format) {
if ($format->name == 'Migrate example format') {
$this->basicFormat = $format->format;
break;
}
}
}
}
/**
* TIP: While usually you'll create true migrations - processes that copy data
* from some source into Drupal - you can also define processing steps for either
* the import or rollback stages that take other actions. In this case, we want
* to disable auto_nodetitle while the migration steps run. We'll re-enable it
* over in WineFinishMigration.
*/
class WinePrepMigration extends MigrationBase {
// Track whether the auto_nodetitle was originally enabled so we know whether
// to re-enable it. This is public so WineFinishMigration can reference it.
public static $wasEnabled = FALSE;
public function __construct() {
// Because we're derived directly from migrationBase rather than AdvancedExampleMigration,
// we must specify the group again here.
parent::__construct(MigrateGroup::getInstance('wine', array(
'default',
)));
$this->description = t('If auto_nodetitle is present, disable it for the duration');
}
// Define isComplete(), returning a boolean, to indicate whether dependent
// migrations may proceed
public function isComplete() {
// If Auto Node Title is disabled, other migrations are free to go
if (module_exists('auto_nodetitle')) {
return FALSE;
}
else {
return TRUE;
}
}
// Implement any action you want to occur during an import process in an
// import() method (alternatively, if you have an action which you want to
// run during rollbacks, define a rollback() method).
public function import() {
if (module_exists('auto_nodetitle')) {
self::$wasEnabled = TRUE;
module_disable(array(
'auto_nodetitle',
));
self::displayMessage(t('Disabled auto_nodetitle module'), 'success');
}
else {
self::$wasEnabled = FALSE;
self::displayMessage(t('Auto_nodetitle is already disabled'), 'success');
}
// Must return one of the MigrationBase RESULT constants
return MigrationBase::RESULT_COMPLETED;
}
}
// The term migrations are very similar - implement the commonalities here
abstract class WineTermMigration extends AdvancedExampleMigration {
public function __construct($type, $vocabulary_name, $description) {
parent::__construct();
$this->description = $description;
$this->dependencies = array(
'WinePrep',
);
$this->map = new MigrateSQLMap($this->machineName, array(
'categoryid' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
),
), MigrateDestinationTerm::getKeySchema());
$query = db_select('migrate_example_wine_categories', 'wc')
->fields('wc', array(
'categoryid',
'name',
'details',
'category_parent',
'ordering',
))
->condition('type', $type)
->orderBy('category_parent', 'ASC');
$this->source = new MigrateSourceSQL($query);
$this->destination = new MigrateDestinationTerm($vocabulary_name);
// Mapped fields
$this
->addFieldMapping('name', 'name');
$this
->addFieldMapping('description', 'details');
$this
->addFieldMapping('parent', 'category_parent')
->sourceMigration($this
->getMachineName());
$this
->addFieldMapping('weight', 'ordering');
$this
->addFieldMapping('format')
->defaultValue($this->basicFormat);
// Unmapped source fields
// Unmapped destination fields
$this
->addFieldMapping('parent_name')
->issueGroup(t('DNM'));
}
}
class WineVarietyMigration extends WineTermMigration {
public function __construct() {
parent::__construct('variety', 'Migrate Example Wine Varieties', t('Migrate varieties from the source database to taxonomy terms'));
}
}
class WineRegionMigration extends WineTermMigration {
public function __construct() {
parent::__construct('region', 'Migrate Example Wine Regions', t('Migrate regions from the source database to taxonomy terms'));
}
}
class WineBestWithMigration extends WineTermMigration {
public function __construct() {
parent::__construct('best_with', 'Migrate Example Wine Best With', t('Migrate "Best With" from the source database to taxonomy terms'));
}
}
class WineRoleMigration extends XMLMigration {
public function __construct() {
parent::__construct(MigrateGroup::getInstance('wine', array(
'default',
)));
$this->description = t('XML feed (multi items) of roles (positions)');
// TIP: Regular dependencies, besides enforcing (in the absence of --force)
// the run order of migrations, affect the sorting of migrations on display.
// You can use soft dependencies to affect just the display order when the
// migrations aren't technically required to run in a certain order. In this
// case, we want the role migration to appear after the file migration.
$this->softDependencies = array(
'WineBestWith',
);
// 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());
// IMPORTANT: Do not try this at home! We have included importable files
// with the migrate_example module so it can be very simply installed and
// run, but you should never include any data you want to keep private
// (especially user data like email addresses, phone numbers, etc.) in the
// module directory. Your source data should be outside of the webroot, and
// should not be anywhere where it may get committed into a revision control
// system.
// This can also be an URL instead of a file path.
$xml_folder = 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',
'WineRole',
);
$this->map = new MigrateSQLMap($this->machineName, array(
'accountid' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'description' => 'Account ID.',
),
), MigrateDestinationUser::getKeySchema());
$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',
'positions',
));
$this->source = new MigrateSourceSQL($query);
$this->destination = new MigrateDestinationUser();
// Mapped fields
$this
->addSimpleMappings(array(
'name',
'status',
'mail',
));
$this
->addFieldMapping('created', 'posted');
$this
->addFieldMapping('access', 'last_access');
$this
->addFieldMapping('login', 'last_login');
$this
->addFieldMapping('pass', 'password');
$this
->addFieldMapping('roles', 'positions')
->separator(',')
->sourceMigration('WineRole');
$this
->addFieldMapping('signature', 'sig');
$this
->addFieldMapping('signature_format')
->defaultValue($this->basicFormat);
$this
->addFieldMapping('init', 'original_mail');
// Unmapped source fields
// Unmapped destination fields
$this
->addUnmigratedDestinations(array(
'theme',
'timezone',
'language',
'picture',
'role_names',
));
}
}
class WineProducerMigration extends AdvancedExampleMigration {
public function __construct() {
parent::__construct();
$this->description = t('Wine producers of the world');
$this->dependencies = array(
'WineRegion',
'WineUser',
);
$this->map = new MigrateSQLMap($this->machineName, array(
'producerid' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'alias' => 'p',
),
), MigrateDestinationNode::getKeySchema());
$query = db_select('migrate_example_wine_producer', 'p')
->fields('p', array(
'producerid',
'name',
'body',
'excerpt',
'accountid',
));
// Region term is singletons, handled straighforwardly
$query
->leftJoin('migrate_example_wine_category_producer', 'reg', "p.producerid = reg.producerid");
$query
->addField('reg', 'categoryid', 'region');
$this->source = new MigrateSourceSQL($query);
$this->destination = new MigrateDestinationNode('migrate_example_producer');
// Mapped fields
$this
->addFieldMapping('title', 'name')
->description(t('Mapping producer name in source to node title'));
$this
->addFieldMapping('uid', 'accountid')
->sourceMigration('WineUser')
->defaultValue(1);
$this
->addFieldMapping('Migrate Example Wine Regions', 'region')
->sourceMigration('WineRegion')
->arguments(array(
'source_type' => 'tid',
));
$this
->addFieldMapping('body', 'body');
$this
->addFieldMapping('teaser', 'excerpt');
$this
->addFieldMapping('sticky')
->defaultValue(0);
// No unmapped source fields
// Unmapped destination fields
$this
->addUnmigratedDestinations(array(
'is_new',
'name',
'created',
'changed',
'status',
'promote',
'revision',
'language',
));
}
}
/**
* TIP: An example of importing from an XML feed. See the files in the xml
* directory - index.xml contains a list of IDs to import, and <id>.xml
* is the data for a given producer.
*
* Note that, if basing a migration on an XML source, you need to derive it
* from XMLMigration instead of Migration.
*/
class WineProducerXMLMigration extends XMLMigration {
public function __construct() {
parent::__construct(MigrateGroup::getInstance('wine', array(
'default',
)));
$this->description = t('XML feed of wine producers of the world');
$this->dependencies = array(
'WineRegion',
'WineUser',
);
// 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('Producer name'),
'description' => t('Description of producer'),
'authorid' => t('Numeric ID of the author'),
'region' => t('Name of region'),
);
// The source ID here is the one retrieved from the XML listing file, and
// used to identify the specific item's file
$this->map = new MigrateSQLMap($this->machineName, array(
'sourceid' => array(
'type' => 'varchar',
'length' => 4,
'not null' => TRUE,
),
), MigrateDestinationNode::getKeySchema());
// IMPORTANT: Do not try this at home! We have included importable files
// with the migrate_example module so it can be very simply installed and
// run, but you should never include any data you want to keep private
// (especially user data like email addresses, phone numbers, etc.) in the
// module directory. Your source data should be outside of the webroot, and
// should not be anywhere where it may get committed into a revision control
// system.
// This can also be an URL instead of a file path.
$xml_folder = drupal_get_path('module', 'migrate_example') . '/xml/';
$list_url = $xml_folder . 'index.xml';
// Each ID retrieved from the list URL will be plugged into :id in the
// item URL to fetch the specific objects.
$item_url = $xml_folder . ':id.xml';
// We use the MigrateSourceList class for any source where we obtain the list
// of IDs to process separately from the data for each item. The listing
// and item are represented by separate classes, so for example we could
// replace the XML listing with a file directory listing, or the XML item
// with a JSON item.
$this->source = new MigrateSourceList(new MigrateListXML($list_url), new MigrateItemXML($item_url), $fields);
$this->destination = new MigrateDestinationNode('migrate_example_producer');
// TIP: Note that for XML sources, in addition to the source field passed to
// addFieldMapping (the name under which it will be saved in the data row
// passed through the migration process) we specify the Xpath used to retrieve
// the value from the XML.
$this
->addFieldMapping('title', 'name')
->xpath('/producer/name');
$this
->addFieldMapping('uid', 'authorid')
->xpath('/producer/authorid')
->sourceMigration('WineUser')
->defaultValue(1);
$this
->addFieldMapping('Migrate Example Wine Regions', 'region')
->xpath('/producer/region');
$this
->addFieldMapping('body', 'description')
->xpath('/producer/description');
}
}
/**
* TIP: An example of importing from an XML feed where both the id and the
* data to import are in the same file. The id is a part of the data. See
* the file in the xml directory - producers.xml which contains all IDs and
* producer data for this example.
*
* Note that, if basing a migration on an XML source, you need to derive it
* from XMLMigration instead of Migration.
*/
class WineProducerMultiXMLMigration extends XMLMigration {
public function __construct() {
parent::__construct(MigrateGroup::getInstance('wine', array(
'default',
)));
$this->description = t('XML feed (multi items) of wine producers of the world');
$this->dependencies = array(
'WineRegion',
'WineUser',
);
// 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('Producer name'),
'description' => t('Description of producer'),
'authorid' => t('Numeric ID of the author'),
'region' => t('Name of region'),
);
// 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' => 'varchar',
'length' => 4,
'not null' => TRUE,
),
), MigrateDestinationNode::getKeySchema());
// IMPORTANT: Do not try this at home! We have included importable files
// with the migrate_example module so it can be very simply installed and
// run, but you should never include any data you want to keep private
// (especially user data like email addresses, phone numbers, etc.) in the
// module directory. Your source data should be outside of the webroot, and
// should not be anywhere where it may get committed into a revision control
// system.
// This can also be an URL instead of a file path.
$xml_folder = drupal_get_path('module', 'migrate_example') . '/xml/';
$items_url = $xml_folder . 'producers.xml';
// We use the MigrateSourceMultiItems class for any source where we obtain the list
// of IDs to process and the data for each item from the same file. Typically the data
// for an item is not contained in a single line within the source file. Examples include
// multiple items defined in a single xml file or a single json file where in both cases
// the id is part of the item.
$item_xpath = '/producers/producer';
// 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 MigrateDestinationNode('migrate_example_producer');
// TIP: Note that for XML sources, in addition to the source field passed to
// addFieldMapping (the name under which it will be saved in the data row
// passed through the migration process) we specify the Xpath used to retrieve
// the value from the XML.
// TIP: Note that all xpaths for fields begin at the last element of the item
// xpath since each item xml chunk is processed individually.
// (ex. xpath=name is equivalent to a full xpath of /producers/producer/name)
$this
->addFieldMapping('title', 'name')
->xpath('name');
$this
->addFieldMapping('uid', 'authorid')
->xpath('authorid')
->sourceMigration('WineUser')
->defaultValue(1);
$this
->addFieldMapping('Migrate Example Wine Regions', 'region')
->xpath('region');
$this
->addFieldMapping('body', 'description')
->xpath('description');
}
}
/**
* TIP: An alternative approach using MigrateSourceSQL. This uses a different
* XML library, which advances element-by-element through the XML file rather
* than reading in the whole file. This source will work better with large XML
* files, but is slower for small files and has a more restrictive query lanaguage
* for selecting the elements to process.
*/
class WineProducerXMLPullMigration extends XMLMigration {
public function __construct() {
parent::__construct(MigrateGroup::getInstance('wine', array(
'default',
)));
$this->description = t('XML feed (pull) of wine producers of the world');
$this->dependencies = array(
'WineRegion',
'WineUser',
);
$fields = array(
'name' => t('Producer name'),
'description' => t('Description of producer'),
'authorid' => t('Numeric ID of the author'),
'region' => t('Name of region'),
);
$this->map = new MigrateSQLMap($this->machineName, array(
'sourceid' => array(
'type' => 'varchar',
'length' => 4,
'not null' => TRUE,
),
), MigrateDestinationNode::getKeySchema());
// IMPORTANT: Do not try this at home! We have included importable files
// with the migrate_example module so it can be very simply installed and
// run, but you should never include any data you want to keep private
// (especially user data like email addresses, phone numbers, etc.) in the
// module directory. Your source data should be outside of the webroot, and
// should not be anywhere where it may get committed into a revision control
// system.
// This can also be an URL instead of a file path.
$xml_folder = drupal_get_path('module', 'migrate_example') . '/xml/';
$items_url = $xml_folder . 'producers2.xml';
// As with MigrateSourceMultiItems, this applies where there is not a separate
// list of IDs to process - the source XML file is entirely self-contained.
// For the ID path, and xpath for each component, we can use the full xpath
// syntax as usual. However, the syntax to select the elements that correspond
// to objects to import is more limited. It must be a fully-qualified path
// to the element (i.e., /producers/producer rather than just //producer).
$item_xpath = '/producers/producer';
// relative to document
$item_ID_xpath = 'sourceid';
// relative to item_xpath
$this->source = new MigrateSourceXML($items_url, $item_xpath, $item_ID_xpath, $fields);
$this->destination = new MigrateDestinationNode('migrate_example_producer');
$this
->addFieldMapping('title', 'name')
->xpath('name');
$this
->addFieldMapping('uid', 'authorid')
->xpath('authorid')
->sourceMigration('WineUser')
->defaultValue(1);
$this
->addFieldMapping('migrate_example_wine_regions', 'region')
->xpath('region');
$this
->addFieldMapping('body', 'description')
->xpath('description');
}
}
// TODO: Add node_reference field pointing to producer
class WineWineMigration extends AdvancedExampleMigration {
public function __construct() {
parent::__construct();
$this->description = t('Wines of the world');
$this->dependencies = array(
'WineVariety',
'WineRegion',
'WineBestWith',
'WineUser',
'WineProducer',
);
// You can add a 'track_last_imported' option to the map, to record the
// timestamp of when each item was last imported in the map table.
$this->map = new MigrateSQLMap($this->machineName, array(
'wineid' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'description' => 'Wine ID',
'alias' => 'w',
),
), MigrateDestinationNode::getKeySchema(), 'default', array(
'track_last_imported' => TRUE,
));
$query = db_select('migrate_example_wine', 'w')
->fields('w', array(
'wineid',
'name',
'body',
'excerpt',
'accountid',
'posted',
'last_changed',
'variety',
'region',
'rating',
'last_reviewed',
));
$query
->leftJoin('migrate_example_wine_category_wine', 'cwbw', "w.wineid = cwbw.wineid");
$query
->leftJoin('migrate_example_wine_categories', 'bw', "cwbw.categoryid = bw.categoryid AND bw.type = 'best_with'");
// Gives a single comma-separated list of related terms
$query
->groupBy('w.wineid');
$query
->addExpression('GROUP_CONCAT(bw.categoryid)', 'best_with');
$count_query = db_select('migrate_example_wine', 'w');
$count_query
->addExpression('COUNT(wineid)', 'cnt');
// TIP: By passing an array of source fields to the MigrateSourceSQL constructor,
// we can modify the descriptions of source fields (which just default, for
// SQL migrations, to table_alias.column_name), as well as add additional fields
// (which may be populated in prepareRow()).
$source_fields = array(
'wineid' => t('Wine ID in the old system'),
'name' => t('The name of the wine'),
'best_vintages' => t('What years were best for this wine?'),
'images' => t('Images attached to this wine; populated in prepareRow()'),
);
// TIP: By default, each time a migration is run, any previously unimported source items
// are imported (along with any previously-imported items marked for update). If the
// source data contains a timestamp that is set to the creation time of each new item,
// as well as set to the update time for any existing items that are updated, then
// you can have those updated items automatically reimported by setting the field as
// your highwater field.
$this->highwaterField = array(
'name' => 'last_changed',
// Column to be used as highwater mark
'alias' => 'w',
// Table alias containing that column
'type' => 'int',
);
// Note that it is important to process rows in the order of the highwater mark
$query
->orderBy('last_changed');
$this->source = new MigrateSourceSQL($query, $source_fields, $count_query);
$this->destination = new MigrateDestinationNode('migrate_example_wine');
// Mapped fields
$this
->addFieldMapping('title', 'name')
->description(t('Mapping wine name in source to node title'));
$this
->addFieldMapping('uid', 'accountid')
->sourceMigration('WineUser')
->defaultValue(1);
// TIP: By default, term relationship are assumed to be passed by name.
// In this case, the source values are IDs, so we specify the relevant
// migration (so the tid can be looked up in the map), and tell the term
// field handler that it is receiving tids instead of names
$this
->addFieldMapping('Migrate Example Wine Varieties', 'variety')
->sourceMigration('WineVariety')
->arguments(array(
'source_type' => 'tid',
));
$this
->addFieldMapping('Migrate Example Wine Regions', 'region')
->sourceMigration('WineRegion')
->arguments(array(
'source_type' => 'tid',
));
$this
->addFieldMapping('Migrate Example Wine Best With', 'best_with')
->separator(',')
->sourceMigration('WineBestWith')
->arguments(array(
'source_type' => 'tid',
));
$this
->addFieldMapping('field_migrate_example_wine_ratin', 'rating');
$this
->addFieldMapping('field_migrate_example_wine_rvw', 'last_reviewed');
$this
->addFieldMapping('field_migrate_example_top_vintag', 'best_vintages');
// TIP: You can apply one or more functions to a source value using ->callbacks().
// The function must take a single argument and return a value which is a
// transformation of the argument. As this example shows, you can have multiple
// callbacks, and they can either be straight functions or class methods. In
// this case, our custom method prepends 'review: ' to the body, and then we
// call a standard Drupal function to uppercase the whole body.
$this
->addFieldMapping('body', 'body')
->callbacks(array(
$this,
'addTitlePrefix',
), 'drupal_strtoupper');
$this
->addFieldMapping('teaser', 'excerpt');
// We will get the image data from a related table in prepareRow()
$arguments = MigrateFileFieldHandler::arguments(NULL, 'file_copy', FILE_EXISTS_REPLACE);
$this
->addFieldMapping('field_migrate_example_image', 'images')
->arguments($arguments);
$this
->addFieldMapping('sticky')
->defaultValue(0);
// These are already UNIX timestamps, so just pass through
$this
->addFieldMapping('created', 'posted');
$this
->addFieldMapping('changed', 'last_changed');
// No unmapped source fields
// Unmapped destination fields
$this
->addUnmigratedDestinations(array(
'is_new',
'status',
'promote',
'revision',
'language',
));
}
protected function addTitlePrefix($source_title) {
return t('review: ') . $source_title;
}
// TIP: Implement a prepareRow() method to manipulate the source row between
// retrieval from the database and the automatic applicaton of mappings
public function prepareRow($current_row) {
// We used the MySQL GROUP_CONCAT function above to handle a multi-value source
// field - more portably, we query the related table with multiple values here,
// so the values can run through the mapping process
$source_id = $current_row->wineid;
$result = db_select('migrate_example_wine_vintages', 'v')
->fields('v', array(
'vintage',
))
->condition('wineid', $source_id)
->execute();
foreach ($result as $row) {
$current_row->best_vintages[] = $row->vintage;
}
// An advanced feature of the file field handler is that in addition to the
// path to the image itself, we can add image properties like ALT text,
// encapsulating them as JSON
/*
* This is disabled - see http://drupal.org/node/1679798. To demonstrate
* remote file migration, edit the migrate_example_wine_files table and enter
* the URLs of known remote image files, then enable this code.
$result = db_select('migrate_example_wine_files', 'f')
->fields('f', array('url', 'image_alt', 'image_title'))
->condition('wineid', $source_id)
->execute();
$current_row->images = array();
foreach ($result as $row) {
$image_data = array(
'path' => $row->url,
'alt' => $row->image_alt,
'title' => $row->image_title,
);
$current_row->images[] = drupal_to_js($image_data);
}
*/
// We could also have used this function to decide to skip a row, in cases
// where that couldn't easy be done through the original query. Simply
// return FALSE in such cases.
return TRUE;
}
}
class WineCommentMigration extends AdvancedExampleMigration {
public function __construct() {
parent::__construct();
$this->description = 'Comments about wines';
$this->dependencies = array(
'WineUser',
'WineWine',
);
$this->map = new MigrateSQLMap($this->machineName, array(
'commentid' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
),
), MigrateDestinationComment::getKeySchema());
$query = db_select('migrate_example_wine_comment', 'wc')
->fields('wc', array(
'commentid',
'comment_parent',
'name',
'mail',
'accountid',
'body',
'wineid',
'subject',
'commenthost',
'userpage',
'posted',
'lastchanged',
))
->orderBy('comment_parent');
$this->source = new MigrateSourceSQL($query);
$this->destination = new MigrateDestinationComment('comment_node_migrate_example_wine');
// Mapped fields
$this
->addSimpleMappings(array(
'name',
'subject',
'mail',
));
$this
->addFieldMapping('status')
->defaultValue(COMMENT_PUBLISHED);
$this
->addFieldMapping('nid', 'wineid')
->sourceMigration('WineWine');
$this
->addFieldMapping('uid', 'accountid')
->sourceMigration('WineUser')
->defaultValue(0);
$this
->addFieldMapping('pid', 'comment_parent')
->sourceMigration('WineComment')
->description('Parent comment');
$this
->addFieldMapping('comment', 'body');
$this
->addFieldMapping('hostname', 'commenthost');
$this
->addFieldMapping('timestamp', 'lastchanged');
$this
->addFieldMapping('homepage', 'userpage');
// No unmapped source fields
// Unmapped destination fields
$this
->addUnmigratedDestinations(array(
'thread',
'language',
));
}
}
// TIP: An easy way to simply migrate into a Drupal table (i.e., one defined
// through the Schema API) is to use the MigrateDestinationTable destination.
// Just pass the table name to getKeySchema and the MigrateDestinationTable constructor.
class WineTableMigration extends AdvancedExampleMigration {
public function __construct() {
parent::__construct();
$this->description = 'Miscellaneous table data';
$this->softDependencies = array(
'WineComment',
);
$table_name = 'migrate_example_wine_table_dest';
$this->map = new MigrateSQLMap($this->machineName, array(
'fooid' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
),
), MigrateDestinationTable::getKeySchema($table_name));
$query = db_select('migrate_example_wine_table_source', 't')
->fields('t', array(
'fooid',
'field1',
'field2',
));
$this->source = new MigrateSourceSQL($query);
$this->destination = new MigrateDestinationTable($table_name);
// Mapped fields
$this
->addFieldMapping('drupal_text', 'field1');
$this
->addFieldMapping('drupal_int', 'field2');
$this
->addUnmigratedDestinations(array(
'recordid',
));
}
}
/**
* This migration works with WinePrepMigration to make ensure auto_nodetitle
* is re-enabled if we disabled it.
*/
class WineFinishMigration extends MigrationBase {
public function __construct() {
parent::__construct(MigrateGroup::getInstance('wine', array(
'default',
)));
$this->description = t('If auto_nodetitle is present and was previously enabled,
re-enable it');
$this->dependencies = array(
'WineComment',
);
}
public function isComplete() {
if (module_exists('auto_nodetitle')) {
return TRUE;
}
else {
return FALSE;
}
}
public function import() {
if (!module_exists('auto_nodetitle')) {
if (WinePrepMigration::$wasEnabled) {
module_enable(array(
'auto_nodetitle',
));
self::displayMessage(t('Re-enabled auto_nodetitle module'), 'success');
}
else {
self::displayMessage(t('auto_nodetitle was not originally enabled'), 'success');
}
}
else {
self::displayMessage(t('Auto_nodetitle module already enabled'), 'success');
}
return Migration::RESULT_COMPLETED;
}
}
/**
* TIP: This demonstrates a migration designed not to import new content, but
* to update existing content (in this case, revised wine ratings)
*/
class WineUpdatesMigration extends AdvancedExampleMigration {
public function __construct() {
parent::__construct();
$this->description = t('Update wine ratings');
$this->dependencies = array(
'WineWine',
);
$this->softDependencies = array(
'WineFinish',
);
$this->map = new MigrateSQLMap($this->machineName, array(
'wineid' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'description' => 'Wine ID',
'alias' => 'w',
),
), MigrateDestinationNode::getKeySchema());
$query = db_select('migrate_example_wine_updates', 'w')
->fields('w', array(
'wineid',
'rating',
));
$this->source = new MigrateSourceSQL($query);
$this->destination = new MigrateDestinationNode('migrate_example_wine');
// Indicate we're updating existing data. The default, Migration::SOURCE, would
// cause existing nodes to be completely replaced by the source data. In this
// case, the existing node will be loaded and only the rating altered.
$this->systemOfRecord = Migration::DESTINATION;
// Mapped fields
// The destination handler needs the nid to change - since the incoming data
// has a source id, not a nid, we need to apply the original wine migration
// mapping to populate the nid.
$this
->addFieldMapping('nid', 'wineid')
->sourceMigration('WineWine');
$this
->addFieldMapping('field_migrate_example_wine_ratin', 'rating');
// No unmapped source fields
// Unmapped destination fields
$this
->addFieldMapping('uid');
$this
->addFieldMapping('migrate_example_wine_varieties');
$this
->addFieldMapping('migrate_example_wine_regions');
$this
->addFieldMapping('migrate_example_wine_best_with');
$this
->addFieldMapping('body');
$this
->addFieldMapping('field_migrate_example_image');
$this
->addFieldMapping('sticky');
$this
->addFieldMapping('created');
$this
->addFieldMapping('changed');
$this
->addUnmigratedDestinations(array(
'is_new',
'status',
'promote',
'revision',
'language',
));
}
}
class WineCommentUpdatesMigration extends AdvancedExampleMigration {
public function __construct() {
parent::__construct();
$this->description = 'Update wine comments';
$this->dependencies = array(
'WineComment',
);
$this->softDependencies = array(
'WineUpdates',
);
$this->map = new MigrateSQLMap($this->machineName, array(
'commentid' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
),
), MigrateDestinationComment::getKeySchema());
$query = db_select('migrate_example_wine_comment_updates', 'wc')
->fields('wc', array(
'commentid',
'subject',
));
$this->source = new MigrateSourceSQL($query);
$this->destination = new MigrateDestinationComment('comment_node_migrate_example_wine');
$this->systemOfRecord = Migration::DESTINATION;
// Mapped fields
$this
->addFieldMapping('cid', 'commentid')
->sourceMigration('WineComment');
$this
->addFieldMapping('subject', 'subject');
// No unmapped source fields
// Unmapped destination fields
$this
->addFieldMapping('name');
$this
->addFieldMapping('mail');
$this
->addFieldMapping('status');
$this
->addFieldMapping('nid');
$this
->addFieldMapping('uid');
$this
->addFieldMapping('pid');
$this
->addFieldMapping('comment_body');
$this
->addFieldMapping('hostname');
$this
->addFieldMapping('created');
$this
->addFieldMapping('changed');
$this
->addFieldMapping('homepage');
$this
->addUnmigratedDestinations(array(
'thread',
'language',
));
}
}
class WineVarietyUpdatesMigration extends AdvancedExampleMigration {
public function __construct() {
parent::__construct();
$this->description = t('Migrate varieties from the source database to taxonomy terms');
$this->dependencies = array(
'WineVariety',
);
$this->softDependencies = array(
'WineUpdates',
);
$this->map = new MigrateSQLMap($this->machineName, array(
'categoryid' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
),
), MigrateDestinationTerm::getKeySchema());
$query = db_select('migrate_example_wine_variety_updates', 'wc')
->fields('wc', array(
'categoryid',
'details',
));
$this->source = new MigrateSourceSQL($query);
$this->destination = new MigrateDestinationTerm('migrate_example_wine_varieties');
$this->systemOfRecord = Migration::DESTINATION;
// Mapped fields
$this
->addFieldMapping('tid', 'categoryid')
->sourceMigration('WineVariety');
$this
->addFieldMapping('description', 'details');
// Unmapped source fields
// Unmapped destination fields
$this
->addFieldMapping('name');
$this
->addFieldMapping('parent');
$this
->addFieldMapping('weight');
$this
->addFieldMapping('format');
$this
->addFieldMapping('parent_name')
->issueGroup(t('DNM'));
}
}
// Doesn't really do anything, because we don't have fields on users in D6.
class WineUserUpdatesMigration extends AdvancedExampleMigration {
public function __construct() {
parent::__construct();
$this->description = t('Account updates');
$this->dependencies = array(
'WineUser',
);
$this->softDependencies = array(
'WineUpdates',
);
$this->map = new MigrateSQLMap($this->machineName, array(
'accountid' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'description' => 'Account ID.',
),
), MigrateDestinationUser::getKeySchema());
$query = db_select('migrate_example_wine_account_updates', 'wa')
->fields('wa', array(
'accountid',
'sex',
));
$this->source = new MigrateSourceSQL($query);
$this->destination = new MigrateDestinationUser();
$this->systemOfRecord = Migration::DESTINATION;
// Mapped fields
$this
->addFieldMapping('uid', 'accountid')
->sourceMigration('WineUser');
// Unmapped source fields
// Unmapped destination fields
$this
->addFieldMapping('name');
$this
->addFieldMapping('status');
$this
->addFieldMapping('created');
$this
->addFieldMapping('access');
$this
->addFieldMapping('login');
$this
->addFieldMapping('mail');
$this
->addFieldMapping('pass');
$this
->addFieldMapping('roles');
$this
->addFieldMapping('signature');
$this
->addFieldMapping('signature_format');
$this
->addFieldMapping('init');
$this
->addUnmigratedDestinations(array(
'theme',
'timezone',
'language',
'picture',
));
}
}
Classes
Name | Description |
---|---|
AdvancedExampleMigration | Abstract intermediate class holding common settings. |
WineBestWithMigration | |
WineCommentMigration | |
WineCommentUpdatesMigration | |
WineFinishMigration | This migration works with WinePrepMigration to make ensure auto_nodetitle is re-enabled if we disabled it. |
WinePrepMigration | TIP: While usually you'll create true migrations - processes that copy data from some source into Drupal - you can also define processing steps for either the import or rollback stages that take other actions. In this case, we want to disable… |
WineProducerMigration | |
WineProducerMultiXMLMigration | TIP: An example of importing from an XML feed where both the id and the data to import are in the same file. The id is a part of the data. See the file in the xml directory - producers.xml which contains all IDs and producer data for this example. |
WineProducerXMLMigration | TIP: An example of importing from an XML feed. See the files in the xml directory - index.xml contains a list of IDs to import, and <id>.xml is the data for a given producer. |
WineProducerXMLPullMigration | TIP: An alternative approach using MigrateSourceSQL. This uses a different XML library, which advances element-by-element through the XML file rather than reading in the whole file. This source will work better with large XML files, but is slower for… |
WineRegionMigration | |
WineRoleMigration | |
WineTableMigration | |
WineTermMigration | |
WineUpdatesMigration | TIP: This demonstrates a migration designed not to import new content, but to update existing content (in this case, revised wine ratings) |
WineUserMigration | |
WineUserUpdatesMigration | |
WineVarietyMigration | |
WineVarietyUpdatesMigration | |
WineWineMigration |