Мигрируем на Drupal 8! 
#dckiev14
About us 
Andy Postnikov http://dgo.to/@andypost 
Pavel Makhrinsky http://dgo.to/@gumanist
More then 2% of all sites 
How many sites are running Drupal 6 and 7?
Latest stats
10 Drupal myths 
● Box product 
● Lego 
● Contrib - themes, modules, libraries 
● Multilingual 
● Platform 
● Support 
● Community 
● Evolution
Go Drupal 8 
● PHP 5.4 - 5.5, 5.6.2 
● HTML 5 
● Libraries - jQuery 2.1 (3.0) 
● Modules 
● CDN - REST 
● Database
Common migration tasks 
● Planning 
o Data mapping 
o Dependencies management 
o Data cleanup 
● Chicken 'n Egg handling 
● Continuous content lifecycle 
● Progress monitoring 
● Rollback results
What is the migrate module? 
Source => Process => Destination
Migrate vs Feeds 
Mostly indentical feature set: 
● Since 2009 but FeedAPI 2007 
● feeds is UI-oriented 
● feeds_tamper vs custom code 
● feeds has a lot of satelite modules
Migrate in Drupal 8 retrospective 
Signed after 6 weeks away from feature freeze 
https://www.drupal.org/node/1052692#comment-6620570 
Initial patch was commited November 21, 2013 
https://www.drupal.org/node/2125717#comment-8197259 
Drupal 6 to Drupal 8 patch April 23, 2014 
https://www.drupal.org/node/2121299#comment-8710315 
Still in progress of polishing 
https://groups.drupal.org/imp - weekly call
Processing
Mapping
Definition (yml-file) 
id: migrate_example_people 
source: 
plugin: migrate_example_people 
destination: 
plugin: entity:user 
md5_passwords: true 
process: 
name: 
- 
plugin: concat 
delimiter: . 
source: 
- first_name 
- last_name 
- 
plugin: callback 
callable: 
- 'DrupalComponentUtilityUnicode' 
- strtolower 
- 
plugin: callback 
callable: trim 
- 
plugin: dedupe_entity 
entity_type: user 
field: name 
mail: email 
pass: pass 
roles: 
- 
plugin: explode 
delimiter: ';' 
source: groups
Chicken and egg 
process: 
tid: tid 
vid: 
plugin: migration 
migration: d6_taxonomy_vocabulary 
source: vid 
parent: 
- 
plugin: skip_process_on_empty 
source: parent 
- 
plugin: migration 
migration: d6_taxonomy_term
Dependencies 
migration_dependencies: 
required: 
- d6_filter_format 
- d6_user_role 
- d6_user_picture_entity_display 
- d6_user_picture_entity_form_display 
optional: 
- d6_user_picture_file
Execution flow 
class MigrateExecutable { 
/** Performs an import operation - migrate items from source to destination. */ 
public function import() { 
$source = $this->getSource(); 
$id_map = $this->migration->getIdMap(); 
$source->rewind(); 
while ($source->valid()) { 
$row = $source->current(); 
$this->processRow($row); 
$destination_id_values = $destination->import($row, $id_map- 
>lookupDestinationId($this->sourceIdValues)); 
$id_map->saveIdMapping($row, $destination_id_values, $this- 
>sourceRowStatus, $this->rollbackAction); 
$source->next(); 
} 
}
Source plugins 
Provides source rows - mostly custom 
1. getIterator(): iterator producing rows 
2. prepareRow(): add more data to a row 
3. There are hooks for prepareRow() 
MigrateSourceInterface
Source example - core 
/** 
* Drupal 6 menu source from database. 
* 
* @MigrateSource( 
* id = "d6_menu", 
* source_provider = "menu" 
* ) 
*/ 
class Menu extends DrupalSqlBase { 
/** 
* {@inheritdoc} 
*/ 
public function query() { 
$query = $this->select('menu_custom', 'm') 
->fields('m', array('menu_name', 'title', 'description')); 
return $query; 
}
Source example - custom 
public function count() { 
if (is_array($this->getData())) { 
return count($this->getData()); 
} 
return 0; 
} 
public function getIterator() { 
return new ArrayIterator($this->getData()); 
} 
protected function getData() { 
if (!isset($this->data)) { 
$this->data = array(); 
foreach ($this->fetchDataFromYandexDirect() as $key => $value) { 
$this->data[$key] = (array) $value; 
} 
} 
return $this->data; 
}
Process plugins 
● Keys are destination properties 
● Values are process pipelines 
● Each pipeline is a series of process plugins 
+ configuration 
● There are shorthands 
MigrateProcessInterface::transform()
Process pipelines 
process: 
id: 
- 
plugin: machine_name 
source: name 
- 
plugin: dedupe_entity 
entity_type: user_role 
field: id 
- 
plugin: user_update_8002 #custom
Process plugins shipped 
Constant values 
Plugins: 
 get 
 concat 
 dedupebase 
 iterator 
 skip_row_if_not_set 
 default_value 
 extract 
 flatten 
 iterator 
 migration 
 skip_process_on_empty 
 skip_row_on_empty 
 static map 
 machine_name 
 dedupe_entity 
 callback
Process plugin example 
public function transform($value, MigrateExecutable 
$migrate_executable, Row $row, $destination_property) { 
$new_value = $this->getTransliteration()- 
>transliterate($value, 
LanguageInterface::LANGCODE_DEFAULT, '_'); 
$new_value = strtolower($new_value); 
$new_value = preg_replace('/[^a-z0-9_]+/', '_', 
$new_value); 
return preg_replace('/_+/', '_', $new_value); 
}
Destination plugins 
● Does the actual import 
● Almost always provided by migrate module 
● Most common is entity:$entity_type 
o entity:node 
o entity:user 
● If you are writing one, you are doing it wrong 
MigrateDestinationInterface
Destination plugins shipped 
● Config 
● Entity 
● Null 
● for custom tables: url_alias, user_data… 
destination: 
plugin: config 
config_name: user.mail
Destination plugin example 
/** 
* {@inheritdoc} 
*/ 
public function import(Row $row, array $old_destination_id_values = 
array()) { 
$path = $this->aliasStorage->save( 
$row->getDestinationProperty('source'), 
$row->getDestinationProperty('alias'), 
$row->getDestinationProperty('langcode'), 
$old_destination_id_values ? $old_destination_id_values[0] : NULL 
); 
return array($path['pid']); 
}
Demo 
● Drush 
● UI sandbox
Drush or custom code 
Recommended way to execute - DRUSH 
Custom code: 
public function submitForm(array &$form, array &$form_state) { 
/** @var $migration DrupalmigrateEntityMigrationInterface */ 
$migration = entity_load('migration', $form_state['values']['migration']); 
$executable = new MigrateExecutable($migration, $this); 
$executable->import(); 
// Display statistics. 
$this->getStats($form, $form_state); 
$form_state['rebuild'] = TRUE; 
}
How to help 
Document driven development 
http://dgo.to/2127611 
Open issues of migration system: 
http://goo.gl/fmVNQl 
Drupal groups http://dgo.to/g/imp 
IRC: Freenode #drupal-migrate
Links 
https://www.drupal.org/upgrade/migrate 
https://www.drupal.org/node/2127611 
https://groups.drupal.org/imp 
IRC: Freenode #drupal-migrate
Questions & Discussions 
Andy Postnikov http://dgo.to/@andypost 
Pavel Makhrinsky http://dgo.to/@gumanist 
Kiev 2014
Roadmap d8 
● миграция только посредством migrate 
● текущее состояние (d6->d8, d7 testing) 
● drush demo! UI contrib 
● под капотом 
o как работает, сходство с 7 
o состоит - сущности и плагины 
o кастомные - source, destination, plugins 
o stubs, parent migrations 
● needs work 
o d7 test, demo?! 
o migration groups, ui

Drupal 8 migrate!

