| Commit | Line | Data |
|---|---|---|
| 79f72dcc | 1 | <?php |
| 79f72dcc MR |
2 | |
| 3 | /** | |
| 4 | * @file | |
| 5 | * Advanced migration examples. These serve two purposes: | |
| 6 | * | |
| 7 | * 1. To demonstrate some of the more advanced usages of the Migrate module. | |
| 8 | * Search for "TIP:" below for features not found in the basic example. | |
| 9 | * 2. To provide thorough test cases for the simpletest suite. | |
| 10 | * | |
| 11 | */ | |
| 12 | ||
| 13 | /** | |
| 14 | * Abstract intermediate class holding common settings. | |
| 15 | */ | |
| 16 | abstract class AdvancedExampleMigration extends Migration { | |
| e0c558fa MR |
17 | public $basicFormat; |
| 18 | ||
| 79f72dcc | 19 | public function __construct() { |
| 79f72dcc | 20 | parent::__construct(); |
| 79f72dcc | 21 | $this->team = array( |
| 2518dfe3 MR |
22 | new MigrateTeamMember('Jack Kramer', 'jkramer@example.com', t('Taster')), |
| 23 | new MigrateTeamMember('Linda Madison', 'lmadison@example.com', t('Winemaker')), | |
| 79f72dcc | 24 | ); |
| 79f72dcc | 25 | $this->issuePattern = 'http://drupal.org/node/:id:'; |
| e0c558fa MR |
26 | |
| 27 | // A format of our own, for testing migration of formats | |
| 3b7ece73 | 28 | $this->basicFormat = filter_format_load('migrate_example'); |
| 79f72dcc MR |
29 | } |
| 30 | } | |
| 31 | ||
| 32 | /** | |
| 33 | * TIP: While usually you'll create true migrations - processes that copy data | |
| 34 | * from some source into Drupal - you can also define processing steps for either | |
| 35 | * the import or rollback stages that take other actions. In this case, we want | |
| 4ab61127 | 36 | * to disable auto_nodetitle while the migration steps run. |
| 79f72dcc | 37 | */ |
| 20d432de | 38 | class WinePrepMigration extends MigrationBase { |
| 81da2cf8 MR |
39 | // Remember whether the auto_nodetitle was originally enabled, so we know whether |
| 40 | // to re-enable it | |
| 41 | public static $wasEnabled = FALSE; | |
| 42 | ||
| 79f72dcc MR |
43 | public function __construct() { |
| 44 | parent::__construct(); | |
| 4ab61127 | 45 | $this->description = t('If auto_nodetitle is present, disable it for the duration'); |
| 79f72dcc MR |
46 | // TIP: Regular dependencies, besides enforcing (in the absence of --force) |
| 47 | // the run order of migrations, affect the sorting of migrations on display. | |
| 2518dfe3 | 48 | // You can use soft dependencies to affect just the display order when the |
| 79f72dcc MR |
49 | // migrations aren't technically required to run in a certain order. In this |
| 50 | // case, we want the wine migrations to appear after the beer migrations - | |
| 51 | // without this line, they would be intermingled due to their lack of | |
| 52 | // (formal) interdependencies. | |
| 7a68c5aa | 53 | $this->softDependencies = array('BeerComment'); |
| 79f72dcc MR |
54 | } |
| 55 | // Define isComplete(), returning a boolean, to indicate whether dependent | |
| 56 | // migrations may proceed | |
| 57 | public function isComplete() { | |
| cdfe3ddb | 58 | // If Auto Node Title is disabled, other migrations are free to go |
| 4ab61127 | 59 | if (module_exists('auto_nodetitle')) { |
| 79f72dcc MR |
60 | return FALSE; |
| 61 | } | |
| 62 | else { | |
| 63 | return TRUE; | |
| 64 | } | |
| 65 | } | |
| 66 | // Implement any action you want to occur during an import process in an | |
| 70380ea8 | 67 | // import() method (alternatively, if you have an action which you want to |
| 79f72dcc MR |
68 | // run during rollbacks, define a rollback() method). |
| 69 | public function import() { | |
| 4ab61127 | 70 | if (module_exists('auto_nodetitle')) { |
| 81da2cf8 | 71 | self::$wasEnabled = TRUE; |
| 4ab61127 | 72 | module_disable(array('auto_nodetitle')); |
| 73 | $this->showMessage(t('Disabled auto_nodetitle module'), 'success'); | |
| 79f72dcc | 74 | } |
| 2518dfe3 | 75 | else { |
| 81da2cf8 | 76 | self::$wasEnabled = FALSE; |
| 4ab61127 | 77 | $this->showMessage(t('Auto_nodetitle is already disabled'), 'success'); |
| 2518dfe3 MR |
78 | } |
| 79 | // Must return one of the MigrationBase RESULT constants | |
| 80 | return MigrationBase::RESULT_COMPLETED; | |
| 79f72dcc MR |
81 | } |
| 82 | } | |
| 83 | ||
| 2518dfe3 | 84 | // The term migrations are very similar - implement the commonalities here |
| 20d432de | 85 | abstract class WineTermMigration extends AdvancedExampleMigration { |
| 2518dfe3 | 86 | public function __construct($type, $vocabulary_name, $description) { |
| 79f72dcc | 87 | parent::__construct(); |
| 2518dfe3 | 88 | $this->description = $description; |
| 7a68c5aa | 89 | $this->dependencies = array('WinePrep'); |
| 79f72dcc MR |
90 | $this->map = new MigrateSQLMap($this->machineName, |
| 91 | array( | |
| 2518dfe3 MR |
92 | 'categoryid' => array('type' => 'int', |
| 93 | 'unsigned' => TRUE, | |
| 94 | 'not null' => TRUE, | |
| 95 | ) | |
| 79f72dcc MR |
96 | ), |
| 97 | MigrateDestinationTerm::getKeySchema() | |
| 98 | ); | |
| 99 | ||
| 2518dfe3 | 100 | $query = db_select('migrate_example_wine_categories', 'wc') |
| e0c558fa | 101 | ->fields('wc', array('categoryid', 'name', 'details', 'category_parent', 'ordering')) |
| 2518dfe3 | 102 | ->condition('type', $type) |
| 79f72dcc | 103 | // This sort assures that parents are saved before children. |
| 2518dfe3 | 104 | ->orderBy('category_parent', 'ASC'); |
| 9fadaa93 | 105 | $this->source = new MigrateSourceSQL($query); |
| 2518dfe3 MR |
106 | $this->destination = new MigrateDestinationTerm($vocabulary_name); |
| 107 | ||
| 108 | // Mapped fields | |
| 109 | $this->addFieldMapping('name', 'name'); | |
| 79f72dcc | 110 | $this->addFieldMapping('description', 'details'); |
| 2518dfe3 | 111 | $this->addFieldMapping('parent', 'category_parent') |
| 7a68c5aa | 112 | ->sourceMigration($this->getMachineName()); |
| e0c558fa MR |
113 | $this->addFieldMapping('weight', 'ordering'); |
| 114 | $this->addFieldMapping('format') | |
| c67c70af | 115 | ->defaultValue($this->basicFormat->format); |
| 2518dfe3 MR |
116 | |
| 117 | // Unmapped source fields | |
| 118 | ||
| 119 | // Unmapped destination fields | |
| 2518dfe3 | 120 | $this->addFieldMapping('parent_name') |
| 79f72dcc MR |
121 | ->issueGroup(t('DNM')); |
| 122 | } | |
| 123 | } | |
| 124 | ||
| 20d432de | 125 | class WineVarietyMigration extends WineTermMigration { |
| 2518dfe3 MR |
126 | public function __construct() { |
| 127 | parent::__construct('variety', 'migrate_example_wine_varieties', | |
| 128 | t('Migrate varieties from the source database to taxonomy terms')); | |
| 129 | } | |
| 130 | } | |
| 131 | ||
| 20d432de | 132 | class WineRegionMigration extends WineTermMigration { |
| 2518dfe3 MR |
133 | public function __construct() { |
| 134 | parent::__construct('region', 'migrate_example_wine_regions', | |
| 135 | t('Migrate regions from the source database to taxonomy terms')); | |
| 136 | } | |
| 137 | } | |
| 138 | ||
| 20d432de | 139 | class WineBestWithMigration extends WineTermMigration { |
| 2518dfe3 MR |
140 | public function __construct() { |
| 141 | parent::__construct('best_with', 'migrate_example_wine_best_with', | |
| 142 | t('Migrate "Best With" from the source database to taxonomy terms')); | |
| 143 | } | |
| 144 | } | |
| 145 | ||
| 15c0ee92 MR |
146 | /** |
| 147 | * TIP: Files can be migrated directly by themselves, by using the MigrateDestinationFile | |
| 148 | * class. This will copy the files themselves from the source, and set up the | |
| 149 | * Drupal file tables appropriately. | |
| 150 | */ | |
| 151 | class WineFileMigration extends AdvancedExampleMigration { | |
| 152 | public function __construct() { | |
| 153 | parent::__construct(); | |
| 154 | $this->description = t('Profile images'); | |
| 155 | $this->dependencies = array('WinePrep'); | |
| 156 | $this->map = new MigrateSQLMap($this->machineName, | |
| 157 | array('imageid' => array( | |
| 158 | 'type' => 'int', | |
| 159 | 'unsigned' => TRUE, | |
| 160 | 'not null' => TRUE, | |
| 161 | 'description' => 'Image ID.' | |
| 162 | ) | |
| 163 | ), | |
| 164 | MigrateDestinationFile::getKeySchema() | |
| 165 | ); | |
| 166 | $query = db_select('migrate_example_wine_files', 'wf') | |
| cc029251 MR |
167 | ->fields('wf', array('imageid', 'url')) |
| 168 | ->isNull('wineid'); | |
| 15c0ee92 MR |
169 | $this->source = new MigrateSourceSQL($query); |
| 170 | ||
| 171 | // TIP: Set copy_file to copy the file from its source (which could be a | |
| 172 | // remote server, i.e. the uri is of the form http://example.com/images/foo.jpg). | |
| 173 | $this->destination = new MigrateDestinationFile(array('copy_file' => TRUE)); | |
| 174 | ||
| 175 | // Just map the incoming URL to the destination's 'uri' | |
| 176 | $this->addFieldMapping('uri', 'url'); | |
| 177 | $this->addUnmigratedDestinations(array('fid', 'uid', 'filename', 'status', | |
| 178 | 'filemime', 'timestamp')); | |
| 179 | } | |
| 180 | } | |
| 181 | ||
| c5ee5d7b MR |
182 | class WineRoleMigration extends XMLMigration { |
| 183 | public function __construct() { | |
| 184 | parent::__construct(); | |
| 185 | $this->description = t('XML feed (multi items) of roles (positions)'); | |
| 186 | $this->softDependencies = array('WineFile'); | |
| 187 | ||
| 188 | // There isn't a consistent way to automatically identify appropriate "fields" | |
| 189 | // from an XML feed, so we pass an explicit list of source fields | |
| 190 | $fields = array( | |
| 191 | 'name' => t('Position name'), | |
| 192 | ); | |
| 193 | ||
| 194 | // The source ID here is the one retrieved from each data item in the XML file, and | |
| 195 | // used to identify specific items | |
| 196 | $this->map = new MigrateSQLMap($this->machineName, | |
| 197 | array( | |
| 198 | 'sourceid' => array( | |
| 199 | 'type' => 'int', | |
| 200 | 'unsigned' => TRUE, | |
| 201 | 'not null' => TRUE, | |
| 202 | ) | |
| 203 | ), | |
| 204 | MigrateDestinationRole::getKeySchema() | |
| 205 | ); | |
| 206 | ||
| 207 | // This can also be an URL instead of a file path. | |
| 208 | $xml_folder = DRUPAL_ROOT . '/' . drupal_get_path('module', 'migrate_example') . '/xml/'; | |
| 209 | $items_url = $xml_folder . 'positions.xml'; | |
| 210 | $item_xpath = '/positions/position'; // relative to document | |
| 211 | $item_ID_xpath = 'sourceid'; // relative to item_xpath and gets assembled | |
| 212 | // into full path /producers/producer/sourceid | |
| 213 | ||
| 214 | $items_class = new MigrateItemsXML($items_url, $item_xpath, $item_ID_xpath); | |
| 215 | $this->source = new MigrateSourceMultiItems($items_class, $fields); | |
| 216 | ||
| 217 | $this->destination = new MigrateDestinationRole(); | |
| 218 | ||
| 219 | $this->addFieldMapping('name', 'name') | |
| 220 | ->xpath('name'); | |
| 221 | $this->addUnmigratedDestinations(array('weight')); | |
| 222 | } | |
| 223 | } | |
| 224 | ||
| 20d432de | 225 | class WineUserMigration extends AdvancedExampleMigration { |
| 79f72dcc MR |
226 | public function __construct() { |
| 227 | parent::__construct(); | |
| 228 | $this->description = t('Wine Drinkers of the world'); | |
| c5ee5d7b | 229 | $this->dependencies = array('WinePrep', 'WineFile', 'WineRole'); |
| 79f72dcc MR |
230 | $this->map = new MigrateSQLMap($this->machineName, |
| 231 | array('accountid' => array( | |
| 232 | 'type' => 'int', | |
| 2518dfe3 | 233 | 'unsigned' => TRUE, |
| 79f72dcc MR |
234 | 'not null' => TRUE, |
| 235 | 'description' => 'Account ID.' | |
| 236 | ) | |
| 237 | ), | |
| 238 | MigrateDestinationUser::getKeySchema() | |
| 239 | ); | |
| 2518dfe3 | 240 | $query = db_select('migrate_example_wine_account', 'wa') |
| e0c558fa MR |
241 | ->fields('wa', array('accountid', 'status', 'posted', 'name', |
| 242 | 'password', 'mail', 'last_access', 'last_login', | |
| c5ee5d7b | 243 | 'original_mail', 'sig', 'sex', 'imageid', 'positions')); |
| 9fadaa93 | 244 | $this->source = new MigrateSourceSQL($query); |
| 79f72dcc MR |
245 | $this->destination = new MigrateDestinationUser(); |
| 246 | ||
| 247 | // Mapped fields | |
| 552d9ae3 | 248 | $this->addSimpleMappings(array('name', 'status', 'mail')); |
| 79f72dcc MR |
249 | $this->addFieldMapping('created', 'posted') |
| 250 | ->description('See prepare method'); | |
| e0c558fa MR |
251 | $this->addFieldMapping('access', 'last_access') |
| 252 | ->description('See prepare method'); | |
| 253 | $this->addFieldMapping('login', 'last_login') | |
| 254 | ->description('See prepare method'); | |
| 79f72dcc | 255 | $this->addFieldMapping('pass', 'password'); |
| c5ee5d7b MR |
256 | $this->addFieldMapping('roles', 'positions') |
| 257 | ->separator(',') | |
| 258 | ->sourceMigration('WineRole'); | |
| e0c558fa MR |
259 | $this->addFieldMapping('signature', 'sig'); |
| 260 | $this->addFieldMapping('signature_format') | |
| c67c70af | 261 | ->defaultValue($this->basicFormat->format); |
| e0c558fa MR |
262 | $this->addFieldMapping('init', 'original_mail'); |
| 263 | $this->addFieldMapping('field_migrate_example_gender', 'sex') | |
| 264 | ->description(t('Map from M/F to 0/1 in prepare method')); | |
| 15c0ee92 MR |
265 | $this->addFieldMapping('picture', 'imageid') |
| 266 | ->sourceMigration('WineFile'); | |
| 79f72dcc MR |
267 | |
| 268 | // Unmapped source fields | |
| 79f72dcc MR |
269 | |
| 270 | // Unmapped destination fields | |
| 15c0ee92 | 271 | $this->addUnmigratedDestinations(array('theme', 'timezone', 'language')); |
| 79f72dcc MR |
272 | } |
| 273 | ||
| 274 | public function prepare(stdClass $account, stdClass $row) { | |
| 275 | // Source dates are in ISO format. | |
| 276 | // Because the mappings above have been applied, $account->created contains | |
| 277 | // the date/time string now - we could also pass $row->posted here. | |
| 278 | $account->created = strtotime($account->created); | |
| e0c558fa MR |
279 | $account->access = strtotime($account->access); |
| 280 | $account->login = strtotime($account->login); | |
| 281 | ||
| 282 | // Gender data comes in as M/F, needs to be saved as Male=0/Female=1 | |
| 283 | // TIP: Note that the Migration prepare method is called after all other | |
| 284 | // prepare handlers. Most notably, the field handlers have had their way | |
| 285 | // and created field arrays, so we have to save in the same format. | |
| 286 | switch ($row->sex) { | |
| 287 | case 'm': | |
| 288 | case 'M': | |
| 289 | $account->field_migrate_example_gender[LANGUAGE_NONE][0]['value'] = 0; | |
| 290 | break; | |
| 291 | case 'f': | |
| 292 | case 'F': | |
| 293 | $account->field_migrate_example_gender[LANGUAGE_NONE][0]['value'] = 1; | |
| 294 | break; | |
| 295 | default: | |
| 296 | unset($account->field_migrate_example_gender); | |
| 297 | break; | |
| 298 | } | |
| 79f72dcc MR |
299 | } |
| 300 | } | |
| 301 | ||
| 20d432de | 302 | class WineProducerMigration extends AdvancedExampleMigration { |
| 2518dfe3 MR |
303 | public function __construct() { |
| 304 | parent::__construct(); | |
| 305 | $this->description = t('Wine producers of the world'); | |
| 7a68c5aa | 306 | $this->dependencies = array('WineRegion', 'WineUser'); |
| 2518dfe3 MR |
307 | |
| 308 | $this->map = new MigrateSQLMap($this->machineName, | |
| 309 | array( | |
| 310 | 'producerid' => array( | |
| 311 | 'type' => 'int', | |
| 312 | 'unsigned' => TRUE, | |
| 313 | 'not null' => TRUE, | |
| 314 | 'alias' => 'p', | |
| 315 | ) | |
| 316 | ), | |
| 317 | MigrateDestinationNode::getKeySchema() | |
| 318 | ); | |
| 319 | ||
| 320 | $query = db_select('migrate_example_wine_producer', 'p') | |
| 321 | ->fields('p', array('producerid', 'name', 'body', 'excerpt', 'accountid')); | |
| 322 | // Region term is singletons, handled straighforwardly | |
| 323 | $query->leftJoin('migrate_example_wine_category_producer', 'reg', | |
| 324 | "p.producerid = reg.producerid"); | |
| 325 | $query->addField('reg', 'categoryid', 'region'); | |
| 326 | ||
| 9fadaa93 | 327 | $this->source = new MigrateSourceSQL($query); |
| 2518dfe3 MR |
328 | $this->destination = new MigrateDestinationNode('migrate_example_producer'); |
| 329 | ||
| 330 | // Mapped fields | |
| 331 | $this->addFieldMapping('title', 'name') | |
| 332 | ->description(t('Mapping producer name in source to node title')); | |
| 333 | $this->addFieldMapping('uid', 'accountid') | |
| 7a68c5aa | 334 | ->sourceMigration('WineUser') |
| 2518dfe3 MR |
335 | ->defaultValue(1); |
| 336 | $this->addFieldMapping('migrate_example_wine_regions', 'region') | |
| 7a68c5aa | 337 | ->sourceMigration('WineRegion') |
| 990a4601 | 338 | ->arguments(array('source_type' => 'tid')); |
| 2518dfe3 MR |
339 | $arguments = MigrateTextFieldHandler::arguments(array('source_field' => 'excerpt')); |
| 340 | $this->addFieldMapping('body', 'body') | |
| 341 | ->arguments($arguments); | |
| 342 | $this->addFieldMapping(NULL, 'excerpt'); | |
| 343 | $this->addFieldMapping('sticky') | |
| 344 | ->defaultValue(0); | |
| 345 | ||
| 346 | // No unmapped source fields | |
| 347 | ||
| 348 | // Unmapped destination fields | |
| 552d9ae3 MR |
349 | $this->addUnmigratedDestinations(array('is_new', 'name', 'created', 'changed', |
| 350 | 'status', 'promote', 'revision', 'language')); | |
| 2518dfe3 MR |
351 | } |
| 352 | } | |
| 353 | ||
| 990a4601 MR |
354 | /** |
| 355 | * TIP: An example of importing from an XML feed. See the files in the xml | |
| 356 | * directory - index.xml contains a list of IDs to import, and <id>.xml | |
| 357 | * is the data for a given producer. | |
| 358 | * | |
| 990a4601 MR |
359 | * Note that, if basing a migration on an XML source, you need to derive it |
| 360 | * from XMLMigration instead of Migration. | |
| 361 | */ | |
| 20d432de | 362 | class WineProducerXMLMigration extends XMLMigration { |
| 990a4601 MR |
363 | public function __construct() { |
| 364 | parent::__construct(); | |
| 365 | $this->description = t('XML feed of wine producers of the world'); | |
| 7a68c5aa | 366 | $this->dependencies = array('WineRegion', 'WineUser'); |
| 990a4601 | 367 | |
| 9023a77e MR |
368 | // There isn't a consistent way to automatically identify appropriate "fields" |
| 369 | // from an XML feed, so we pass an explicit list of source fields | |
| 370 | $fields = array( | |
| 371 | 'name' => t('Producer name'), | |
| 372 | 'description' => t('Description of producer'), | |
| 373 | 'authorid' => t('Numeric ID of the author'), | |
| 374 | 'region' => t('Name of region'), | |
| 375 | ); | |
| 376 | ||
| 990a4601 | 377 | // The source ID here is the one retrieved from the XML listing file, and |
| 9023a77e | 378 | // used to identify the specific item's file |
| 990a4601 MR |
379 | $this->map = new MigrateSQLMap($this->machineName, |
| 380 | array( | |
| 381 | 'sourceid' => array( | |
| 382 | 'type' => 'varchar', | |
| 383 | 'length' => 4, | |
| 384 | 'not null' => TRUE, | |
| 385 | ) | |
| 386 | ), | |
| 387 | MigrateDestinationNode::getKeySchema() | |
| 388 | ); | |
| 389 | ||
| b14ba196 | 390 | // This can also be an URL instead of a file path. |
| 391 | $xml_folder = DRUPAL_ROOT . '/' . drupal_get_path('module', 'migrate_example') . '/xml/'; | |
| 9023a77e MR |
392 | $list_url = $xml_folder . 'index.xml'; |
| 393 | // Each ID retrieved from the list URL will be plugged into :id in the | |
| 394 | // item URL to fetch the specific objects. | |
| 395 | $item_url = $xml_folder . ':id.xml'; | |
| 396 | ||
| 397 | // We use the MigrateSourceList class for any source where we obtain the list | |
| 398 | // of IDs to process separately from the data for each item. The listing | |
| 399 | // and item are represented by separate classes, so for example we could | |
| 400 | // replace the XML listing with a file directory listing, or the XML item | |
| 401 | // with a JSON item. | |
| 9fadaa93 | 402 | $this->source = new MigrateSourceList(new MigrateListXML($list_url), |
| 9023a77e | 403 | new MigrateItemXML($item_url), $fields); |
| 990a4601 MR |
404 | |
| 405 | $this->destination = new MigrateDestinationNode('migrate_example_producer'); | |
| 406 | ||
| 70380ea8 | 407 | // TIP: Note that for XML sources, in addition to the source field passed to |
| 990a4601 MR |
408 | // addFieldMapping (the name under which it will be saved in the data row |
| 409 | // passed through the migration process) we specify the Xpath used to retrieve | |
| 410 | // the value from the XML. | |
| 9023a77e | 411 | $this->addFieldMapping('title', 'name') |
| 990a4601 MR |
412 | ->xpath('/producer/name'); |
| 413 | $this->addFieldMapping('uid', 'authorid') | |
| 414 | ->xpath('/producer/authorid') | |
| 7a68c5aa | 415 | ->sourceMigration('WineUser') |
| 990a4601 MR |
416 | ->defaultValue(1); |
| 417 | $this->addFieldMapping('migrate_example_wine_regions', 'region') | |
| 418 | ->xpath('/producer/region'); | |
| 419 | $this->addFieldMapping('body', 'description') | |
| 420 | ->xpath('/producer/description'); | |
| 421 | } | |
| 422 | } | |
| 423 | ||
| 8e570661 MR |
424 | /** |
| 425 | * TIP: An example of importing from an XML feed where both the id and the | |
| 426 | * data to import are in the same file. The id is a part of the data. See | |
| 427 | * the file in the xml directory - producers.xml which contains all IDs and | |
| 428 | * producer data for this example. | |
| 429 | * | |
| 430 | * Note that, if basing a migration on an XML source, you need to derive it | |
| 431 | * from XMLMigration instead of Migration. | |
| 432 | */ | |
| 433 | class WineProducerMultiXMLMigration extends XMLMigration { | |
| 434 | public function __construct() { | |
| 435 | parent::__construct(); | |
| 436 | $this->description = t('XML feed (multi items) of wine producers of the world'); | |
| 437 | $this->dependencies = array('WineRegion', 'WineUser'); | |
| 438 | ||
| 439 | // There isn't a consistent way to automatically identify appropriate "fields" | |
| 440 | // from an XML feed, so we pass an explicit list of source fields | |
| 441 | $fields = array( | |
| 442 | 'name' => t('Producer name'), | |
| 443 | 'description' => t('Description of producer'), | |
| 444 | 'authorid' => t('Numeric ID of the author'), | |
| 445 | 'region' => t('Name of region'), | |
| 446 | ); | |
| 447 | ||
| 448 | // The source ID here is the one retrieved from each data item in the XML file, and | |
| 449 | // used to identify specific items | |
| 450 | $this->map = new MigrateSQLMap($this->machineName, | |
| 451 | array( | |
| 452 | 'sourceid' => array( | |
| 453 | 'type' => 'varchar', | |
| 454 | 'length' => 4, | |
| 455 | 'not null' => TRUE, | |
| 456 | ) | |
| 457 | ), | |
| 458 | MigrateDestinationNode::getKeySchema() | |
| 459 | ); | |
| 460 | ||
| 461 | ||
| 462 | // This can also be an URL instead of a file path. | |
| 463 | $xml_folder = DRUPAL_ROOT . '/' . drupal_get_path('module', 'migrate_example') . '/xml/'; | |
| 464 | $items_url = $xml_folder . 'producers.xml'; | |
| 465 | ||
| 466 | // We use the MigrateSourceMultiItems class for any source where we obtain the list | |
| 467 | // of IDs to process and the data for each item from the same file. Typically the data | |
| 468 | // for an item is not contained in a single line within the source file. Examples include | |
| 469 | // multiple items defined in a single xml file or a single json file where in both cases | |
| 470 | // the id is part of the item. | |
| 471 | ||
| 472 | $item_xpath = '/producers/producer'; // relative to document | |
| 473 | ||
| 474 | $item_ID_xpath = 'sourceid'; // relative to item_xpath and gets assembled | |
| 475 | // into full path /producers/producer/sourceid | |
| 476 | ||
| 477 | $items_class = new MigrateItemsXML($items_url, $item_xpath, $item_ID_xpath); | |
| 478 | $this->source = new MigrateSourceMultiItems($items_class, $fields); | |
| 479 | ||
| 480 | $this->destination = new MigrateDestinationNode('migrate_example_producer'); | |
| 481 | ||
| 482 | // TIP: Note that for XML sources, in addition to the source field passed to | |
| 483 | // addFieldMapping (the name under which it will be saved in the data row | |
| 484 | // passed through the migration process) we specify the Xpath used to retrieve | |
| 485 | // the value from the XML. | |
| 486 | // TIP: Note that all xpaths for fields begin at the last element of the item | |
| 487 | // xpath since each item xml chunk is processed individually. | |
| 488 | // (ex. xpath=name is equivalent to a full xpath of /producers/producer/name) | |
| 489 | $this->addFieldMapping('title', 'name') | |
| 490 | ->xpath('name'); | |
| 491 | $this->addFieldMapping('uid', 'authorid') | |
| 492 | ->xpath('authorid') | |
| 493 | ->sourceMigration('WineUser') | |
| 494 | ->defaultValue(1); | |
| 495 | $this->addFieldMapping('migrate_example_wine_regions', 'region') | |
| 496 | ->xpath('region'); | |
| 497 | $this->addFieldMapping('body', 'description') | |
| 498 | ->xpath('description'); | |
| 499 | } | |
| 500 | } | |
| 501 | ||
| 2518dfe3 | 502 | // TODO: Add node_reference field pointing to producer |
| 20d432de | 503 | class WineWineMigration extends AdvancedExampleMigration { |
| 79f72dcc MR |
504 | public function __construct() { |
| 505 | parent::__construct(); | |
| 506 | $this->description = t('Wines of the world'); | |
| 7a68c5aa MR |
507 | $this->dependencies = array('WineVariety', 'WineRegion', |
| 508 | 'WineBestWith', 'WineUser', 'WineProducer'); | |
| 79f72dcc MR |
509 | |
| 510 | $this->map = new MigrateSQLMap($this->machineName, | |
| 511 | array( | |
| 2518dfe3 | 512 | 'wineid' => array( |
| 79f72dcc | 513 | 'type' => 'int', |
| 2518dfe3 | 514 | 'unsigned' => TRUE, |
| 79f72dcc | 515 | 'not null' => TRUE, |
| 2518dfe3 MR |
516 | 'description' => 'Wine ID', |
| 517 | 'alias' => 'w', | |
| 79f72dcc MR |
518 | ) |
| 519 | ), | |
| 520 | MigrateDestinationNode::getKeySchema() | |
| 521 | ); | |
| 522 | ||
| 2518dfe3 | 523 | $query = db_select('migrate_example_wine', 'w') |
| e0c558fa | 524 | ->fields('w', array('wineid', 'name', 'body', 'excerpt', 'accountid', |
| 35e060d3 | 525 | 'posted', 'last_changed', 'variety', 'region', 'rating')); |
| 2518dfe3 MR |
526 | $query->leftJoin('migrate_example_wine_category_wine', 'cwbw', |
| 527 | "w.wineid = cwbw.wineid"); | |
| 528 | $query->leftJoin('migrate_example_wine_categories', 'bw', | |
| 529 | "cwbw.categoryid = bw.categoryid AND bw.type = 'best_with'"); | |
| 79f72dcc | 530 | // Gives a single comma-separated list of related terms |
| c67c70af | 531 | $query->groupBy('w.wineid'); |
| 2518dfe3 MR |
532 | $query->addExpression('GROUP_CONCAT(bw.categoryid)', 'best_with'); |
| 533 | ||
| 534 | $count_query = db_select('migrate_example_wine', 'w'); | |
| 535 | $count_query->addExpression('COUNT(wineid)', 'cnt'); | |
| 79f72dcc | 536 | |
| 68ffadc1 MR |
537 | // TIP: By passing an array of source fields to the MigrateSourceSQL constructor, |
| 538 | // we can modify the descriptions of source fields (which just default, for | |
| 539 | // SQL migrations, to table_alias.column_name), as well as add additional fields | |
| 540 | // (which may be populated in prepareRow()). | |
| 541 | $source_fields = array( | |
| 542 | 'wineid' => t('Wine ID in the old system'), | |
| 543 | 'name' => t('The name of the wine'), | |
| 544 | 'best_vintages' => t('What years were best for this wine?'), | |
| 35e060d3 | 545 | 'images' => t('Images attached to this wine; populated in prepareRow()'), |
| 68ffadc1 MR |
546 | ); |
| 547 | ||
| c67c70af MR |
548 | // TIP: By default, each time a migration is run, any previously unimported source items |
| 549 | // are imported (along with any previously-imported items marked for update). If the | |
| 550 | // source data contains a timestamp that is set to the creation time of each new item, | |
| 551 | // as well as set to the update time for any existing items that are updated, then | |
| 552 | // you can have those updated items automatically reimported by setting the field as | |
| 553 | // your highwater field. | |
| 554 | $this->highwaterField = array( | |
| 555 | 'name' => 'last_changed', // Column to be used as highwater mark | |
| 556 | 'alias' => 'w', // Table alias containing that column | |
| 557 | ); | |
| 558 | // Note that it is important to process rows in the order of the highwater mark | |
| 559 | $query->orderBy('last_changed'); | |
| 560 | ||
| 9fadaa93 | 561 | $this->source = new MigrateSourceSQL($query, $source_fields, $count_query); |
| 79f72dcc MR |
562 | $this->destination = new MigrateDestinationNode('migrate_example_wine'); |
| 563 | ||
| 564 | // Mapped fields | |
| 565 | $this->addFieldMapping('title', 'name') | |
| 566 | ->description(t('Mapping wine name in source to node title')); | |
| 79f72dcc | 567 | $this->addFieldMapping('uid', 'accountid') |
| 7a68c5aa | 568 | ->sourceMigration('WineUser') |
| 79f72dcc | 569 | ->defaultValue(1); |
| e0c558fa MR |
570 | // TIP: By default, term relationship are assumed to be passed by name. |
| 571 | // In this case, the source values are IDs, so we specify the relevant | |
| 572 | // migration (so the tid can be looked up in the map), and tell the term | |
| 573 | // field handler that it is receiving tids instead of names | |
| 2518dfe3 | 574 | $this->addFieldMapping('migrate_example_wine_varieties', 'variety') |
| 7a68c5aa | 575 | ->sourceMigration('WineVariety') |
| e0c558fa | 576 | ->arguments(array('source_type' => 'tid')); |
| 2518dfe3 | 577 | $this->addFieldMapping('migrate_example_wine_regions', 'region') |
| 7a68c5aa | 578 | ->sourceMigration('WineRegion') |
| e0c558fa | 579 | ->arguments(array('source_type' => 'tid')); |
| 2518dfe3 MR |
580 | $this->addFieldMapping('migrate_example_wine_best_with', 'best_with') |
| 581 | ->separator(',') | |
| 7a68c5aa | 582 | ->sourceMigration('WineBestWith') |
| e0c558fa | 583 | ->arguments(array('source_type' => 'tid')); |
| a934982b | 584 | $this->addFieldMapping('field_migrate_example_wine_ratin', 'rating'); |
| 70380ea8 | 585 | $this->addFieldMapping('field_migrate_example_top_vintag', 'best_vintages'); |
| 1e61b858 MR |
586 | |
| 587 | // TIP: You can apply one or more functions to a source value using ->callbacks(). | |
| 588 | // The function must take a single argument and return a value which is a | |
| 589 | // transformation of the argument. As this example shows, you can have multiple | |
| 590 | // callbacks, and they can either be straight functions or class methods. In | |
| 591 | // this case, our custom method prepends 'review: ' to the body, and then we | |
| 592 | // call a standard Drupal function to uppercase the whole body. | |
| 79f72dcc MR |
593 | $arguments = MigrateTextFieldHandler::arguments(array('source_field' => 'excerpt')); |
| 594 | $this->addFieldMapping('body', 'body') | |
| 1e61b858 MR |
595 | ->arguments($arguments) |
| 596 | ->callbacks(array($this, 'addTitlePrefix'), 'drupal_strtoupper'); | |
| 79f72dcc | 597 | $this->addFieldMapping(NULL, 'excerpt'); |
| 35e060d3 | 598 | // We will get the image data from a related table in prepareRow() |
| 15c0ee92 | 599 | $arguments = MigrateFileFieldHandler::arguments(NULL, 'file_copy', FILE_EXISTS_REPLACE); |
| 35e060d3 | 600 | $this->addFieldMapping('field_migrate_example_image', 'images') |
| 79f72dcc MR |
601 | ->arguments($arguments); |
| 602 | $this->addFieldMapping('sticky') | |
| 603 | ->defaultValue(0); | |
| e0c558fa MR |
604 | // These are already UNIX timestamps, so just pass through |
| 605 | $this->addFieldMapping('created', 'posted'); | |
| 606 | $this->addFieldMapping('changed', 'last_changed'); | |
| 79f72dcc MR |
607 | |
| 608 | // No unmapped source fields | |
| 609 | ||
| 610 | // Unmapped destination fields | |
| 552d9ae3 MR |
611 | $this->addUnmigratedDestinations(array('is_new', 'status', 'promote', |
| 612 | 'revision', 'language')); | |
| 79f72dcc | 613 | } |
| 70380ea8 | 614 | |
| 1e61b858 MR |
615 | protected function addTitlePrefix($source_title) { |
| 616 | return t('review: ') . $source_title; | |
| 617 | } | |
| 618 | ||
| 70380ea8 MR |
619 | // TIP: Implement a prepareRow() method to manipulate the source row between |
| 620 | // retrieval from the database and the automatic applicaton of mappings | |
| 621 | public function prepareRow($current_row) { | |
| 622 | // We can only handle a single multi-value source field using GROUP_CONCAT | |
| 623 | // as we did above - insert others with a query against the related table | |
| 624 | // with multiple values here, so the values can run through the mapping process | |
| 625 | $source_id = $current_row->wineid; | |
| 626 | $result = db_select('migrate_example_wine_vintages', 'v') | |
| 627 | ->fields('v', array('vintage')) | |
| 628 | ->condition('wineid', $source_id) | |
| 629 | ->execute(); | |
| 630 | foreach ($result as $row) { | |
| 631 | $current_row->best_vintages[] = $row->vintage; | |
| 632 | } | |
| 35e060d3 MR |
633 | |
| 634 | // An advanced feature of the file field handler is that in addition to the | |
| 635 | // path to the image itself, we can add image properties like ALT text, | |
| 636 | // encapsulating them as JSON | |
| 637 | $result = db_select('migrate_example_wine_files', 'f') | |
| 638 | ->fields('f', array('url', 'image_alt', 'image_title')) | |
| 639 | ->condition('wineid', $source_id) | |
| 640 | ->execute(); | |
| 641 | $current_row->images = array(); | |
| 642 | foreach ($result as $row) { | |
| 643 | $image_data = array( | |
| 644 | 'path' => $row->url, | |
| 645 | 'alt' => $row->image_alt, | |
| 646 | 'title' => $row->image_title, | |
| 647 | ); | |
| 648 | $current_row->images[] = drupal_json_encode($image_data); | |
| 649 | } | |
| 650 | ||
| 70380ea8 | 651 | // We could also have used this function to decide to skip a row, in cases |
| 35e060d3 | 652 | // where that couldn't easily be done through the original query. Simply |
| 70380ea8 MR |
653 | // return FALSE in such cases. |
| 654 | return TRUE; | |
| 655 | } | |
| 79f72dcc MR |
656 | } |
| 657 | ||
| 20d432de | 658 | class WineCommentMigration extends AdvancedExampleMigration { |
| 79f72dcc MR |
659 | public function __construct() { |
| 660 | parent::__construct(); | |
| 661 | $this->description = 'Comments about wines'; | |
| 7a68c5aa | 662 | $this->dependencies = array('WineUser', 'WineWine'); |
| 79f72dcc | 663 | $this->map = new MigrateSQLMap($this->machineName, |
| 2518dfe3 | 664 | array('commentid' => array( |
| 79f72dcc | 665 | 'type' => 'int', |
| 2518dfe3 | 666 | 'unsigned' => TRUE, |
| 79f72dcc MR |
667 | 'not null' => TRUE, |
| 668 | ) | |
| 669 | ), | |
| 670 | MigrateDestinationComment::getKeySchema() | |
| 671 | ); | |
| 2518dfe3 | 672 | $query = db_select('migrate_example_wine_comment', 'wc') |
| 4b52550a MR |
673 | ->fields('wc', array('commentid', 'comment_parent', 'name', 'mail', |
| 674 | 'accountid', 'body', 'wineid', 'subject', 'commenthost', 'userpage', | |
| 675 | 'posted', 'lastchanged')) | |
| 2518dfe3 | 676 | ->orderBy('comment_parent'); |
| 9fadaa93 | 677 | $this->source = new MigrateSourceSQL($query); |
| 79f72dcc MR |
678 | $this->destination = new MigrateDestinationComment('comment_node_migrate_example_wine'); |
| 679 | ||
| 680 | // Mapped fields | |
| 552d9ae3 | 681 | $this->addSimpleMappings(array('name', 'subject', 'mail')); |
| 79f72dcc MR |
682 | $this->addFieldMapping('status') |
| 683 | ->defaultValue(COMMENT_PUBLISHED); | |
| 4b52550a | 684 | $this->addFieldMapping('nid', 'wineid') |
| 7a68c5aa | 685 | ->sourceMigration('WineWine'); |
| 79f72dcc | 686 | $this->addFieldMapping('uid', 'accountid') |
| 7a68c5aa | 687 | ->sourceMigration('WineUser') |
| 79f72dcc | 688 | ->defaultValue(0); |
| 2518dfe3 | 689 | $this->addFieldMapping('pid', 'comment_parent') |
| 7a68c5aa | 690 | ->sourceMigration('WineComment') |
| 2518dfe3 | 691 | ->description('Parent comment'); |
| 79f72dcc | 692 | $this->addFieldMapping('comment_body', 'body'); |
| 4b52550a MR |
693 | $this->addFieldMapping('hostname', 'commenthost'); |
| 694 | $this->addFieldMapping('created', 'posted'); | |
| 695 | $this->addFieldMapping('changed', 'lastchanged'); | |
| 696 | $this->addFieldMapping('homepage', 'userpage'); | |
| 79f72dcc MR |
697 | |
| 698 | // No unmapped source fields | |
| 699 | ||
| 700 | // Unmapped destination fields | |
| 552d9ae3 | 701 | $this->addUnmigratedDestinations(array('thread', 'language')); |
| 79f72dcc MR |
702 | } |
| 703 | } | |
| 704 | ||
| 5ba25ed4 MR |
705 | // TIP: An easy way to simply migrate into a Drupal table (i.e., one defined |
| 706 | // through the Schema API) is to use the MigrateDestinationTable destination. | |
| 707 | // Just pass the table name to getKeySchema and the MigrateDestinationTable constructor. | |
| 708 | class WineTableMigration extends AdvancedExampleMigration { | |
| 709 | public function __construct() { | |
| 710 | parent::__construct(); | |
| 711 | $this->description = 'Miscellaneous table data'; | |
| 712 | $this->softDependencies = array('WineComment'); | |
| 713 | $table_name = 'migrate_example_wine_table_dest'; | |
| 714 | $this->map = new MigrateSQLMap($this->machineName, | |
| 715 | array('fooid' => array( | |
| 716 | 'type' => 'int', | |
| 717 | 'unsigned' => TRUE, | |
| 718 | 'not null' => TRUE, | |
| 719 | ) | |
| 720 | ), | |
| 721 | MigrateDestinationTable::getKeySchema($table_name) | |
| 722 | ); | |
| 723 | $query = db_select('migrate_example_wine_table_source', 't') | |
| 724 | ->fields('t', array('fooid', 'field1', 'field2')); | |
| 725 | $this->source = new MigrateSourceSQL($query); | |
| 726 | $this->destination = new MigrateDestinationTable($table_name); | |
| 727 | ||
| 728 | // Mapped fields | |
| 729 | $this->addFieldMapping('drupal_text', 'field1'); | |
| 730 | $this->addFieldMapping('drupal_int', 'field2'); | |
| 731 | ||
| 732 | $this->addUnmigratedDestinations(array('recordid')); | |
| 733 | } | |
| 734 | } | |
| 735 | ||
| 20d432de | 736 | class WineFinishMigration extends MigrationBase { |
| 79f72dcc MR |
737 | public function __construct() { |
| 738 | parent::__construct(); | |
| 4ab61127 | 739 | $this->description = t('If auto_nodetitle is present and was previously enabled, |
| 79f72dcc | 740 | re-enable it'); |
| 7a68c5aa | 741 | $this->dependencies = array('WineComment'); |
| 79f72dcc MR |
742 | } |
| 743 | public function isComplete() { | |
| 4ab61127 | 744 | if (module_exists('auto_nodetitle')) { |
| 79f72dcc MR |
745 | return TRUE; |
| 746 | } | |
| 747 | else { | |
| 748 | return FALSE; | |
| 749 | } | |
| 750 | } | |
| 751 | public function import() { | |
| 4ab61127 | 752 | if (!module_exists('auto_nodetitle')) { |
| 81da2cf8 MR |
753 | if (WinePrepMigration::$wasEnabled) { |
| 754 | module_enable(array('auto_nodetitle')); | |
| 755 | $this->showMessage(t('Re-enabled auto_nodetitle module'), 'success'); | |
| 756 | } | |
| 757 | else { | |
| 758 | $this->showMessage(t('auto_nodetitle was not originally enabled'), 'success'); | |
| 759 | } | |
| 2518dfe3 MR |
760 | } |
| 761 | else { | |
| 81da2cf8 | 762 | $this->showMessage(t('Auto_nodetitle module already enabled'), 'success'); |
| 79f72dcc | 763 | } |
| 79f72dcc MR |
764 | return Migration::RESULT_COMPLETED; |
| 765 | } | |
| 766 | } | |
| 176e6c7c MR |
767 | |
| 768 | /** | |
| 70380ea8 | 769 | * TIP: This demonstrates a migration designed not to import new content, but |
| 176e6c7c MR |
770 | * to update existing content (in this case, revised wine ratings) |
| 771 | */ | |
| 20d432de | 772 | class WineUpdatesMigration extends AdvancedExampleMigration { |
| 176e6c7c MR |
773 | public function __construct() { |
| 774 | parent::__construct(); | |
| 775 | $this->description = t('Update wine ratings'); | |
| 7a68c5aa MR |
776 | $this->dependencies = array('WineWine'); |
| 777 | $this->softDependencies = array('WineFinish'); | |
| 176e6c7c MR |
778 | |
| 779 | $this->map = new MigrateSQLMap($this->machineName, | |
| 780 | array( | |
| 781 | 'wineid' => array( | |
| 782 | 'type' => 'int', | |
| 783 | 'unsigned' => TRUE, | |
| 784 | 'not null' => TRUE, | |
| 785 | 'description' => 'Wine ID', | |
| 786 | 'alias' => 'w', | |
| 787 | ) | |
| 788 | ), | |
| 789 | MigrateDestinationNode::getKeySchema() | |
| 790 | ); | |
| 791 | ||
| 792 | $query = db_select('migrate_example_wine_updates', 'w') | |
| 793 | ->fields('w', array('wineid', 'rating')); | |
| 794 | ||
| 9fadaa93 | 795 | $this->source = new MigrateSourceSQL($query); |
| 176e6c7c MR |
796 | $this->destination = new MigrateDestinationNode('migrate_example_wine'); |
| 797 | ||
| 798 | // Indicate we're updating existing data. The default, Migration::SOURCE, would | |
| 799 | // cause existing nodes to be completely replaced by the source data. In this | |
| 800 | // case, the existing node will be loaded and only the rating altered. | |
| 801 | $this->systemOfRecord = Migration::DESTINATION; | |
| 802 | ||
| 803 | // Mapped fields | |
| 804 | // The destination handler needs the nid to change - since the incoming data | |
| 805 | // has a source id, not a nid, we need to apply the original wine migration | |
| 806 | // mapping to populate the nid. | |
| 807 | $this->addFieldMapping('nid', 'wineid') | |
| 7a68c5aa | 808 | ->sourceMigration('WineWine'); |
| 176e6c7c MR |
809 | $this->addFieldMapping('field_migrate_example_wine_ratin', 'rating'); |
| 810 | ||
| 811 | // No unmapped source fields | |
| 812 | ||
| 813 | // Unmapped destination fields | |
| 814 | $this->addFieldMapping('uid'); | |
| 815 | $this->addFieldMapping('migrate_example_wine_varieties'); | |
| 816 | $this->addFieldMapping('migrate_example_wine_regions'); | |
| 817 | $this->addFieldMapping('migrate_example_wine_best_with'); | |
| 818 | $this->addFieldMapping('body'); | |
| 819 | $this->addFieldMapping('field_migrate_example_image'); | |
| 820 | $this->addFieldMapping('sticky'); | |
| 821 | $this->addFieldMapping('created'); | |
| 822 | $this->addFieldMapping('changed'); | |
| 552d9ae3 MR |
823 | $this->addUnmigratedDestinations(array('is_new', 'status', 'promote', |
| 824 | 'revision', 'language')); | |
| 176e6c7c MR |
825 | } |
| 826 | } | |
| 827 | ||
| 20d432de | 828 | class WineCommentUpdatesMigration extends AdvancedExampleMigration { |
| 176e6c7c MR |
829 | public function __construct() { |
| 830 | parent::__construct(); | |
| 831 | $this->description = 'Update wine comments'; | |
| 7a68c5aa MR |
832 | $this->dependencies = array('WineComment'); |
| 833 | $this->softDependencies = array('WineUpdates'); | |
| 176e6c7c MR |
834 | $this->map = new MigrateSQLMap($this->machineName, |
| 835 | array('commentid' => array( | |
| 836 | 'type' => 'int', | |
| 837 | 'unsigned' => TRUE, | |
| 838 | 'not null' => TRUE, | |
| 839 | ) | |
| 840 | ), | |
| 841 | MigrateDestinationComment::getKeySchema() | |
| 842 | ); | |
| 843 | $query = db_select('migrate_example_wine_comment_updates', 'wc') | |
| 844 | ->fields('wc', array('commentid', 'subject')); | |
| 9fadaa93 | 845 | $this->source = new MigrateSourceSQL($query); |
| 176e6c7c MR |
846 | $this->destination = new MigrateDestinationComment('comment_node_migrate_example_wine'); |
| 847 | $this->systemOfRecord = Migration::DESTINATION; | |
| 848 | ||
| 849 | // Mapped fields | |
| 850 | $this->addFieldMapping('cid', 'commentid') | |
| 7a68c5aa | 851 | ->sourceMigration('WineComment'); |
| 176e6c7c MR |
852 | $this->addFieldMapping('subject', 'subject'); |
| 853 | ||
| 854 | // No unmapped source fields | |
| 855 | ||
| 856 | // Unmapped destination fields | |
| 857 | $this->addFieldMapping('name'); | |
| 858 | $this->addFieldMapping('mail'); | |
| 859 | $this->addFieldMapping('status'); | |
| 860 | $this->addFieldMapping('nid'); | |
| 861 | $this->addFieldMapping('uid'); | |
| 862 | $this->addFieldMapping('pid'); | |
| 863 | $this->addFieldMapping('comment_body'); | |
| 864 | $this->addFieldMapping('hostname'); | |
| 865 | $this->addFieldMapping('created'); | |
| 866 | $this->addFieldMapping('changed'); | |
| 867 | $this->addFieldMapping('homepage'); | |
| 552d9ae3 | 868 | $this->addUnmigratedDestinations(array('thread', 'language')); |
| 176e6c7c MR |
869 | } |
| 870 | } | |
| 871 | ||
| 20d432de | 872 | class WineVarietyUpdatesMigration extends AdvancedExampleMigration { |
| 176e6c7c MR |
873 | public function __construct() { |
| 874 | parent::__construct(); | |
| 875 | $this->description = t('Migrate varieties from the source database to taxonomy terms'); | |
| 7a68c5aa MR |
876 | $this->dependencies = array('WineVariety'); |
| 877 | $this->softDependencies = array('WineUpdates'); | |
| 176e6c7c MR |
878 | $this->map = new MigrateSQLMap($this->machineName, |
| 879 | array( | |
| 880 | 'categoryid' => array('type' => 'int', | |
| 881 | 'unsigned' => TRUE, | |
| 882 | 'not null' => TRUE, | |
| 883 | ) | |
| 884 | ), | |
| 885 | MigrateDestinationTerm::getKeySchema() | |
| 886 | ); | |
| 887 | ||
| 888 | $query = db_select('migrate_example_wine_variety_updates', 'wc') | |
| 889 | ->fields('wc', array('categoryid', 'details')); | |
| 9fadaa93 | 890 | $this->source = new MigrateSourceSQL($query); |
| 176e6c7c MR |
891 | $this->destination = new MigrateDestinationTerm('migrate_example_wine_varieties'); |
| 892 | $this->systemOfRecord = Migration::DESTINATION; | |
| 893 | ||
| 894 | // Mapped fields | |
| 895 | $this->addFieldMapping('tid', 'categoryid') | |
| 7a68c5aa | 896 | ->sourceMigration('WineVariety'); |
| 176e6c7c MR |
897 | $this->addFieldMapping('description', 'details'); |
| 898 | ||
| 899 | // Unmapped source fields | |
| 900 | ||
| 901 | // Unmapped destination fields | |
| 902 | $this->addFieldMapping('name'); | |
| 903 | $this->addFieldMapping('parent'); | |
| 904 | $this->addFieldMapping('weight'); | |
| 905 | $this->addFieldMapping('format'); | |
| 906 | $this->addFieldMapping('parent_name') | |
| 907 | ->issueGroup(t('DNM')); | |
| 908 | } | |
| 909 | } | |
| 910 | ||
| 911 | ||
| 20d432de | 912 | class WineUserUpdatesMigration extends AdvancedExampleMigration { |
| 176e6c7c MR |
913 | public function __construct() { |
| 914 | parent::__construct(); | |
| 915 | $this->description = t('Account updates'); | |
| 7a68c5aa MR |
916 | $this->dependencies = array('WineUser'); |
| 917 | $this->softDependencies = array('WineUpdates'); | |
| 176e6c7c MR |
918 | $this->map = new MigrateSQLMap($this->machineName, |
| 919 | array('accountid' => array( | |
| 920 | 'type' => 'int', | |
| 921 | 'unsigned' => TRUE, | |
| 922 | 'not null' => TRUE, | |
| 923 | 'description' => 'Account ID.' | |
| 924 | ) | |
| 925 | ), | |
| 926 | MigrateDestinationUser::getKeySchema() | |
| 927 | ); | |
| 928 | $query = db_select('migrate_example_wine_account_updates', 'wa') | |
| 929 | ->fields('wa', array('accountid', 'sex')); | |
| 9fadaa93 | 930 | $this->source = new MigrateSourceSQL($query); |
| 176e6c7c MR |
931 | $this->destination = new MigrateDestinationUser(); |
| 932 | $this->systemOfRecord = Migration::DESTINATION; | |
| 933 | ||
| 934 | // Mapped fields | |
| 935 | $this->addFieldMapping('uid', 'accountid') | |
| 7a68c5aa | 936 | ->sourceMigration('WineUser'); |
| 176e6c7c MR |
937 | $this->addFieldMapping('field_migrate_example_gender', 'sex') |
| 938 | ->description(t('Map from M/F to 0/1 in prepare method')); | |
| 939 | ||
| 940 | // Unmapped source fields | |
| 941 | ||
| 942 | // Unmapped destination fields | |
| 943 | $this->addFieldMapping('name'); | |
| 944 | $this->addFieldMapping('status'); | |
| 945 | $this->addFieldMapping('created'); | |
| 946 | $this->addFieldMapping('access'); | |
| 947 | $this->addFieldMapping('login'); | |
| 948 | $this->addFieldMapping('mail'); | |
| 949 | $this->addFieldMapping('pass'); | |
| 950 | $this->addFieldMapping('roles'); | |
| 951 | $this->addFieldMapping('signature'); | |
| 952 | $this->addFieldMapping('signature_format'); | |
| 953 | $this->addFieldMapping('init'); | |
| 552d9ae3 | 954 | $this->addUnmigratedDestinations(array('theme', 'timezone', 'language', 'picture')); |
| 176e6c7c MR |
955 | } |
| 956 | ||
| 957 | public function prepare(stdClass $account, stdClass $row) { | |
| 958 | // Gender data comes in as M/F, needs to be saved as Male=0/Female=1 | |
| 959 | // TIP: Note that the Migration prepare method is called after all other | |
| 960 | // prepare handlers. Most notably, the field handlers have had their way | |
| 961 | // and created field arrays, so we have to save in the same format. | |
| 962 | switch ($row->sex) { | |
| 963 | case 'm': | |
| 964 | case 'M': | |
| 965 | $account->field_migrate_example_gender[LANGUAGE_NONE][0]['value'] = 0; | |
| 966 | break; | |
| 967 | case 'f': | |
| 968 | case 'F': | |
| 969 | $account->field_migrate_example_gender[LANGUAGE_NONE][0]['value'] = 1; | |
| 970 | break; | |
| 971 | default: | |
| 73658591 | 972 | $account->field_migrate_example_gender = NULL; |
| 176e6c7c MR |
973 | break; |
| 974 | } | |
| 975 | } | |
| 976 | } |