SlideShare ist ein Scribd-Unternehmen logo
1 von 57
Downloaden Sie, um offline zu lesen
The Digital Mayflower 
Data Pilgrimage with the Migrate Module 
1
Erich Beyrent 
Working with Drupal 
since 2004! 
Drupal: http://drupal.org/u/ebeyrent 
Twitter: http://twitter.com/ebeyrent 
Github: http://github.com/ebeyrent 
2
Agenda 
3
Agenda 
• Prerequisites 
4
Agenda 
• Prerequisites 
• Migrate Concepts 
5
Agenda 
• Prerequisites 
• Migrate Concepts 
• Implementation 
6
Agenda 
• Prerequisites 
• Migrate Concepts 
• Implementation 
• Classes & Organization 
7
Agenda 
• Prerequisites 
• Migrate Concepts 
• Implementation 
• Classes & Organization 
• Execution 
8
Agenda 
• Prerequisites 
• Migrate Concepts 
• Implementation 
• Classes & Organization 
• Execution 
• Performance 
9
Agenda 
• Prerequisites 
• Migrate Concepts 
• Implementation 
• Classes & Organization 
• Execution 
• Performance 
• Q & A 
10
11
12
13
14
Prerequisites 
• A working Drupal 7 / Drupal 8 installation 
• Basic understanding of PHP OO 
• Understanding of Drupal modules, hooks, 
and the API 
• Understanding of how to write SQL 
and the QueryInterface 
15
16
Migrate Goals 
17 
• Accurate 
• Repeatable 
• Performant 
• Safe
Concepts 
Source 
The source is the interface to the data that is 
being migrated. 
18
Concepts 
Destination 
Destinations are responsible for saving data in 
Drupal. 
19
Concepts 
Map 
Connects the source to the destination 
20
Implementation 
The Module 
Implements hook_migrate_api() 
Registers classes in the .info file 
21
; ** 
; MY_MODULE.info 
; ** 
dependencies[] = migrate 
files[] = migrate_newsletters.module 
files[] = migrate_newsletters.migrate.inc 
files[] = base.inc 
files[] = newsletters.inc 
files[] = subscribers.inc 
files[] = sources.inc 
files[] = subscriptions.inc 
22
23 
/** 
* Implements hook_migrate_api(). 
*/ 
function MY_MODULE_migrate_api() { 
$api = array( 
'api' => 2, 
'groups' => array( 
'newsletters' => array( 
'title' => t('Newsletter'), 
), 
), 
'field handlers' => array( 
'DateMigrateFieldHandler', 
), 
'migrations' => array( 
'Newsletters' => array( 
'class_name' => 'NewslettersMigration', 
'group_name' => 'newsletters', 
), 
'Sources' => array( 
'class_name' => 'SourcesMigration', 
'group_name' => 'newsletters', 
), 
), 
); 
return $api; 
}
24 
/** 
* Implements hook_migrate_api(). 
*/ 
function MY_MODULE_migrate_api() { 
$api = array( 
'api' => 2, 
'groups' => array( 
'newsletters' => array( 
'title' => t('Newsletter'), 
), 
), 
'field handlers' => array( 
'DateMigrateFieldHandler', 
), 
'migrations' => array( 
'Newsletters' => array( 
'class_name' => 'NewslettersMigration', 
'group_name' => 'newsletters', 
), 
'Sources' => array( 
'class_name' => 'SourcesMigration', 
'group_name' => 'newsletters', 
), 
), 
); 
return $api; 
}
25 
/** 
* Implements hook_migrate_api(). 
*/ 
function MY_MODULE_migrate_api() { 
$api = array( 
'api' => 2, 
'groups' => array( 
'newsletters' => array( 
'title' => t('Newsletter'), 
), 
), 
'field handlers' => array( 
'DateMigrateFieldHandler', 
), 
'migrations' => array( 
'Newsletters' => array( 
'class_name' => 'NewslettersMigration', 
'group_name' => 'newsletters', 
), 
'Sources' => array( 
'class_name' => 'SourcesMigration', 
'group_name' => 'newsletters', 
), 
), 
); 
return $api; 
}
26 
/** 
* Implements hook_migrate_api(). 
*/ 
function MY_MODULE_migrate_api() { 
$api = array( 
'api' => 2, 
'groups' => array( 
'newsletters' => array( 
'title' => t('Newsletter'), 
), 
), 
'field handlers' => array( 
'DateMigrateFieldHandler', 
), 
'migrations' => array( 
'Newsletters' => array( 
'class_name' => 'NewslettersMigration', 
'group_name' => 'newsletters', 
), 
'Sources' => array( 
'class_name' => 'SourcesMigration', 
'group_name' => 'newsletters', 
), 
), 
); 
return $api; 
}
27 
/** 
* Implements hook_migrate_api(). 
*/ 
function MY_MODULE_migrate_api() { 
$api = array( 
'api' => 2, 
'groups' => array( 
'newsletters' => array( 
'title' => t('Newsletter'), 
), 
), 
'field handlers' => array( 
'DateMigrateFieldHandler', 
), 
'migrations' => array( 
'Newsletters' => array( 
'class_name' => 'NewslettersMigration', 
'group_name' => 'newsletters', 
), 
'Sources' => array( 
'class_name' => 'SourcesMigration', 
'group_name' => 'newsletters', 
), 
), 
); 
return $api; 
}
Implementation 
The Classes 
Migration classes extend the abstract 
Migration class 
28
abstract class NewslettersBaseMigration extends Migration { 
/** 
* @var array 
*/ 
protected $sourceConfiguration = array(); 
/** 
* Class constructor. 
*/ 
public function __construct($group = NULL) { 
// Always call the parent constructor first for basic setup. 
parent::__construct($group); 
$this->team = array( 
new MigrateTeamMember(‘Joe Migrate', ‘foo@bar.com', t('admin')), 
); 
$this->issuePattern = 'https://example.com/issues/:id:'; 
$this->sourceConfiguration = array( 
'servername' => 'localhost', 
'username' => 'admin', 
'password' => 'bubbles', 
'database' => ‘source_database', 
); 
} 
} 
29
abstract class NewslettersBaseMigration extends Migration { 
/** 
* @var array 
*/ 
protected $sourceConfiguration = array(); 
/** 
* Class constructor. 
*/ 
public function __construct($group = NULL) { 
// Always call the parent constructor first for basic setup. 
parent::__construct($group); 
$this->team = array( 
new MigrateTeamMember(‘Joe Migrate', ‘foo@bar.com', t('admin')), 
); 
$this->issuePattern = 'https://example.com/issues/:id:'; 
$this->sourceConfiguration = array( 
'servername' => 'localhost', 
'username' => 'admin', 
'password' => 'bubbles', 
'database' => ‘source_database', 
); 
} 
} 
30
abstract class NewslettersBaseMigration extends Migration { 
/** 
* @var array 
*/ 
protected $sourceConfiguration = array(); 
/** 
* Class constructor. 
*/ 
public function __construct($group = NULL) { 
// Always call the parent constructor first for basic setup. 
parent::__construct($group); 
$this->team = array( 
new MigrateTeamMember(‘Joe Migrate', ‘foo@bar.com', t('admin')), 
); 
$this->issuePattern = 'https://example.com/issues/:id:'; 
$this->sourceConfiguration = array( 
'servername' => 'localhost', 
'username' => 'admin', 
'password' => 'bubbles', 
'database' => ‘source_database', 
); 
} 
} 
31
abstract class NewslettersBaseMigration extends Migration { 
/** 
* @var array 
*/ 
protected $sourceConfiguration = array(); 
/** 
* Class constructor. 
*/ 
public function __construct($group = NULL) { 
// Always call the parent constructor first for basic setup. 
parent::__construct($group); 
$this->team = array( 
new MigrateTeamMember(‘Joe Migrate', ‘foo@bar.com', t('admin')), 
); 
$this->issuePattern = 'https://example.com/issues/:id:'; 
$this->sourceConfiguration = array( 
'servername' => 'localhost', 
'username' => 'admin', 
'password' => 'bubbles', 
'database' => ‘source_database', 
); 
} 
} 
32
Anatomy of a 
migration class 
Migration classes typically contain four methods: 
• __construct() 
• prepare() 
• prepareRow() 
• complete() 
33
class NewslettersMigration extends NewslettersBaseMigration { 
/** 
* Class constructor method. 
* 
* @param array $arguments 
*/ 
public function __construct(array $arguments = array()) { 
parent::__construct($arguments); 
$this->description = t(‘Newsletters’); 
$options = array( 
34 
'track_changes' => 1 
);
class NewslettersMigration extends NewslettersBaseMigration { 
/** 
* Class constructor method. 
* 
* @param array $arguments 
*/ 
public function __construct(array $arguments = array()) { 
parent::__construct($arguments); 
$this->description = t(‘Newsletters’); 
$options = array( 
35 
'track_changes' => 1 
);
// List of source fields to import. 
$source_fields = array( 
‘email’ => t(‘Subscriber email address’), 
// … 
); 
$select_query = Database::getConnection('default', ‘legacy') 
->select('profile', 'p'); 
$select_query->fields('p', array()); 
$select_query->orderBy(‘email’); 
$count_query = Database::getConnection('default', ‘legacy') 
->select('profile', 'p'); 
$count_query->fields('p', array()); 
$count_query->orderBy(‘email’); 
$count_query->addExpression(‘COUNT(email)’, ‘count’); 
$this->source = new MigrateSourceSQL( 
$select_query, 
$source_fields, 
$count_query, 
$options 
); 
36
$this->destination = new MigrateDestinationTable(‘subscribers’); 
/* 
* Other examples of destination: 
* 
* $this->destination = new MigrateDestinationNode(‘newsletter'); 
* 
* $this->destination = new MigrateDestinationTerm(‘advertising_source'); 
* 
*/ 
37
// Source and destination relation for rollbacks. 
$this->map = new MigrateSQLMap( 
$this->machineName, 
array( 
'id' => array( 
'type' => 'int', 
'not null' => TRUE, 
'description' => 'Newsletter ID.', 
'alias' => 'n', 
) 
), 
MigrateDestinationNode::getKeySchema() 
); 
38
// Source and destination relation for rollbacks. 
$this->map = new MigrateSQLMap( 
$this->machineName, 
array( 
'member_id' => array( 
'type' => 'varchar', 
'length' => 128, 
'not null' => TRUE, 
'description' => 'Subscriber Email ID.', 
'alias' => 'member_id', 
), 
), 
MigrateDestinationTable::getKeySchema('subscribers') 
); 
39
// Source and destination relation for rollbacks. 
$this->map = new MigrateSQLMap( 
$this->machineName, 
array( 
'Source_ID' => array( 
'type' => 'int', 
'not null' => TRUE, 
'description' => 'Source ID.', 
'alias' => 't', 
), 
), 
MigrateDestinationTerm::getKeySchema() 
); 
40
// Basic field mapping. 
$this->addFieldMapping('email', 'email') 
->description(t('Map the subscriber email from the source’)); 
// More advanced field mapping. 
$this->addFieldMapping('uuid', 'uuid') 
->description(t('UUID for the subscriber’)) 
->defaultValue(uuid_generate()) 
->issueGroup(t('Client questions')) 
->issueNumber(765736) 
->issuePriority(MigrateFieldMapping::ISSUE_PRIORITY_OK); 
// Getting fancy - convert string to an array. 
$this->addFieldMapping(‘field_tags', ‘tags') 
->separator(‘,’); 
// Process the field with a callback. 
$this->addFieldMapping(‘json_field’, ‘json’) 
->callback(‘json_decode’); 
// De-duplicate data. 
$this->addFieldMapping('name', 'username') 
->dedupe('users', 'name'); 
41
Map fields to previously migrated fields 
// Map the field to a value from another migration. 
$this->addFieldMapping('uid', 'author_id') 
42 
->sourceMigration('Users');
Skip source and destination fields 
43 
// Unmapped source fields. 
$this->addUnmigratedSources( 
array( 
'first_name', 
'last_name', 
) 
); 
// Unmapped destination fields. 
$this->addUnmigratedDestinations( 
array( 
'eid', 
) 
);
Define the highwater field 
44 
// Define the highwater field. 
$this->highwaterField = array( 
'name' => 'last_changed', 
'alias' => 'w', 
'type' => 'int', 
);
Anatomy of a 
migration class 
• prepare($entity, stdClass $row) 
This method is called just before saving the 
entity. 
• complete($entity, stdClass $row) 
This method is called immediately after the 
entity is saved. 
45
Anatomy of a 
migration class 
• prepareRow(stdClass $row) 
This method is for conditionally skipping rows, 
and for modifying fields before other handlers 
• createStub($migration, array $id) 
This method is for creating stub objects to be 
referenced by the current row 
46
Anatomy of a 
migration class 
source: http://alexrayu.com/blog/drupal-migration-onion-skin-or-node 
47
Migration flow 
Iterator prepareRow() 
Mappings & 
field handlers 
prepare() 
complete() 
48
Execution 
Use drush, not the web interface 
https://www.drupal.org/node/1806824 
Run a single migration: 
drush migrate-import Subscribers 
Run all the migrations in a migration group: 
drush migrate-import --group newsletters 
49
Performance 
Benchmarking 
$ drush mi Migration --instrument [timer, memory, all] 
$ drush mi Newsletters  
--limit="100 items"  
--instrument=“all"  
--feedback=“30 seconds" 
50
Performance 
Database indexes add a lot of overhead on 
writes, especially with multiple multi-column 
indexes 
db_drop_index($table, $index) 
db_add_index($table, $index, array $fields) 
51
class MyMigration extends MigrationBase { 
/** 
* Code to execute before first article row is imported. 
*/ 
public function preImport() { 
parent::preImport(); 
$this->dropIndexes(); 
} 
/** 
* Code to execute after the last article row has been imported. 
*/ 
public function postImport() { 
parent::postImport(); 
$this->restoreIndexes(); 
} 
protected function dropIndexes() { 
db_drop_index('my_table', 'name_of_index'); 
return $this; 
} 
protected function restoreIndexes() { 
db_add_index('my_table', 'name_of_index', array('name_of_field')); 
return $this; 
} 
} 
52
Performance 
53 
MySQL Tuning 
innodb_flush_log_at_trx_commit = 0 
innodb_doublewrite = 0 
innodb_support_xa = 0
Performance 
MySQL Tuning 
key_buffer_size = 128M 
max_allowed_packet = 20M 
query_cache_size = 128M 
table_open_cache = 64 
read_buffer_size = 2M 
read_rnd_buffer_size = 8M 
myisam_sort_buffer_size = 16M 
join_buffer_size = 4M 
tmp_table_size = 92M 
max_heap_table_size = 92M 
sort_buffer_size = 4M 
innodb_additional_mem_pool_size = 8M 
54
Performance 
55 
MySQL Tuning 
innodb_file_per_table
Resources 
Project page - http://drupal.org/project/migrate 
Migrate Handbook - http://drupal.org/node/415260 
Drush migrate commands - http://drupal.org/node/1561820 
Using stubs - http://drupal.org/node/1013506 
Database Tuning - http://www.drupal.org/node/1994584 
56
Questions & Answers 
57

Weitere ähnliche Inhalte

Was ist angesagt?

Doctrine fixtures
Doctrine fixturesDoctrine fixtures
Doctrine fixturesBill Chang
 
Building Lithium Apps
Building Lithium AppsBuilding Lithium Apps
Building Lithium AppsNate Abele
 
How I started to love design patterns
How I started to love design patternsHow I started to love design patterns
How I started to love design patternsSamuel ROZE
 
The State of Lithium
The State of LithiumThe State of Lithium
The State of LithiumNate Abele
 
Lithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate FrameworksLithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate FrameworksNate Abele
 
Tips of CakePHP and MongoDB - Cakefest2011 ichikaway
Tips of CakePHP and MongoDB - Cakefest2011 ichikaway Tips of CakePHP and MongoDB - Cakefest2011 ichikaway
Tips of CakePHP and MongoDB - Cakefest2011 ichikaway ichikaway
 
The Query the Whole Query and Nothing but the Query
The Query the Whole Query and Nothing but the QueryThe Query the Whole Query and Nothing but the Query
The Query the Whole Query and Nothing but the QueryChris Olbekson
 
Symfony CoP: Form component
Symfony CoP: Form componentSymfony CoP: Form component
Symfony CoP: Form componentSamuel ROZE
 
Lithium: The Framework for People Who Hate Frameworks, Tokyo Edition
Lithium: The Framework for People Who Hate Frameworks, Tokyo EditionLithium: The Framework for People Who Hate Frameworks, Tokyo Edition
Lithium: The Framework for People Who Hate Frameworks, Tokyo EditionNate Abele
 
PHP 5.3 and Lithium: the most rad php framework
PHP 5.3 and Lithium: the most rad php frameworkPHP 5.3 and Lithium: the most rad php framework
PHP 5.3 and Lithium: the most rad php frameworkG Woo
 
Extending Moose
Extending MooseExtending Moose
Extending Moosesartak
 
50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 Minutes50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 MinutesAzim Kurt
 
Symfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il clienteSymfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il clienteLeonardo Proietti
 
Design how your objects talk through mocking
Design how your objects talk through mockingDesign how your objects talk through mocking
Design how your objects talk through mockingKonstantin Kudryashov
 
Intro programacion funcional
Intro programacion funcionalIntro programacion funcional
Intro programacion funcionalNSCoder Mexico
 
What's new in the Drupal 7 API?
What's new in the Drupal 7 API?What's new in the Drupal 7 API?
What's new in the Drupal 7 API?Alexandru Badiu
 
Extbase and Beyond
Extbase and BeyondExtbase and Beyond
Extbase and BeyondJochen Rau
 
CQRS and Event Sourcing in a Symfony application
CQRS and Event Sourcing in a Symfony applicationCQRS and Event Sourcing in a Symfony application
CQRS and Event Sourcing in a Symfony applicationSamuel ROZE
 

Was ist angesagt? (20)

Doctrine fixtures
Doctrine fixturesDoctrine fixtures
Doctrine fixtures
 
Drupal 8 database api
Drupal 8 database apiDrupal 8 database api
Drupal 8 database api
 
Building Lithium Apps
Building Lithium AppsBuilding Lithium Apps
Building Lithium Apps
 
How I started to love design patterns
How I started to love design patternsHow I started to love design patterns
How I started to love design patterns
 
The State of Lithium
The State of LithiumThe State of Lithium
The State of Lithium
 
Lithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate FrameworksLithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate Frameworks
 
Tips of CakePHP and MongoDB - Cakefest2011 ichikaway
Tips of CakePHP and MongoDB - Cakefest2011 ichikaway Tips of CakePHP and MongoDB - Cakefest2011 ichikaway
Tips of CakePHP and MongoDB - Cakefest2011 ichikaway
 
The Query the Whole Query and Nothing but the Query
The Query the Whole Query and Nothing but the QueryThe Query the Whole Query and Nothing but the Query
The Query the Whole Query and Nothing but the Query
 
Symfony CoP: Form component
Symfony CoP: Form componentSymfony CoP: Form component
Symfony CoP: Form component
 
Lithium: The Framework for People Who Hate Frameworks, Tokyo Edition
Lithium: The Framework for People Who Hate Frameworks, Tokyo EditionLithium: The Framework for People Who Hate Frameworks, Tokyo Edition
Lithium: The Framework for People Who Hate Frameworks, Tokyo Edition
 
PHP 5.3 and Lithium: the most rad php framework
PHP 5.3 and Lithium: the most rad php frameworkPHP 5.3 and Lithium: the most rad php framework
PHP 5.3 and Lithium: the most rad php framework
 
Extending Moose
Extending MooseExtending Moose
Extending Moose
 
50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 Minutes50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 Minutes
 
Symfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il clienteSymfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il cliente
 
Design how your objects talk through mocking
Design how your objects talk through mockingDesign how your objects talk through mocking
Design how your objects talk through mocking
 
CakeFest 2013 keynote
CakeFest 2013 keynoteCakeFest 2013 keynote
CakeFest 2013 keynote
 
Intro programacion funcional
Intro programacion funcionalIntro programacion funcional
Intro programacion funcional
 
What's new in the Drupal 7 API?
What's new in the Drupal 7 API?What's new in the Drupal 7 API?
What's new in the Drupal 7 API?
 
Extbase and Beyond
Extbase and BeyondExtbase and Beyond
Extbase and Beyond
 
CQRS and Event Sourcing in a Symfony application
CQRS and Event Sourcing in a Symfony applicationCQRS and Event Sourcing in a Symfony application
CQRS and Event Sourcing in a Symfony application
 

Ähnlich wie Digital Mayflower - Data Pilgrimage with the Drupal Migrate Module

第49回Php勉強会@関東 Datasource
第49回Php勉強会@関東 Datasource第49回Php勉強会@関東 Datasource
第49回Php勉強会@関東 DatasourceKaz Watanabe
 
Advanced symfony Techniques
Advanced symfony TechniquesAdvanced symfony Techniques
Advanced symfony TechniquesKris Wallsmith
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For BeginnersJonathan Wage
 
Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)Fabien Potencier
 
laravel tricks in 50minutes
laravel tricks in 50minuteslaravel tricks in 50minutes
laravel tricks in 50minutesBarang CK
 
Keeping it Small: Getting to know the Slim Micro Framework
Keeping it Small: Getting to know the Slim Micro FrameworkKeeping it Small: Getting to know the Slim Micro Framework
Keeping it Small: Getting to know the Slim Micro FrameworkJeremy Kendall
 
The Zen of Lithium
The Zen of LithiumThe Zen of Lithium
The Zen of LithiumNate Abele
 
How Kris Writes Symfony Apps
How Kris Writes Symfony AppsHow Kris Writes Symfony Apps
How Kris Writes Symfony AppsKris Wallsmith
 
Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Leonardo Proietti
 
Nickolay Shmalenuk.Render api eng.DrupalCamp Kyiv 2011
Nickolay Shmalenuk.Render api eng.DrupalCamp Kyiv 2011Nickolay Shmalenuk.Render api eng.DrupalCamp Kyiv 2011
Nickolay Shmalenuk.Render api eng.DrupalCamp Kyiv 2011camp_drupal_ua
 
Virtual Madness @ Etsy
Virtual Madness @ EtsyVirtual Madness @ Etsy
Virtual Madness @ EtsyNishan Subedi
 
Keeping It Small with Slim
Keeping It Small with SlimKeeping It Small with Slim
Keeping It Small with SlimRaven Tools
 
Keeping it small: Getting to know the Slim micro framework
Keeping it small: Getting to know the Slim micro frameworkKeeping it small: Getting to know the Slim micro framework
Keeping it small: Getting to know the Slim micro frameworkJeremy Kendall
 
WordPress as an application framework
WordPress as an application frameworkWordPress as an application framework
WordPress as an application frameworkDustin Filippini
 
前端MVC 豆瓣说
前端MVC 豆瓣说前端MVC 豆瓣说
前端MVC 豆瓣说Ting Lv
 

Ähnlich wie Digital Mayflower - Data Pilgrimage with the Drupal Migrate Module (20)

第49回Php勉強会@関東 Datasource
第49回Php勉強会@関東 Datasource第49回Php勉強会@関東 Datasource
第49回Php勉強会@関東 Datasource
 
Advanced symfony Techniques
Advanced symfony TechniquesAdvanced symfony Techniques
Advanced symfony Techniques
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For Beginners
 
Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)
 
laravel tricks in 50minutes
laravel tricks in 50minuteslaravel tricks in 50minutes
laravel tricks in 50minutes
 
Keeping it Small: Getting to know the Slim Micro Framework
Keeping it Small: Getting to know the Slim Micro FrameworkKeeping it Small: Getting to know the Slim Micro Framework
Keeping it Small: Getting to know the Slim Micro Framework
 
Drupal 8 migrate!
Drupal 8 migrate!Drupal 8 migrate!
Drupal 8 migrate!
 
The Zen of Lithium
The Zen of LithiumThe Zen of Lithium
The Zen of Lithium
 
How Kris Writes Symfony Apps
How Kris Writes Symfony AppsHow Kris Writes Symfony Apps
How Kris Writes Symfony Apps
 
Lithium Best
Lithium Best Lithium Best
Lithium Best
 
Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5
 
Nickolay Shmalenuk.Render api eng.DrupalCamp Kyiv 2011
Nickolay Shmalenuk.Render api eng.DrupalCamp Kyiv 2011Nickolay Shmalenuk.Render api eng.DrupalCamp Kyiv 2011
Nickolay Shmalenuk.Render api eng.DrupalCamp Kyiv 2011
 
Virtual Madness @ Etsy
Virtual Madness @ EtsyVirtual Madness @ Etsy
Virtual Madness @ Etsy
 
Unit testing zend framework apps
Unit testing zend framework appsUnit testing zend framework apps
Unit testing zend framework apps
 
Migrare da symfony 1 a Symfony2
 Migrare da symfony 1 a Symfony2  Migrare da symfony 1 a Symfony2
Migrare da symfony 1 a Symfony2
 
Keeping It Small with Slim
Keeping It Small with SlimKeeping It Small with Slim
Keeping It Small with Slim
 
Keeping it small: Getting to know the Slim micro framework
Keeping it small: Getting to know the Slim micro frameworkKeeping it small: Getting to know the Slim micro framework
Keeping it small: Getting to know the Slim micro framework
 
Drupal7 dbtng
Drupal7  dbtngDrupal7  dbtng
Drupal7 dbtng
 
WordPress as an application framework
WordPress as an application frameworkWordPress as an application framework
WordPress as an application framework
 
前端MVC 豆瓣说
前端MVC 豆瓣说前端MVC 豆瓣说
前端MVC 豆瓣说
 

Mehr von Erich Beyrent

{ JSON:API} 2 - A Path to Decoupled Drupal
{ JSON:API} 2 - A Path to Decoupled Drupal{ JSON:API} 2 - A Path to Decoupled Drupal
{ JSON:API} 2 - A Path to Decoupled DrupalErich Beyrent
 
Configuration as Dependency: Managing Drupal 8 Configuration with git and Com...
Configuration as Dependency: Managing Drupal 8 Configuration with git and Com...Configuration as Dependency: Managing Drupal 8 Configuration with git and Com...
Configuration as Dependency: Managing Drupal 8 Configuration with git and Com...Erich Beyrent
 
Hack-Proof Your Drupal App
Hack-Proof Your Drupal AppHack-Proof Your Drupal App
Hack-Proof Your Drupal AppErich Beyrent
 
Staging Drupal: Change Management Strategies for Drupal
Staging Drupal: Change Management Strategies for DrupalStaging Drupal: Change Management Strategies for Drupal
Staging Drupal: Change Management Strategies for DrupalErich Beyrent
 
Staging Drupal: Change Management Strategies for Drupal
Staging Drupal: Change Management Strategies for DrupalStaging Drupal: Change Management Strategies for Drupal
Staging Drupal: Change Management Strategies for DrupalErich Beyrent
 

Mehr von Erich Beyrent (6)

{ JSON:API} 2 - A Path to Decoupled Drupal
{ JSON:API} 2 - A Path to Decoupled Drupal{ JSON:API} 2 - A Path to Decoupled Drupal
{ JSON:API} 2 - A Path to Decoupled Drupal
 
Test your modules
Test your modulesTest your modules
Test your modules
 
Configuration as Dependency: Managing Drupal 8 Configuration with git and Com...
Configuration as Dependency: Managing Drupal 8 Configuration with git and Com...Configuration as Dependency: Managing Drupal 8 Configuration with git and Com...
Configuration as Dependency: Managing Drupal 8 Configuration with git and Com...
 
Hack-Proof Your Drupal App
Hack-Proof Your Drupal AppHack-Proof Your Drupal App
Hack-Proof Your Drupal App
 
Staging Drupal: Change Management Strategies for Drupal
Staging Drupal: Change Management Strategies for DrupalStaging Drupal: Change Management Strategies for Drupal
Staging Drupal: Change Management Strategies for Drupal
 
Staging Drupal: Change Management Strategies for Drupal
Staging Drupal: Change Management Strategies for DrupalStaging Drupal: Change Management Strategies for Drupal
Staging Drupal: Change Management Strategies for Drupal
 

Kürzlich hochgeladen

Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Modelsaagamshah0812
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsArshad QA
 
Test Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and BackendTest Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and BackendArshad QA
 
What is Binary Language? Computer Number Systems
What is Binary Language?  Computer Number SystemsWhat is Binary Language?  Computer Number Systems
What is Binary Language? Computer Number SystemsJheuzeDellosa
 
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...stazi3110
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantAxelRicardoTrocheRiq
 
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AISyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AIABDERRAOUF MEHENNI
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software DevelopersVinodh Ram
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...ICS
 
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...OnePlan Solutions
 
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideChristina Lin
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...MyIntelliSource, Inc.
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsAlberto González Trastoy
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdfWave PLM
 
Project Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationProject Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationkaushalgiri8080
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxComplianceQuest1
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)OPEN KNOWLEDGE GmbH
 
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerHow To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerThousandEyes
 

Kürzlich hochgeladen (20)

Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Models
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview Questions
 
Test Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and BackendTest Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and Backend
 
What is Binary Language? Computer Number Systems
What is Binary Language?  Computer Number SystemsWhat is Binary Language?  Computer Number Systems
What is Binary Language? Computer Number Systems
 
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service Consultant
 
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AISyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software Developers
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
 
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
 
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS LiveVip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf
 
Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
 
Project Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationProject Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanation
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docx
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)
 
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerHow To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
 

Digital Mayflower - Data Pilgrimage with the Drupal Migrate Module

  • 1. The Digital Mayflower Data Pilgrimage with the Migrate Module 1
  • 2. Erich Beyrent Working with Drupal since 2004! Drupal: http://drupal.org/u/ebeyrent Twitter: http://twitter.com/ebeyrent Github: http://github.com/ebeyrent 2
  • 5. Agenda • Prerequisites • Migrate Concepts 5
  • 6. Agenda • Prerequisites • Migrate Concepts • Implementation 6
  • 7. Agenda • Prerequisites • Migrate Concepts • Implementation • Classes & Organization 7
  • 8. Agenda • Prerequisites • Migrate Concepts • Implementation • Classes & Organization • Execution 8
  • 9. Agenda • Prerequisites • Migrate Concepts • Implementation • Classes & Organization • Execution • Performance 9
  • 10. Agenda • Prerequisites • Migrate Concepts • Implementation • Classes & Organization • Execution • Performance • Q & A 10
  • 11. 11
  • 12. 12
  • 13. 13
  • 14. 14
  • 15. Prerequisites • A working Drupal 7 / Drupal 8 installation • Basic understanding of PHP OO • Understanding of Drupal modules, hooks, and the API • Understanding of how to write SQL and the QueryInterface 15
  • 16. 16
  • 17. Migrate Goals 17 • Accurate • Repeatable • Performant • Safe
  • 18. Concepts Source The source is the interface to the data that is being migrated. 18
  • 19. Concepts Destination Destinations are responsible for saving data in Drupal. 19
  • 20. Concepts Map Connects the source to the destination 20
  • 21. Implementation The Module Implements hook_migrate_api() Registers classes in the .info file 21
  • 22. ; ** ; MY_MODULE.info ; ** dependencies[] = migrate files[] = migrate_newsletters.module files[] = migrate_newsletters.migrate.inc files[] = base.inc files[] = newsletters.inc files[] = subscribers.inc files[] = sources.inc files[] = subscriptions.inc 22
  • 23. 23 /** * Implements hook_migrate_api(). */ function MY_MODULE_migrate_api() { $api = array( 'api' => 2, 'groups' => array( 'newsletters' => array( 'title' => t('Newsletter'), ), ), 'field handlers' => array( 'DateMigrateFieldHandler', ), 'migrations' => array( 'Newsletters' => array( 'class_name' => 'NewslettersMigration', 'group_name' => 'newsletters', ), 'Sources' => array( 'class_name' => 'SourcesMigration', 'group_name' => 'newsletters', ), ), ); return $api; }
  • 24. 24 /** * Implements hook_migrate_api(). */ function MY_MODULE_migrate_api() { $api = array( 'api' => 2, 'groups' => array( 'newsletters' => array( 'title' => t('Newsletter'), ), ), 'field handlers' => array( 'DateMigrateFieldHandler', ), 'migrations' => array( 'Newsletters' => array( 'class_name' => 'NewslettersMigration', 'group_name' => 'newsletters', ), 'Sources' => array( 'class_name' => 'SourcesMigration', 'group_name' => 'newsletters', ), ), ); return $api; }
  • 25. 25 /** * Implements hook_migrate_api(). */ function MY_MODULE_migrate_api() { $api = array( 'api' => 2, 'groups' => array( 'newsletters' => array( 'title' => t('Newsletter'), ), ), 'field handlers' => array( 'DateMigrateFieldHandler', ), 'migrations' => array( 'Newsletters' => array( 'class_name' => 'NewslettersMigration', 'group_name' => 'newsletters', ), 'Sources' => array( 'class_name' => 'SourcesMigration', 'group_name' => 'newsletters', ), ), ); return $api; }
  • 26. 26 /** * Implements hook_migrate_api(). */ function MY_MODULE_migrate_api() { $api = array( 'api' => 2, 'groups' => array( 'newsletters' => array( 'title' => t('Newsletter'), ), ), 'field handlers' => array( 'DateMigrateFieldHandler', ), 'migrations' => array( 'Newsletters' => array( 'class_name' => 'NewslettersMigration', 'group_name' => 'newsletters', ), 'Sources' => array( 'class_name' => 'SourcesMigration', 'group_name' => 'newsletters', ), ), ); return $api; }
  • 27. 27 /** * Implements hook_migrate_api(). */ function MY_MODULE_migrate_api() { $api = array( 'api' => 2, 'groups' => array( 'newsletters' => array( 'title' => t('Newsletter'), ), ), 'field handlers' => array( 'DateMigrateFieldHandler', ), 'migrations' => array( 'Newsletters' => array( 'class_name' => 'NewslettersMigration', 'group_name' => 'newsletters', ), 'Sources' => array( 'class_name' => 'SourcesMigration', 'group_name' => 'newsletters', ), ), ); return $api; }
  • 28. Implementation The Classes Migration classes extend the abstract Migration class 28
  • 29. abstract class NewslettersBaseMigration extends Migration { /** * @var array */ protected $sourceConfiguration = array(); /** * Class constructor. */ public function __construct($group = NULL) { // Always call the parent constructor first for basic setup. parent::__construct($group); $this->team = array( new MigrateTeamMember(‘Joe Migrate', ‘foo@bar.com', t('admin')), ); $this->issuePattern = 'https://example.com/issues/:id:'; $this->sourceConfiguration = array( 'servername' => 'localhost', 'username' => 'admin', 'password' => 'bubbles', 'database' => ‘source_database', ); } } 29
  • 30. abstract class NewslettersBaseMigration extends Migration { /** * @var array */ protected $sourceConfiguration = array(); /** * Class constructor. */ public function __construct($group = NULL) { // Always call the parent constructor first for basic setup. parent::__construct($group); $this->team = array( new MigrateTeamMember(‘Joe Migrate', ‘foo@bar.com', t('admin')), ); $this->issuePattern = 'https://example.com/issues/:id:'; $this->sourceConfiguration = array( 'servername' => 'localhost', 'username' => 'admin', 'password' => 'bubbles', 'database' => ‘source_database', ); } } 30
  • 31. abstract class NewslettersBaseMigration extends Migration { /** * @var array */ protected $sourceConfiguration = array(); /** * Class constructor. */ public function __construct($group = NULL) { // Always call the parent constructor first for basic setup. parent::__construct($group); $this->team = array( new MigrateTeamMember(‘Joe Migrate', ‘foo@bar.com', t('admin')), ); $this->issuePattern = 'https://example.com/issues/:id:'; $this->sourceConfiguration = array( 'servername' => 'localhost', 'username' => 'admin', 'password' => 'bubbles', 'database' => ‘source_database', ); } } 31
  • 32. abstract class NewslettersBaseMigration extends Migration { /** * @var array */ protected $sourceConfiguration = array(); /** * Class constructor. */ public function __construct($group = NULL) { // Always call the parent constructor first for basic setup. parent::__construct($group); $this->team = array( new MigrateTeamMember(‘Joe Migrate', ‘foo@bar.com', t('admin')), ); $this->issuePattern = 'https://example.com/issues/:id:'; $this->sourceConfiguration = array( 'servername' => 'localhost', 'username' => 'admin', 'password' => 'bubbles', 'database' => ‘source_database', ); } } 32
  • 33. Anatomy of a migration class Migration classes typically contain four methods: • __construct() • prepare() • prepareRow() • complete() 33
  • 34. class NewslettersMigration extends NewslettersBaseMigration { /** * Class constructor method. * * @param array $arguments */ public function __construct(array $arguments = array()) { parent::__construct($arguments); $this->description = t(‘Newsletters’); $options = array( 34 'track_changes' => 1 );
  • 35. class NewslettersMigration extends NewslettersBaseMigration { /** * Class constructor method. * * @param array $arguments */ public function __construct(array $arguments = array()) { parent::__construct($arguments); $this->description = t(‘Newsletters’); $options = array( 35 'track_changes' => 1 );
  • 36. // List of source fields to import. $source_fields = array( ‘email’ => t(‘Subscriber email address’), // … ); $select_query = Database::getConnection('default', ‘legacy') ->select('profile', 'p'); $select_query->fields('p', array()); $select_query->orderBy(‘email’); $count_query = Database::getConnection('default', ‘legacy') ->select('profile', 'p'); $count_query->fields('p', array()); $count_query->orderBy(‘email’); $count_query->addExpression(‘COUNT(email)’, ‘count’); $this->source = new MigrateSourceSQL( $select_query, $source_fields, $count_query, $options ); 36
  • 37. $this->destination = new MigrateDestinationTable(‘subscribers’); /* * Other examples of destination: * * $this->destination = new MigrateDestinationNode(‘newsletter'); * * $this->destination = new MigrateDestinationTerm(‘advertising_source'); * */ 37
  • 38. // Source and destination relation for rollbacks. $this->map = new MigrateSQLMap( $this->machineName, array( 'id' => array( 'type' => 'int', 'not null' => TRUE, 'description' => 'Newsletter ID.', 'alias' => 'n', ) ), MigrateDestinationNode::getKeySchema() ); 38
  • 39. // Source and destination relation for rollbacks. $this->map = new MigrateSQLMap( $this->machineName, array( 'member_id' => array( 'type' => 'varchar', 'length' => 128, 'not null' => TRUE, 'description' => 'Subscriber Email ID.', 'alias' => 'member_id', ), ), MigrateDestinationTable::getKeySchema('subscribers') ); 39
  • 40. // Source and destination relation for rollbacks. $this->map = new MigrateSQLMap( $this->machineName, array( 'Source_ID' => array( 'type' => 'int', 'not null' => TRUE, 'description' => 'Source ID.', 'alias' => 't', ), ), MigrateDestinationTerm::getKeySchema() ); 40
  • 41. // Basic field mapping. $this->addFieldMapping('email', 'email') ->description(t('Map the subscriber email from the source’)); // More advanced field mapping. $this->addFieldMapping('uuid', 'uuid') ->description(t('UUID for the subscriber’)) ->defaultValue(uuid_generate()) ->issueGroup(t('Client questions')) ->issueNumber(765736) ->issuePriority(MigrateFieldMapping::ISSUE_PRIORITY_OK); // Getting fancy - convert string to an array. $this->addFieldMapping(‘field_tags', ‘tags') ->separator(‘,’); // Process the field with a callback. $this->addFieldMapping(‘json_field’, ‘json’) ->callback(‘json_decode’); // De-duplicate data. $this->addFieldMapping('name', 'username') ->dedupe('users', 'name'); 41
  • 42. Map fields to previously migrated fields // Map the field to a value from another migration. $this->addFieldMapping('uid', 'author_id') 42 ->sourceMigration('Users');
  • 43. Skip source and destination fields 43 // Unmapped source fields. $this->addUnmigratedSources( array( 'first_name', 'last_name', ) ); // Unmapped destination fields. $this->addUnmigratedDestinations( array( 'eid', ) );
  • 44. Define the highwater field 44 // Define the highwater field. $this->highwaterField = array( 'name' => 'last_changed', 'alias' => 'w', 'type' => 'int', );
  • 45. Anatomy of a migration class • prepare($entity, stdClass $row) This method is called just before saving the entity. • complete($entity, stdClass $row) This method is called immediately after the entity is saved. 45
  • 46. Anatomy of a migration class • prepareRow(stdClass $row) This method is for conditionally skipping rows, and for modifying fields before other handlers • createStub($migration, array $id) This method is for creating stub objects to be referenced by the current row 46
  • 47. Anatomy of a migration class source: http://alexrayu.com/blog/drupal-migration-onion-skin-or-node 47
  • 48. Migration flow Iterator prepareRow() Mappings & field handlers prepare() complete() 48
  • 49. Execution Use drush, not the web interface https://www.drupal.org/node/1806824 Run a single migration: drush migrate-import Subscribers Run all the migrations in a migration group: drush migrate-import --group newsletters 49
  • 50. Performance Benchmarking $ drush mi Migration --instrument [timer, memory, all] $ drush mi Newsletters --limit="100 items" --instrument=“all" --feedback=“30 seconds" 50
  • 51. Performance Database indexes add a lot of overhead on writes, especially with multiple multi-column indexes db_drop_index($table, $index) db_add_index($table, $index, array $fields) 51
  • 52. class MyMigration extends MigrationBase { /** * Code to execute before first article row is imported. */ public function preImport() { parent::preImport(); $this->dropIndexes(); } /** * Code to execute after the last article row has been imported. */ public function postImport() { parent::postImport(); $this->restoreIndexes(); } protected function dropIndexes() { db_drop_index('my_table', 'name_of_index'); return $this; } protected function restoreIndexes() { db_add_index('my_table', 'name_of_index', array('name_of_field')); return $this; } } 52
  • 53. Performance 53 MySQL Tuning innodb_flush_log_at_trx_commit = 0 innodb_doublewrite = 0 innodb_support_xa = 0
  • 54. Performance MySQL Tuning key_buffer_size = 128M max_allowed_packet = 20M query_cache_size = 128M table_open_cache = 64 read_buffer_size = 2M read_rnd_buffer_size = 8M myisam_sort_buffer_size = 16M join_buffer_size = 4M tmp_table_size = 92M max_heap_table_size = 92M sort_buffer_size = 4M innodb_additional_mem_pool_size = 8M 54
  • 55. Performance 55 MySQL Tuning innodb_file_per_table
  • 56. Resources Project page - http://drupal.org/project/migrate Migrate Handbook - http://drupal.org/node/415260 Drush migrate commands - http://drupal.org/node/1561820 Using stubs - http://drupal.org/node/1013506 Database Tuning - http://www.drupal.org/node/1994584 56