  • 1.
  • 2.
    About us AndyPostnikov http://dgo.to/@andypost Pavel Makhrinsky http://dgo.to/@gumanist
  • 3.
    More then 2%of all sites How many sites are running Drupal 6 and 7?
  • 4.
  • 5.
    10 Drupal myths ● Box product ● Lego ● Contrib - themes, modules, libraries ● Multilingual ● Platform ● Support ● Community ● Evolution
  • 6.
    Go Drupal 8 ● PHP 5.4 - 5.5, 5.6.2 ● HTML 5 ● Libraries - jQuery 2.1 (3.0) ● Modules ● CDN - REST ● Database
  • 7.
    Common migration tasks ● Planning o Data mapping o Dependencies management o Data cleanup ● Chicken 'n Egg handling ● Continuous content lifecycle ● Progress monitoring ● Rollback results
  • 8.
    What is themigrate module? Source => Process => Destination
  • 9.
    Migrate vs Feeds Mostly indentical feature set: ● Since 2009 but FeedAPI 2007 ● feeds is UI-oriented ● feeds_tamper vs custom code ● feeds has a lot of satelite modules
  • 10.
    Migrate in Drupal8 retrospective Signed after 6 weeks away from feature freeze https://www.drupal.org/node/1052692#comment-6620570 Initial patch was commited November 21, 2013 https://www.drupal.org/node/2125717#comment-8197259 Drupal 6 to Drupal 8 patch April 23, 2014 https://www.drupal.org/node/2121299#comment-8710315 Still in progress of polishing https://groups.drupal.org/imp - weekly call
  • 11.
  • 12.
  • 13.
    Definition (yml-file) id:migrate_example_people source: plugin: migrate_example_people destination: plugin: entity:user md5_passwords: true process: name: - plugin: concat delimiter: . source: - first_name - last_name - plugin: callback callable: - 'DrupalComponentUtilityUnicode' - strtolower - plugin: callback callable: trim - plugin: dedupe_entity entity_type: user field: name mail: email pass: pass roles: - plugin: explode delimiter: ';' source: groups
  • 14.
    Chicken and egg process: tid: tid vid: plugin: migration migration: d6_taxonomy_vocabulary source: vid parent: - plugin: skip_process_on_empty source: parent - plugin: migration migration: d6_taxonomy_term
  • 15.
    Dependencies migration_dependencies: required: - d6_filter_format - d6_user_role - d6_user_picture_entity_display - d6_user_picture_entity_form_display optional: - d6_user_picture_file
  • 16.
    Execution flow classMigrateExecutable { /** Performs an import operation - migrate items from source to destination. */ public function import() { $source = $this->getSource(); $id_map = $this->migration->getIdMap(); $source->rewind(); while ($source->valid()) { $row = $source->current(); $this->processRow($row); $destination_id_values = $destination->import($row, $id_map- >lookupDestinationId($this->sourceIdValues)); $id_map->saveIdMapping($row, $destination_id_values, $this- >sourceRowStatus, $this->rollbackAction); $source->next(); } }
  • 17.
    Source plugins Providessource rows - mostly custom 1. getIterator(): iterator producing rows 2. prepareRow(): add more data to a row 3. There are hooks for prepareRow() MigrateSourceInterface
  • 18.
    Source example -core /** * Drupal 6 menu source from database. * * @MigrateSource( * id = "d6_menu", * source_provider = "menu" * ) */ class Menu extends DrupalSqlBase { /** * {@inheritdoc} */ public function query() { $query = $this->select('menu_custom', 'm') ->fields('m', array('menu_name', 'title', 'description')); return $query; }
  • 19.
    Source example -custom public function count() { if (is_array($this->getData())) { return count($this->getData()); } return 0; } public function getIterator() { return new ArrayIterator($this->getData()); } protected function getData() { if (!isset($this->data)) { $this->data = array(); foreach ($this->fetchDataFromYandexDirect() as $key => $value) { $this->data[$key] = (array) $value; } } return $this->data; }
  • 20.
    Process plugins ●Keys are destination properties ● Values are process pipelines ● Each pipeline is a series of process plugins + configuration ● There are shorthands MigrateProcessInterface::transform()
  • 21.
    Process pipelines process: id: - plugin: machine_name source: name - plugin: dedupe_entity entity_type: user_role field: id - plugin: user_update_8002 #custom
  • 22.
    Process plugins shipped Constant values Plugins:  get  concat  dedupebase  iterator  skip_row_if_not_set  default_value  extract  flatten  iterator  migration  skip_process_on_empty  skip_row_on_empty  static map  machine_name  dedupe_entity  callback
  • 23.
    Process plugin example public function transform($value, MigrateExecutable $migrate_executable, Row $row, $destination_property) { $new_value = $this->getTransliteration()- >transliterate($value, LanguageInterface::LANGCODE_DEFAULT, '_'); $new_value = strtolower($new_value); $new_value = preg_replace('/[^a-z0-9_]+/', '_', $new_value); return preg_replace('/_+/', '_', $new_value); }
  • 24.
    Destination plugins ●Does the actual import ● Almost always provided by migrate module ● Most common is entity:$entity_type o entity:node o entity:user ● If you are writing one, you are doing it wrong MigrateDestinationInterface
  • 25.
    Destination plugins shipped ● Config ● Entity ● Null ● for custom tables: url_alias, user_data… destination: plugin: config config_name: user.mail
  • 26.
    Destination plugin example /** * {@inheritdoc} */ public function import(Row $row, array $old_destination_id_values = array()) { $path = $this->aliasStorage->save( $row->getDestinationProperty('source'), $row->getDestinationProperty('alias'), $row->getDestinationProperty('langcode'), $old_destination_id_values ? $old_destination_id_values[0] : NULL ); return array($path['pid']); }
  • 27.
    Demo ● Drush ● UI sandbox
  • 28.
    Drush or customcode Recommended way to execute - DRUSH Custom code: public function submitForm(array &$form, array &$form_state) { /** @var $migration DrupalmigrateEntityMigrationInterface */ $migration = entity_load('migration', $form_state['values']['migration']); $executable = new MigrateExecutable($migration, $this); $executable->import(); // Display statistics. $this->getStats($form, $form_state); $form_state['rebuild'] = TRUE; }
  • 29.
    How to help Document driven development http://dgo.to/2127611 Open issues of migration system: http://goo.gl/fmVNQl Drupal groups http://dgo.to/g/imp IRC: Freenode #drupal-migrate
  • 30.
    Links https://www.drupal.org/upgrade/migrate https://www.drupal.org/node/2127611 https://groups.drupal.org/imp IRC: Freenode #drupal-migrate
  • 31.
    Questions & Discussions Andy Postnikov http://dgo.to/@andypost Pavel Makhrinsky http://dgo.to/@gumanist Kiev 2014
  • 32.
    Roadmap d8 ●миграция только посредством migrate ● текущее состояние (d6->d8, d7 testing) ● drush demo! UI contrib ● под капотом o как работает, сходство с 7 o состоит - сущности и плагины o кастомные - source, destination, plugins o stubs, parent migrations ● needs work o d7 test, demo?! o migration groups, ui

Editor's Notes

  • #2 Текущее состояние модуля migrate и migrate_drupal в ядре Покажем миграцию с drupal 6 на 8 Расскажем, что находится “под капотом” Обсудим грядущие и возможные изменения
  • #4 Наукоград имени Dries B
  • #5 1/5
  • #8 5 - Что из себя представляет миграция данных вообще как общая задача
  • #9 Начальная идея была использовать только конфигурации для д2д
  • #10 2 - кратко рассказать, что различия в основном архитектурные, feeds орентирован на UI, больше процессинга
  • #11 5 - решение принято после фризов, так как важный таск. раньше была возможность мигрировать сайт, но не было возможности расширяться.
  • #12 Начальная идея была использовать только конфигурации для д2д
  • #17 5 - описание потока выполнения
  • #18 Описание интерфейса, рассказать, что можно забирать данные например из web service
  • #19 добавить пример базы, JSON, prepareRow()
  • #20 Описание интерфейса, рассказать, что можно забирать данные например из web service
  • #21 Описание интерфейса, рассказать, что можно забирать данные например из web service
  • #22 Описание интерфейса, рассказать, что можно забирать данные например из web service
  • #23 needs link to d,o handbook
  • #28 5 - запустить пример миграции