diff --git a/docroot/sites/all/modules/contrib/migrate/includes/base.inc b/docroot/sites/all/modules/contrib/migrate/includes/base.inc index c83a2dfe..6d2a47f8 100644 --- a/docroot/sites/all/modules/contrib/migrate/includes/base.inc +++ b/docroot/sites/all/modules/contrib/migrate/includes/base.inc @@ -736,7 +736,7 @@ abstract class MigrationBase { * An array that points to the active symbol table at the point the error * occurred. */ - public function errorHandler($error_level, $message, $filename, $line, $context) { + public function errorHandler($error_level, $message, $filename, $line, $context = array()) { if ($error_level & error_reporting()) { $message .= "\n" . t('File !file, line !line', array('!line' => $line, '!file' => $filename)); @@ -806,10 +806,11 @@ abstract class MigrationBase { ->condition('machine_name', $this->machineName) ->isNotNull('endtime') ->orderBy('endtime', 'DESC') + ->range(0, 1) ->execute() ->fetchField(); if ($last_imported) { - $last_imported = date('Y-m-d H:i:s', $last_imported / 1000); + $last_imported = date('Y-m-d H:i:s', (int) ($last_imported / 1000)); } else { $last_imported = ''; @@ -1050,6 +1051,17 @@ abstract class MigrationBase { $this->processing = FALSE; } self::$currentMigration = NULL; + + // If we're disabling any hooks, reset the static module_implements cache so + // it is rebuilt again and the specified hooks removed by our + // hook_module_implements_alter() is recollected. By setting #write_cache to + // FALSE, we ensure that our munged version of the hooks array does not get + // written to the persistent cache and interfere with other Drupal processes. + if (!empty($this->disableHooks)) { + $implementations = &drupal_static('module_implements'); + $implementations = array(); + $implementations['#write_cache'] = FALSE; + } } /** diff --git a/docroot/sites/all/modules/contrib/migrate/includes/migration.inc b/docroot/sites/all/modules/contrib/migrate/includes/migration.inc index d66b601a..36fc5e6c 100644 --- a/docroot/sites/all/modules/contrib/migrate/includes/migration.inc +++ b/docroot/sites/all/modules/contrib/migrate/includes/migration.inc @@ -242,6 +242,8 @@ abstract class Migration extends MigrationBase { */ protected $queuedMessages = array(); + protected $subfieldDelimiter = ':'; + /** * General initialization of a Migration object. */ @@ -749,33 +751,17 @@ abstract class Migration extends MigrationBase { $ids = $this->destination->import($this->destinationValues, $this->sourceValues); migrate_instrument_stop('destination import'); if ($ids) { - $this->map->saveIDMapping($this->sourceValues, $ids, - $this->needsUpdate, $this->rollbackAction, - $data_row->migrate_map_hash); - $this->successes_since_feedback++; - $this->total_successes++; + $this->onSuccess($data_row, $ids); } else { - $this->map->saveIDMapping($this->sourceValues, array(), - MigrateMap::STATUS_FAILED, $this->rollbackAction, - NULL); - if ($this->map->messageCount() == 0) { - $message = t('New object was not saved, no error provided'); - $this->saveMessage($message); - self::displayMessage($message); - } + $this->onEmptyDestination($data_row, $ids); } } catch (MigrateException $e) { - $this->map->saveIDMapping($this->sourceValues, array(), - $e->getStatus(), $this->rollbackAction, $data_row->migrate_map_hash); - $this->saveMessage($e->getMessage(), $e->getLevel()); - self::displayMessage($e->getMessage()); + $this->onMigrateException($e, $data_row); } catch (Exception $e) { - $this->map->saveIDMapping($this->sourceValues, array(), - MigrateMap::STATUS_FAILED, $this->rollbackAction, - NULL); - $this->handleException($e); + $this->onException($e); } + $this->total_processed++; $this->processed_since_feedback++; if ($this->highwaterField) { @@ -821,6 +807,68 @@ abstract class Migration extends MigrationBase { return $return; } + /** + * React when the migration has been successful. + * + * @param object $data_row + * Data. + * @param array $ids + * Destination ids. + */ + protected function onSuccess($data_row, $ids) { + $this->map->saveIDMapping($this->sourceValues, $ids, + $this->needsUpdate, $this->rollbackAction, + $data_row->migrate_map_hash); + $this->successes_since_feedback++; + $this->total_successes++; + } + + /** + * React when migration didn't failed but destination ids are empty. + * + * @param object $data_row + * Data. + * @param array $ids + * Destination ids. + */ + protected function onEmptyDestination($data_row, $ids) { + $this->map->saveIDMapping($this->sourceValues, array(), + MigrateMap::STATUS_FAILED, $this->rollbackAction, + NULL); + if ($this->map->messageCount() == 0) { + $message = t('New object was not saved, no error provided'); + $this->saveMessage($message); + self::displayMessage($message); + } + } + + /** + * React when there is a migrate exception + * + * @param \MigrateException $e + * Exception. + * + */ + protected function onMigrateException(\MigrateException $e, $data_row) { + $this->map->saveIDMapping($this->sourceValues, array(), + $e->getStatus(), $this->rollbackAction, $data_row->migrate_map_hash); + $this->saveMessage($e->getMessage(), $e->getLevel()); + self::displayMessage($e->getMessage()); + } + + /** + * React when there is an exception + * + * @param \Exception $e + * Exception. + */ + protected function onException(\Exception $e) { + $this->map->saveIDMapping($this->sourceValues, array(), + MigrateMap::STATUS_FAILED, $this->rollbackAction, + NULL); + $this->handleException($e); + } + /** * Perform an analysis operation - report on field values in the source. * @@ -1328,7 +1376,7 @@ abstract class Migration extends MigrationBase { // Are we dealing with the primary value of the destination field, or a // subfield? - $destination = explode(':', $destination); + $destination = explode($this->subfieldDelimiter, $destination); // Count how many levels of fields are in the mapping. We'll use the // last one. $destination_count = count($destination); @@ -1358,7 +1406,11 @@ abstract class Migration extends MigrationBase { elseif (!is_array($this->destinationValues->{$destination_field})) { $this->destinationValues->{$destination_field} = array($this->destinationValues->{$destination_field}); } - if (!is_array($this->destinationValues->{$destination_field}['arguments'][$destination[1]])) { + // Additional check for case when first subfield doesn't exist. + if (!isset($this->destinationValues->{$destination_field}['arguments'][$destination[1]])) { + $this->destinationValues->{$destination_field}['arguments'][$destination[1]] = array(); + } + elseif (!is_array($this->destinationValues->{$destination_field}['arguments'][$destination[1]])) { // Convert first subfield level to an array so we can add to it. $this->destinationValues->{$destination_field}['arguments'][$destination[1]] = array($this->destinationValues->{$destination_field}['arguments'][$destination[1]]); } @@ -1449,7 +1501,7 @@ abstract class Migration extends MigrationBase { } } // Occasionally $source_key comes through with an empty string. - $sanity_check = array_filter($source_key); + $sanity_check = array_filter($source_key, 'strlen'); if ($continue || empty($source_key) || empty($sanity_check)) { continue; } diff --git a/docroot/sites/all/modules/contrib/migrate/includes/source.inc b/docroot/sites/all/modules/contrib/migrate/includes/source.inc index 54e4df39..63475ff7 100644 --- a/docroot/sites/all/modules/contrib/migrate/includes/source.inc +++ b/docroot/sites/all/modules/contrib/migrate/includes/source.inc @@ -226,6 +226,7 @@ abstract class MigrateSource implements Iterator { * Implementation of Iterator::current() - called when entering a loop * iteration, returning the current row */ + #[\ReturnTypeWillChange] public function current() { return $this->currentRow; } @@ -236,6 +237,7 @@ abstract class MigrateSource implements Iterator { * serialize to fulfill the requirement, but using getCurrentKey() is * preferable. */ + #[\ReturnTypeWillChange] public function key() { return serialize($this->currentKey); } @@ -244,6 +246,7 @@ abstract class MigrateSource implements Iterator { * Implementation of Iterator::valid() - called at the top of the loop, * returning TRUE to process the loop and FALSE to terminate it */ + #[\ReturnTypeWillChange] public function valid() { return !is_null($this->currentRow); } @@ -253,6 +256,7 @@ abstract class MigrateSource implements Iterator { * implement performRewind() to do any class-specific setup for iterating * source records. */ + #[\ReturnTypeWillChange] public function rewind() { $this->activeMigration = Migration::currentMigration(); $this->activeMap = $this->activeMigration->getMap(); @@ -278,6 +282,7 @@ abstract class MigrateSource implements Iterator { * Implementation of Iterator::next() - subclasses of MigrateSource should * implement getNextRow() to retrieve the next valid source rocord to process. */ + #[\ReturnTypeWillChange] public function next() { $this->currentKey = NULL; $this->currentRow = NULL; diff --git a/docroot/sites/all/modules/contrib/migrate/migrate.drush.inc b/docroot/sites/all/modules/contrib/migrate/migrate.drush.inc index 6a784ef1..c1bec2ed 100644 --- a/docroot/sites/all/modules/contrib/migrate/migrate.drush.inc +++ b/docroot/sites/all/modules/contrib/migrate/migrate.drush.inc @@ -1270,6 +1270,13 @@ function drush_migrate_import($args = NULL) { } if (drush_get_option('needs-update')) { $map_rows = $migration->getMap()->getRowsNeedingUpdate(10000); + + if (empty($map_rows)) { + drush_set_error(NULL, dt("Not found records to update for '!name' migration.", + array('!name' => get_class($migration)))); + return; + } + $idlist = array(); foreach ($map_rows as $row) { $idlist[] = $row->sourceid1; @@ -1431,7 +1438,7 @@ function drush_migrate_deregister($args = NULL) { $migrations = explode(',', $args); } foreach ($migrations as $machine_name) { - drush_migrate_deregister_migration(drupal_strtolower($machine_name)); + drush_migrate_deregister_migration($machine_name); drush_log(dt("Deregistered '!description' migration", array('!description' => $machine_name)), 'success'); } @@ -1445,13 +1452,15 @@ function drush_migrate_deregister($args = NULL) { /** * Given a migration machine name, remove its tracking from the database. * - * @param $machine_name + * @param string $machine_name + * Migration machine name. */ function drush_migrate_deregister_migration($machine_name) { + $machine_name_lowered = drupal_strtolower($machine_name); // The class is gone, so we'll manually clear migrate_status, and make // the default assumptions about the map/message tables. - db_drop_table('migrate_map_' . $machine_name); - db_drop_table('migrate_message_' . $machine_name); + db_drop_table('migrate_map_' . $machine_name_lowered); + db_drop_table('migrate_message_' . $machine_name_lowered); db_delete('migrate_status') ->condition('machine_name', $machine_name) ->execute(); diff --git a/docroot/sites/all/modules/contrib/migrate/migrate.info b/docroot/sites/all/modules/contrib/migrate/migrate.info index 695bbb03..6ac4a896 100644 --- a/docroot/sites/all/modules/contrib/migrate/migrate.info +++ b/docroot/sites/all/modules/contrib/migrate/migrate.info @@ -39,7 +39,7 @@ files[] = plugins/sources/mongodb.inc files[] = plugins/sources/multiitems.inc files[] = plugins/sources/sql.inc files[] = plugins/sources/sqlmap.inc -files[] = plugins/sources/mssql.inc +files[] = plugins/sources/sqlsrv.inc files[] = plugins/sources/oracle.inc files[] = plugins/sources/spreadsheet.inc files[] = plugins/sources/xml.inc @@ -51,8 +51,8 @@ files[] = tests/plugins/destinations/term.test files[] = tests/plugins/destinations/user.test files[] = tests/plugins/sources/xml.test -; Information added by Drupal.org packaging script on 2018-06-10 -version = "7.x-2.11" +; Information added by Drupal.org packaging script on 2023-01-15 +version = "7.x-2.12" core = "7.x" project = "migrate" -datestamp = "1528674486" +datestamp = "1673814412" diff --git a/docroot/sites/all/modules/contrib/migrate/migrate.module b/docroot/sites/all/modules/contrib/migrate/migrate.module index 3d9e1be1..f4f83391 100644 --- a/docroot/sites/all/modules/contrib/migrate/migrate.module +++ b/docroot/sites/all/modules/contrib/migrate/migrate.module @@ -191,17 +191,40 @@ function migrate_handler_invoke_all($destination, $method) { * @param $method * Handler method to call (defaults to prepare()). */ -function migrate_field_handler_invoke_all($entity, array $field_info, - array $instance, array $values, $method = 'prepare') { +function migrate_field_handler_invoke_all($entity, array $field_info, array $instance, array $values, $method = 'prepare') { + static $types_handled = array(); + static $methods_handled = array(); + static $disabled = null; $return = array(); $type = $field_info['type']; - $class_list = _migrate_class_list('MigrateFieldHandler'); - $disabled = unserialize(variable_get('migrate_disabled_handlers', - serialize(array()))); + static $class_list = null; + if (!$class_list) { + $class_list = _migrate_class_list('MigrateFieldHandler'); + } + // No need to do this unserialize/variable_get/serialize so often, + // it never changes. + if(!is_array($disabled)){ + $disabled = unserialize(variable_get('migrate_disabled_handlers', + serialize(array()))); + } + // This function is called a lot. Rather than determine if the field type is + // handled once for every record, the value should be determined once per + // execution. + // The same can go for whether the handler/method pair exists + if(!isset($types_handled[$type])){ + foreach($class_list as $class_name => $handler) { + $types_handled[$type][$class_name] = $handler->handlesType($type); + } + } + if(!isset($methods_handled[$method])){ + foreach($class_list as $class_name => $handler) { + $methods_handled[$method][$class_name] = method_exists($handler, $method); + } + } + $handler_called = FALSE; foreach ($class_list as $class_name => $handler) { - if (!in_array($class_name, $disabled) && $handler->handlesType($type) - && method_exists($handler, $method)) { + if (!in_array($class_name, $disabled) && $types_handled[$type][$class_name] && $methods_handled[$method][$class_name]) { migrate_instrument_start($class_name . '->' . $method); $result = call_user_func_array(array($handler, $method), array($entity, $field_info, $instance, $values)); diff --git a/docroot/sites/all/modules/contrib/migrate/migrate/migrate.views_default.inc b/docroot/sites/all/modules/contrib/migrate/migrate/migrate.views_default.inc new file mode 100644 index 00000000..9c6bad87 --- /dev/null +++ b/docroot/sites/all/modules/contrib/migrate/migrate/migrate.views_default.inc @@ -0,0 +1,116 @@ +getMap(); + $migration_name = $migration->getMachineName(); + if (!is_a($map, 'MigrateSQLMap')) { + continue; + } + + // Skip non-entities. + $destination = $migration->getDestination(); + if (!is_a($destination, 'MigrateDestinationEntity')) { + continue; + } + + $view = migrate_views_default_views_get_view($migration); + + // Add view to list of views to provide. + $views[$view->name] = $view; + + } + return $views; +} + +/** + * Helper for migrate_views_default_views() to get a single view. + * + * @param $migration + * A migration object. + * + * @return + * A view object. + */ +function migrate_views_default_views_get_view($migration) { + $migration_name = $migration->getMachineName(); + $destination = $migration->getDestination(); + $entity_type = $destination->getEntityType(); + $entity_info = entity_get_info($entity_type); + $entity_base_table = $entity_info['base table']; + $map_table = $migration->getMap()->getMapTable(); + + // The ID for the relationship from the entity base table. + $map_table_relationship_id = 'migrate_map_' . $map_table; + + // Use the same logic as the Views wizard to figure out a field to add to the + // view. + $data = views_fetch_data($entity_base_table); + if (isset($data['table']['base']['defaults']['field'])) { + $field = $data['table']['base']['defaults']['field']; + } + else { + foreach ($data as $field => $field_data) { + if (isset($field_data['field']['handler'])) { + break; + } + } + } + + $view = new view; + $view->name = 'migrate_' . $migration_name; + $view->description = 'Audit view for the migration ' . $migration_name; + $view->tag = 'migrate'; + $view->base_table = $entity_base_table; + $view->human_name = $migration_name; + $view->core = 0; + $view->api_version = '3.0'; + $view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */ + + /* Display: Master */ + $handler = $view->new_display('default', 'Master', 'default'); + $handler->display->display_options['title'] = 'Audit for migration ' . $migration_name; + $handler->display->display_options['access']['type'] = 'perm'; + $handler->display->display_options['access']['perm'] = 'migration information'; + $handler->display->display_options['cache']['type'] = 'none'; + $handler->display->display_options['query']['type'] = 'views_query'; + $handler->display->display_options['query']['options']['query_comment'] = FALSE; + $handler->display->display_options['exposed_form']['type'] = 'basic'; + $handler->display->display_options['pager']['type'] = 'full'; + $handler->display->display_options['pager']['options']['items_per_page'] = '100'; + $handler->display->display_options['style_plugin'] = 'table'; + /* Relationship: Content: Migration map */ + $handler->display->display_options['relationships'][$map_table_relationship_id]['id'] = $map_table_relationship_id; + $handler->display->display_options['relationships'][$map_table_relationship_id]['table'] = $entity_base_table; + $handler->display->display_options['relationships'][$map_table_relationship_id]['field'] = $map_table_relationship_id; + $handler->display->display_options['relationships'][$map_table_relationship_id]['required'] = TRUE; + /* Field: Entity ID for the entity type */ + if (isset($entity_info['entity keys']['id'])) { + $entity_id_key = $entity_info['entity keys']['id']; + if (isset($data[$entity_id_key]['field']['handler'])) { + $handler->display->display_options['fields'][$entity_id_key]['id'] = $entity_id_key; + $handler->display->display_options['fields'][$entity_id_key]['table'] = $entity_base_table; + $handler->display->display_options['fields'][$entity_id_key]['field'] = $entity_id_key; + } + } + /* Field: Default field for the entity type */ + $handler->display->display_options['fields'][$field]['id'] = $field; + $handler->display->display_options['fields'][$field]['table'] = $entity_base_table; + $handler->display->display_options['fields'][$field]['field'] = $field; + /* Display: Page */ + $handler = $view->new_display('page', 'Page', 'page'); + $handler->display->display_options['path'] = 'admin/content/migrate/audit/' . $migration_name; + + return $view; +} diff --git a/docroot/sites/all/modules/contrib/migrate/migrate_example/migrate_example.info b/docroot/sites/all/modules/contrib/migrate/migrate_example/migrate_example.info index bef523c8..ef8fb0d4 100644 --- a/docroot/sites/all/modules/contrib/migrate/migrate_example/migrate_example.info +++ b/docroot/sites/all/modules/contrib/migrate/migrate_example/migrate_example.info @@ -18,8 +18,8 @@ files[] = wine.inc ; For testing table_copy plugin. Since is infrequently used, we comment it out. ; files[] = example.table_copy.inc -; Information added by Drupal.org packaging script on 2018-06-10 -version = "7.x-2.11" +; Information added by Drupal.org packaging script on 2023-01-15 +version = "7.x-2.12" core = "7.x" project = "migrate" -datestamp = "1528674486" +datestamp = "1673814412" diff --git a/docroot/sites/all/modules/contrib/migrate/migrate_example/migrate_example_oracle/migrate_example_oracle.info b/docroot/sites/all/modules/contrib/migrate/migrate_example/migrate_example_oracle/migrate_example_oracle.info index a2be32ff..fa115442 100644 --- a/docroot/sites/all/modules/contrib/migrate/migrate_example/migrate_example_oracle/migrate_example_oracle.info +++ b/docroot/sites/all/modules/contrib/migrate/migrate_example/migrate_example_oracle/migrate_example_oracle.info @@ -11,8 +11,8 @@ name = "Migrate example - Oracle" package = "Migration" project = "migrate_example_oracle" -; Information added by Drupal.org packaging script on 2018-06-10 -version = "7.x-2.11" +; Information added by Drupal.org packaging script on 2023-01-15 +version = "7.x-2.12" core = "7.x" project = "migrate" -datestamp = "1528674486" +datestamp = "1673814412" diff --git a/docroot/sites/all/modules/contrib/migrate/migrate_example_baseball/migrate_example_baseball.info b/docroot/sites/all/modules/contrib/migrate/migrate_example_baseball/migrate_example_baseball.info index a5af1849..04b4fac8 100644 --- a/docroot/sites/all/modules/contrib/migrate/migrate_example_baseball/migrate_example_baseball.info +++ b/docroot/sites/all/modules/contrib/migrate/migrate_example_baseball/migrate_example_baseball.info @@ -24,8 +24,8 @@ name = "migrate_example_baseball" package = "Migration" php = "5.2.4" -; Information added by Drupal.org packaging script on 2018-06-10 -version = "7.x-2.11" +; Information added by Drupal.org packaging script on 2023-01-15 +version = "7.x-2.12" core = "7.x" project = "migrate" -datestamp = "1528674486" +datestamp = "1673814412" diff --git a/docroot/sites/all/modules/contrib/migrate/migrate_ui/migrate_ui.info b/docroot/sites/all/modules/contrib/migrate/migrate_ui/migrate_ui.info index 7f3763b6..2e52949f 100644 --- a/docroot/sites/all/modules/contrib/migrate/migrate_ui/migrate_ui.info +++ b/docroot/sites/all/modules/contrib/migrate/migrate_ui/migrate_ui.info @@ -6,8 +6,8 @@ core = 7.x dependencies[] = migrate files[] = migrate_ui.wizard.inc -; Information added by Drupal.org packaging script on 2018-06-10 -version = "7.x-2.11" +; Information added by Drupal.org packaging script on 2023-01-15 +version = "7.x-2.12" core = "7.x" project = "migrate" -datestamp = "1528674486" +datestamp = "1673814412" diff --git a/docroot/sites/all/modules/contrib/migrate/migrate_ui/migrate_ui.pages.inc b/docroot/sites/all/modules/contrib/migrate/migrate_ui/migrate_ui.pages.inc index fcea01bb..9185ddbb 100644 --- a/docroot/sites/all/modules/contrib/migrate/migrate_ui/migrate_ui.pages.inc +++ b/docroot/sites/all/modules/contrib/migrate/migrate_ui/migrate_ui.pages.inc @@ -518,7 +518,9 @@ function migrate_ui_migrate_submit($form, &$form_state) { $log_suffix = '.rollback.log'; } $migrations = implode(',', $drush_arguments); - $drush_command = "$drush_path $command $migrations --user=$uid --uri=$uri " . + // If on Acquia, call required shell script to add environment variables. + $drush_command = isset($_ENV['AH_SITE_ENVIRONMENT']) ? "/mnt/users/{$_ENV['AH_SITE_GROUP']}/{$_ENV['AH_SITE_ENVIRONMENT']}.shell " : ''; + $drush_command .= "$drush_path $command $migrations --user=$uid --uri=$uri " . '--root=' . DRUPAL_ROOT; if ($force) { $drush_command .= ' --force'; @@ -563,7 +565,7 @@ function migrate_ui_migrate_submit($form, &$form_state) { * @param $context * Batch API context structure */ -function migrate_ui_batch($operation, $machine_name, $limit, $force = FALSE, &$context) { +function migrate_ui_batch($operation, $machine_name, $limit, $force, &$context) { // If we got a stop message, skip everything else if (isset($context['results']['stopped'])) { $context['finished'] = 1; @@ -1810,7 +1812,9 @@ function migrate_ui_configure_form($form, &$form_state) { // Try running a drush status command to verify it's properly configured. $uri = $GLOBALS['base_url']; $uid = $GLOBALS['user']->uid; - $command = "$drush_path status --user=$uid --uri=$uri --root=" . DRUPAL_ROOT; + // If on Acquia, call required shell script to add environment variables. + $command = isset($_ENV['AH_SITE_ENVIRONMENT']) ? "/mnt/users/{$_ENV['AH_SITE_GROUP']}/{$_ENV['AH_SITE_ENVIRONMENT']}.shell " : ''; + $command .= "$drush_path status --user=$uid --uri=$uri --root=" . DRUPAL_ROOT; exec($command, $output, $status); if ($status == 0) { $version = ''; diff --git a/docroot/sites/all/modules/contrib/migrate/plugins/destinations/entity.inc b/docroot/sites/all/modules/contrib/migrate/plugins/destinations/entity.inc index 99cbed82..d7de7a14 100644 --- a/docroot/sites/all/modules/contrib/migrate/plugins/destinations/entity.inc +++ b/docroot/sites/all/modules/contrib/migrate/plugins/destinations/entity.inc @@ -199,6 +199,9 @@ abstract class MigrateDestinationEntity extends MigrateDestination { foreach ($e->errors as $field_name => $error_list) { if (is_array($error_list)) { foreach ($error_list as $index => $error) { + // Flatten the array to make sure the "message" field is at the top + // level. + $error = self::array_flatten($error); $message = $error['message']; $migration->saveMessage(t('Field validation error for !field_name: !message', array('!field_name' => $field_name, '!message' => $message))); @@ -207,4 +210,30 @@ abstract class MigrateDestinationEntity extends MigrateDestination { } } } + + /** + * Flattens an array of allowed values. + * + * Duplicates options_array_flatten() to avoid a dependency on the core + * options module. + * + * @param $array + * A single or multidimensional array. + * @return + * A flattened array. + */ + static public function array_flatten($array) { + $result = array(); + if (is_array($array)) { + foreach ($array as $key => $value) { + if (is_array($value)) { + $result += self::array_flatten($value); + } + else { + $result[$key] = $value; + } + } + } + return $result; + } } diff --git a/docroot/sites/all/modules/contrib/migrate/plugins/destinations/fields.inc b/docroot/sites/all/modules/contrib/migrate/plugins/destinations/fields.inc index fcc306fc..0beba882 100644 --- a/docroot/sites/all/modules/contrib/migrate/plugins/destinations/fields.inc +++ b/docroot/sites/all/modules/contrib/migrate/plugins/destinations/fields.inc @@ -28,7 +28,7 @@ class MigrateFieldsEntityHandler extends MigrateDestinationHandler { $fields[$machine_name] = $instance['label']; } - // Look for subfields + // Look for subfields. $class_list = _migrate_class_list('MigrateFieldHandler'); $disabled = unserialize(variable_get('migrate_disabled_handlers', serialize(array()))); $fields_found = FALSE; @@ -63,7 +63,8 @@ class MigrateFieldsEntityHandler extends MigrateDestinationHandler { public function prepare($entity, stdClass $row) { migrate_instrument_start('MigrateDestinationEntity->prepareFields'); - // Look for Field API fields attached to this destination and handle appropriately + // Look for Field API fields attached to this destination + // and handle appropriately. $migration = Migration::currentMigration(); $destination = $migration->getDestination(); $entity_type = $destination->getEntityType(); @@ -71,9 +72,9 @@ class MigrateFieldsEntityHandler extends MigrateDestinationHandler { $instances = field_info_instances($entity_type, $bundle); foreach ($instances as $machine_name => $instance) { if (property_exists($entity, $machine_name)) { - // Normalize to an array + // Normalize to an array. if (!is_array($entity->{$machine_name})) { - $entity->{$machine_name} = array($entity->{$machine_name}); + $entity->{$machine_name} = $entity->$machine_name ? array($entity->{$machine_name}) : array(); } $field_info = field_info_field($machine_name); $entity->{$machine_name} = migrate_field_handler_invoke_all($entity, $field_info, @@ -85,7 +86,8 @@ class MigrateFieldsEntityHandler extends MigrateDestinationHandler { public function complete($entity, stdClass $row) { migrate_instrument_start('MigrateDestinationEntity->completeFields'); - // Look for Field API fields attached to this destination and handle appropriately + // Look for Field API fields attached to this destination + // and handle appropriately. $migration = Migration::currentMigration(); $destination = $migration->getDestination(); $entity_type = $destination->getEntityType(); @@ -93,7 +95,7 @@ class MigrateFieldsEntityHandler extends MigrateDestinationHandler { $instances = field_info_instances($entity_type, $bundle); foreach ($instances as $machine_name => $instance) { if (property_exists($entity, $machine_name)) { - // Normalize to an array + // Normalize to an array. if (!is_array($entity->{$machine_name})) { $entity->{$machine_name} = array($entity->{$machine_name}); } @@ -108,20 +110,21 @@ class MigrateFieldsEntityHandler extends MigrateDestinationHandler { abstract class MigrateFieldHandler extends MigrateHandler { - // Derived classes are expected to implement one or both of the prepare/complete - // handlers. - - // abstract public function prepare($entity, array $field_info, array $instance, array $values); - // abstract public function complete($entity, array $field_info, array $instance, array $values); + // Derived classes are expected to implement one + // or both of the prepare/complete handlers. + // Abstract public function + // prepare($entity, array $field_info, array $instance, array $values). + // Abstract public function + // complete($entity, array $field_info, array $instance, array $values). /** - * Determine the language of the field + * Determine the language of the field. * * @param $entity * @param $field_info * @param $arguments * - * @return string language code + * @return string language code. */ function getFieldLanguage($entity, $field_info, array $arguments) { $migration = Migration::currentMigration(); @@ -492,6 +495,7 @@ class MigrateTaxonomyTermReferenceFieldHandler extends MigrateFieldHandler { array('@doc' => 'http://drupal.org/node/1224042#create_term')), 'ignore_case' => t('Option: Set to TRUE to ignore case differences between source data and existing term names', array('@doc' => 'http://drupal.org/node/1224042#ignore_case')), + 'not_empty' => t('Option: Set to TRUE to ignore empty terms to get created in case of multiple term names per row.'), ); } @@ -516,7 +520,7 @@ class MigrateTaxonomyTermReferenceFieldHandler extends MigrateFieldHandler { $vocab_name = $field_info['settings']['allowed_values'][0]['vocabulary']; $names = taxonomy_vocabulary_get_names(); - // Get the vocabulary for this term + // Get the vocabulary for this term. if (isset($field_info['settings']['allowed_values'][0]['vid'])) { $vid = $field_info['settings']['allowed_values'][0]['vid']; } @@ -524,10 +528,22 @@ class MigrateTaxonomyTermReferenceFieldHandler extends MigrateFieldHandler { $vid = $names[$vocab_name]->vid; } - // Remove leading and trailing spaces in term names + // Remove leading and trailing spaces in term names. $values = array_map('trim', $values); - // Cannot use taxonomy_term_load_multiple() since we have an array of names. + // Remove empty array values from $values array. + if (!empty($arguments['not_empty'])) { + $terms = array(); + foreach ($values as $term) { + if (!empty($term)) { + $terms[] = $term; + } + $values = $terms; + } + } + + // Cannot use taxonomy_term_load_multiple() + // since we have an array of names. // It wants a singular value. This query may return case-insensitive // matches. $existing_terms = db_select('taxonomy_term_data', 'td') @@ -669,7 +685,7 @@ abstract class MigrateFileFieldBaseHandler extends MigrateFieldHandler { $migration = Migration::currentMigration(); // One can override the source class via CLI or drushrc.php (the - // option is named file_function for historical reasons) + // option is named file_function for historical reasons). if ($migration->getOption('file_function')) { $file_class = $migration->getOption('file_function'); } @@ -680,8 +696,9 @@ abstract class MigrateFileFieldBaseHandler extends MigrateFieldHandler { $file_class = 'MigrateFileUri'; } - // If a destination directory (relative to the Drupal public files directory) - // is not explicitly provided, use the default for the field. + // If a destination directory + // (relative to the Drupal public files directory) is not + // explicitly provided, use the default for the field. if (empty($arguments['destination_dir'])) { $arguments['destination_dir'] = $this->destinationDir($field_info, $instance); } @@ -693,10 +710,10 @@ abstract class MigrateFileFieldBaseHandler extends MigrateFieldHandler { // etc. foreach ($values as $delta => $value) { if ($value) { - // Handle potentially multiple arguments + // Handle potentially multiple arguments. $instance_arguments = array(); foreach ($arguments as $key => $argument) { - // For a scalar argument, pass it directly + // For a scalar argument, pass it directly. if (!is_array($argument)) { $instance_arguments[$key] = $argument; } @@ -717,9 +734,9 @@ abstract class MigrateFileFieldBaseHandler extends MigrateFieldHandler { } } // If the parent entity doesn't have an explicit uid, give ownership - // to the anonymous account + // to the anonymous account. $owner = isset($entity->uid) ? $entity->uid : 0; - // Call the MigrateFileInterface implementation to do the real work + // Call the MigrateFileInterface implementation to do the real work. $source = new $file_class($instance_arguments); $file = $source->processFile($value, $owner); diff --git a/docroot/sites/all/modules/contrib/migrate/plugins/destinations/file.inc b/docroot/sites/all/modules/contrib/migrate/plugins/destinations/file.inc index 9f638d26..3c7c174b 100644 --- a/docroot/sites/all/modules/contrib/migrate/plugins/destinations/file.inc +++ b/docroot/sites/all/modules/contrib/migrate/plugins/destinations/file.inc @@ -438,6 +438,7 @@ class MigrateFileUri extends MigrateFile { $filename = str_replace('%3A', ':', $filename); $filename = str_replace('%3F', '?', $filename); $filename = str_replace('%26', '&', $filename); + $filename = str_replace('%40', '@', $filename); } return $filename; } @@ -463,7 +464,8 @@ class MigrateFileUri extends MigrateFile { } if (empty($this->destinationFile)) { - $this->destinationFile = basename($this->sourcePath); + $path = explode('?', $this->sourcePath); + $this->destinationFile = basename($path[0]); } // MigrateFile has most of the smarts - the key is that it will call back diff --git a/docroot/sites/all/modules/contrib/migrate/plugins/destinations/path.inc b/docroot/sites/all/modules/contrib/migrate/plugins/destinations/path.inc index 62a28fb4..5d4b4ccf 100644 --- a/docroot/sites/all/modules/contrib/migrate/plugins/destinations/path.inc +++ b/docroot/sites/all/modules/contrib/migrate/plugins/destinations/path.inc @@ -39,4 +39,42 @@ class MigratePathEntityHandler extends MigrateDestinationHandler { } } } + + public function complete($entity, stdClass $row) { + // Check if this is a forum taxonomy term. + if (module_exists('forum')) { + if (isset($entity->vocabulary_machine_name) && $entity->vocabulary_machine_name == 'forums') { + // Check if a path ID exists for this term. + $term_pid = db_select('url_alias', 'url_alias') + ->fields('url_alias', array('pid')) + ->condition('source', 'taxonomy/term/' . $entity->tid) + ->condition('language', $entity->language) + ->execute() + ->fetchField(); + + // Check if there is also a path ID for this term referencing forums. + $forum_term_pid = db_select('url_alias', 'url_alias') + ->fields('url_alias', array('pid')) + ->condition('source', 'forum/' . $entity->tid) + ->condition('language', $entity->language) + ->execute() + ->fetchField(); + + // If both term and forum term path IDs exist, delete the term's path. + if ($term_pid && $forum_term_pid) { + db_delete('url_alias') + ->condition('pid', $term_pid) + ->execute(); + } + // If a term path ID exists but forum term path ID does not, + // update term path to match what the forum module expects. + elseif ($term_pid && empty($forum_term_pid)) { + db_update('url_alias') + ->fields(array('source' => 'forum/' . $entity->tid)) + ->condition('pid', $term_pid) + ->execute(); + } + } + } + } } diff --git a/docroot/sites/all/modules/contrib/migrate/plugins/sources/csv.inc b/docroot/sites/all/modules/contrib/migrate/plugins/sources/csv.inc index a5bd4764..1187feea 100644 --- a/docroot/sites/all/modules/contrib/migrate/plugins/sources/csv.inc +++ b/docroot/sites/all/modules/contrib/migrate/plugins/sources/csv.inc @@ -152,9 +152,9 @@ class MigrateListCSV extends MigrateList { if (!$this->validResource()) { return $count; } - // Skip all but the last header + // Skip header rows for ($i = 0; $i < $this->headerRows; $i++) { - fgets($this->csvHandle); + $this->getNextLine(); } while ($this->getNextLine()) { $count++; diff --git a/docroot/sites/all/modules/contrib/migrate/plugins/sources/json.inc b/docroot/sites/all/modules/contrib/migrate/plugins/sources/json.inc index 9844d109..62eb5cb9 100644 --- a/docroot/sites/all/modules/contrib/migrate/plugins/sources/json.inc +++ b/docroot/sites/all/modules/contrib/migrate/plugins/sources/json.inc @@ -154,7 +154,8 @@ class MigrateItemJSON extends MigrateItem { * @param mixed $id */ protected function constructItemUrl($id) { - return preg_replace(array_fill(0, count($id), '/:id/'), $id, $this->itemUrl, 1); + $count = is_array($id) ? count($id) : 1; + return preg_replace(array_fill(0, $count, '/:id/'), $id, $this->itemUrl, 1); } /** @@ -228,6 +229,7 @@ class MigrateJSONReader implements Iterator { * * @return void */ + #[\ReturnTypeWillChange] public function rewind() { // Close any open file - we open the files lazily in next(). if ($this->fileHandle) { @@ -261,6 +263,7 @@ class MigrateJSONReader implements Iterator { * * @return void */ + #[\ReturnTypeWillChange] public function next() { migrate_instrument_start('MigrateJSONReader::next'); @@ -371,6 +374,7 @@ class MigrateJSONReader implements Iterator { * * @return null|object */ + #[\ReturnTypeWillChange] public function current() { return $this->currentElement; } @@ -380,6 +384,7 @@ class MigrateJSONReader implements Iterator { * * @return null|string */ + #[\ReturnTypeWillChange] public function key() { return $this->currentId; } @@ -389,6 +394,7 @@ class MigrateJSONReader implements Iterator { * * @return bool */ + #[\ReturnTypeWillChange] public function valid() { return !empty($this->currentElement); } @@ -477,7 +483,13 @@ class MigrateSourceJSON extends MigrateSource { } $this->sourceUrls = $urls; - $this->activeUrl = NULL; + + $active_url = variable_get('migrate_source_json_active_url', NULL); + if (isset($active_url)) { + $active_url--; + } + $this->activeUrl = $active_url; + $this->readerClass = $reader_class; $this->fields = $fields; } @@ -538,7 +550,11 @@ class MigrateSourceJSON extends MigrateSource { // Set the reader back to the beginning of the file (positioned to the // first matching element), then apply our logic to make sure we have the // first element fulfilling our logic (idlist/map/prepareRow()). - $this->activeUrl = NULL; + $active_url = variable_get('migrate_source_json_active_url', NULL); + if (isset($active_url)) { + $active_url--; + } + $this->activeUrl = $active_url; if ($this->reader) { $this->reader->rewind(); $this->reader = NULL; @@ -598,6 +614,8 @@ class MigrateSourceJSON extends MigrateSource { $this->activeUrl = $this->activeUrl + 1; } + variable_set('migrate_source_json_active_url', $this->activeUrl); + $this->reader = new $this->readerClass($this->sourceUrls[$this->activeUrl], $this->idField); $this->reader->rewind(); @@ -608,6 +626,10 @@ class MigrateSourceJSON extends MigrateSource { } } + if ((count($this->sourceUrls)-1) == $this->activeUrl) { + variable_del('migrate_source_json_active_url'); + } + migrate_instrument_stop('MigrateSourceJSON::nextSource'); return $status; } diff --git a/docroot/sites/all/modules/contrib/migrate/plugins/sources/sql.inc b/docroot/sites/all/modules/contrib/migrate/plugins/sources/sql.inc index 2cd444d8..b9a45d36 100644 --- a/docroot/sites/all/modules/contrib/migrate/plugins/sources/sql.inc +++ b/docroot/sites/all/modules/contrib/migrate/plugins/sources/sql.inc @@ -2,7 +2,7 @@ /** * @file - * Define a MigrateSource for importing from Drupal connections + * Define a MigrateSource for importing from Drupal connections. */ /** @@ -11,7 +11,7 @@ class MigrateSourceSQL extends MigrateSource { /** - * The SQL query objects from which to obtain data, and counts of data + * The SQL query objects from which to obtain data, and counts of data. * * @var SelectQueryInterface */ @@ -37,7 +37,7 @@ class MigrateSourceSQL extends MigrateSource { protected $result; /** - * Number of eligible rows processed so far (used for itemlimit checking) + * Number of eligible rows processed so far (used for itemlimit checking). * * @var int */ @@ -74,8 +74,8 @@ class MigrateSourceSQL extends MigrateSource { */ protected $mapJoinable = FALSE; - // Dynamically set whether the map is joinable - not really for production use, - // this is primarily to support simpletests + // Dynamically set whether the map is joinable - not really for production + // use, this is primarily to support simpletests. public function setMapJoinable($map_joinable) { $this->mapJoinable = $map_joinable; } @@ -206,13 +206,14 @@ class MigrateSourceSQL extends MigrateSource { $queryFields = $this->query->getFields(); if ($queryFields) { - // Not much we can do in terms of describing the fields without manual intervention + // Not much we can do in terms of describing the fields + // without manual intervention. foreach ($queryFields as $field_name => $field_info) { $fields[$field_name] = $field_info['table'] . '.' . $field_info['field']; } } else { - // Detect available fields + // Detect available fields. $detection_query = clone $this->query; $result = $detection_query->range(0, 1)->execute(); $row = $result->fetchAssoc(); @@ -287,9 +288,9 @@ class MigrateSourceSQL extends MigrateSource { } // The rules for determining what conditions to add to the query are as - // follows (applying first applicable rule) + // follows (applying first applicable rule). // 1. If idlist is provided, then only process items in that list (AND key - // IN (idlist)). Only applicable with single-value keys. + // IN (idlist)). Only applicable with single-value keys. if ($this->idList) { $simple_ids = array(); $compound_ids = array(); @@ -305,7 +306,8 @@ class MigrateSourceSQL extends MigrateSource { $compound_ids[] = explode($this->multikeySeparator, $id); } - // Check for compunded ids. If present add them with subsequent OR statements. + // Check for compunded ids. If present add them with subsequent + // OR statements. if (!empty($compound_ids)) { $condition = db_or(); if (!empty($simple_ids)) { @@ -329,13 +331,13 @@ class MigrateSourceSQL extends MigrateSource { } else { // 2. If the map is joinable, join it. We will want to accept all rows - // which are either not in the map, or marked in the map as NEEDS_UPDATE. - // Note that if highwater fields are in play, we want to accept all rows - // above the highwater mark in addition to those selected by the map - // conditions, so we need to OR them together (but AND with any existing - // conditions in the query). So, ultimately the SQL condition will look - // like (original conditions) AND (map IS NULL OR map needs update - // OR above highwater). + // which are either not in the map, or marked in the map as NEEDS_UPDATE. + // Note that if highwater fields are in play, we want to accept all rows + // above the highwater mark in addition to those selected by the map + // conditions, so we need to OR them together (but AND with any existing + // conditions in the query). So, ultimately the SQL condition will look + // like (original conditions) AND (map IS NULL OR map needs update + // OR above highwater). $conditions = db_or(); $condition_added = FALSE; if ($this->mapJoinable) { @@ -377,7 +379,7 @@ class MigrateSourceSQL extends MigrateSource { $this->query->addField($alias, 'needs_update', 'migrate_map_needs_update'); } // 3. If we are using highwater marks, also include rows above the mark. - // But, include all rows if the highwater mark is not set. + // But, include all rows if the highwater mark is not set. if (isset($this->highwaterField['name']) && $this->activeMigration->getHighwater() !== '') { // But, if there are any existing items marked as needing update which // fall below the highwater mark, and map_joinable is FALSE, those @@ -399,8 +401,15 @@ class MigrateSourceSQL extends MigrateSource { else { $highwater = $this->highwaterField['name']; } - $conditions->condition($highwater, $this->activeMigration->getHighwater(), '>'); - $condition_added = TRUE; + // If highwaterField is an aggregate function add + // as a having condition. + if (isset($this->highwaterField['aggregate'])) { + $this->query->havingCondition($highwater, $this->activeMigration->getHighwater(), '>'); + } + else { + $conditions->condition($highwater, $this->activeMigration->getHighwater(), '>'); + $condition_added = TRUE; + } } } if ($condition_added) { @@ -429,8 +438,8 @@ class MigrateSourceSQL extends MigrateSource { public function getNextRow() { $row = $this->result->fetchObject(); - // We might be out of data entirely, or just out of data in the current batch. - // Attempt to fetch the next batch and see. + // We might be out of data entirely, or just out of data in the current + // batch. Attempt to fetch the next batch and see. if (!is_object($row) && $this->batchSize > 0) { $this->getNextBatch(); $row = $this->result->fetchObject(); diff --git a/docroot/sites/all/modules/contrib/migrate/plugins/sources/sqlmap.inc b/docroot/sites/all/modules/contrib/migrate/plugins/sources/sqlmap.inc index ccfacd45..cea6c1ae 100644 --- a/docroot/sites/all/modules/contrib/migrate/plugins/sources/sqlmap.inc +++ b/docroot/sites/all/modules/contrib/migrate/plugins/sources/sqlmap.inc @@ -64,7 +64,7 @@ class MigrateSQLMap extends MigrateMap { } /** - * Drupal connection object on which to create the map/message tables + * Drupal connection object on which to create the map/message tables. * * @var DatabaseConnection */ @@ -118,7 +118,7 @@ class MigrateSQLMap extends MigrateMap { $this->connection = Database::getConnection('default', $connection_key); - // Default generated table names, limited to 63 characters + // Default generated table names, limited to 63 characters. $prefixLength = strlen($this->connection->tablePrefix()); $this->mapTable = 'migrate_map_' . drupal_strtolower($machine_name); $this->mapTable = drupal_substr($this->mapTable, 0, 63 - $prefixLength); @@ -127,7 +127,7 @@ class MigrateSQLMap extends MigrateMap { $this->sourceKey = $source_key; $this->destinationKey = $destination_key; - // Build the source and destination key maps + // Build the source and destination key maps. $this->sourceKeyMap = array(); $count = 1; foreach ($source_key as $field => $schema) { @@ -148,7 +148,7 @@ class MigrateSQLMap extends MigrateMap { if (!$this->ensured) { if (!$this->connection->schema()->tableExists($this->mapTable)) { // Generate appropriate schema info for the map and message tables, - // and map from the source field names to the map/msg field names + // and map from the source field names to the map/msg field names. $count = 1; $source_key_schema = array(); $pks = array(); @@ -161,11 +161,11 @@ class MigrateSQLMap extends MigrateMap { $fields = $source_key_schema; - // Add destination keys to map table + // Add destination keys to map table. // TODO: How do we discover the destination schema? $count = 1; foreach ($this->destinationKey as $field_schema) { - // Allow dest key fields to be NULL (for IGNORED/FAILED cases) + // Allow dest key fields to be NULL (for IGNORED/FAILED cases). $field_schema['not null'] = FALSE; $field_schema['default'] = NULL; $mapkey = 'destid' . $count++; @@ -236,7 +236,7 @@ class MigrateSQLMap extends MigrateMap { $this->connection->schema()->createTable($this->messageTable, $schema); } else { - // Add any missing columns to the map table + // Add any missing columns to the map table. if (!$this->connection->schema()->fieldExists($this->mapTable, 'rollback_action')) { $this->connection->schema()->addField($this->mapTable, @@ -264,7 +264,7 @@ class MigrateSQLMap extends MigrateMap { } /** - * Retrieve a row from the map table, given a source ID + * Retrieve a row from the map table, given a source ID. * * @param array $source_id */ @@ -281,7 +281,7 @@ class MigrateSQLMap extends MigrateMap { } /** - * Retrieve a row from the map table, given a destination ID + * Retrieve a row from the map table, given a destination ID. * * @param array $source_id */ @@ -301,7 +301,7 @@ class MigrateSQLMap extends MigrateMap { * Retrieve an array of map rows marked as needing update. * * @param int $count - * Maximum rows to return; defaults to 10,000 + * Maximum rows to return; defaults to 10,000. * * @return array * Array of map row objects with needs_update==1. @@ -419,7 +419,7 @@ class MigrateSQLMap extends MigrateMap { $needs_update = MigrateMap::STATUS_IMPORTED, $rollback_action = MigrateMap::ROLLBACK_DELETE, $hash = NULL) { migrate_instrument_start('saveIDMapping'); - // Construct the source key + // Construct the source key. $keys = array(); foreach ($this->sourceKeyMap as $field_name => $key_name) { // A NULL key value will fail. @@ -458,21 +458,21 @@ class MigrateSQLMap extends MigrateMap { * Record a message in the migration's message table. * * @param array $source_key - * Source ID of the record in error + * Source ID of the record in error. * @param string $message * The message to record. * @param int $level * Optional message severity (defaults to MESSAGE_ERROR). */ public function saveMessage($source_key, $message, $level = Migration::MESSAGE_ERROR) { - // Source IDs as arguments + // Source IDs as arguments. $count = 1; if (is_array($source_key)) { foreach ($source_key as $key_value) { $fields['sourceid' . $count++] = $key_value; - // If any key value is not set, we can't save - print out and abort + // If any key value is not set, we can't save - print out and abort. if (!isset($key_value)) { - print($message); + Migration::displayMessage($message); return; } } @@ -484,7 +484,8 @@ class MigrateSQLMap extends MigrateMap { } else { // TODO: What else can we do? - Migration::displayMessage($message); + // Display Message with correct level instead of default level 'error'. + MigrationBase::saveMessage($message, $level); } } @@ -640,7 +641,7 @@ class MigrateSQLMap extends MigrateMap { * Each array member is an array of key fields for one source row. */ public function deleteBulk(array $source_keys) { - // If we have a single-column key, we can shortcut it + // If we have a single-column key, we can shortcut it. if (count($this->sourceKey) == 1) { $sourceids = array(); foreach ($source_keys as $source_key) { @@ -696,8 +697,9 @@ class MigrateSQLMap extends MigrateMap { /** * Implementation of Iterator::rewind() - called before beginning a foreach - * loop. TODO: Support idlist, itemlimit + * loop. TODO: Support idlist, itemlimit. */ + #[\ReturnTypeWillChange] public function rewind() { $this->currentRow = NULL; $fields = array(); @@ -707,12 +709,6 @@ class MigrateSQLMap extends MigrateMap { foreach ($this->destinationKeyMap as $field) { $fields[] = $field; } - - /* TODO - if (isset($this->options['itemlimit'])) { - $query = $query->range(0, $this->options['itemlimit']); - } - */ $this->result = $this->connection->select($this->mapTable, 'map') ->fields('map', $fields) ->execute(); @@ -721,8 +717,9 @@ class MigrateSQLMap extends MigrateMap { /** * Implementation of Iterator::current() - called when entering a loop - * iteration, returning the current row + * iteration, returning the current row. */ + #[\ReturnTypeWillChange] public function current() { return $this->currentRow; } @@ -733,6 +730,7 @@ class MigrateSQLMap extends MigrateMap { * serialize to fulfill the requirement, but using getCurrentKey() is * preferable. */ + #[\ReturnTypeWillChange] public function key() { return serialize($this->currentKey); } @@ -741,6 +739,7 @@ class MigrateSQLMap extends MigrateMap { * Implementation of Iterator::next() - called at the bottom of the loop * implicitly, as well as explicitly from rewind(). */ + #[\ReturnTypeWillChange] public function next() { $this->currentRow = $this->result->fetchObject(); $this->currentKey = array(); @@ -750,7 +749,7 @@ class MigrateSQLMap extends MigrateMap { else { foreach ($this->sourceKeyMap as $map_field) { $this->currentKey[$map_field] = $this->currentRow->{$map_field}; - // Leave only destination fields + // Leave only destination fields. unset($this->currentRow->{$map_field}); } } @@ -758,8 +757,9 @@ class MigrateSQLMap extends MigrateMap { /** * Implementation of Iterator::valid() - called at the top of the loop, - * returning TRUE to process the loop and FALSE to terminate it + * returning TRUE to process the loop and FALSE to terminate it. */ + #[\ReturnTypeWillChange] public function valid() { // TODO: Check numProcessed against itemlimit return !is_null($this->currentRow); diff --git a/docroot/sites/all/modules/contrib/migrate/plugins/sources/mssql.inc b/docroot/sites/all/modules/contrib/migrate/plugins/sources/sqlsrv.inc similarity index 77% rename from docroot/sites/all/modules/contrib/migrate/plugins/sources/mssql.inc rename to docroot/sites/all/modules/contrib/migrate/plugins/sources/sqlsrv.inc index 1f1abdcd..0b26a2bc 100644 --- a/docroot/sites/all/modules/contrib/migrate/plugins/sources/mssql.inc +++ b/docroot/sites/all/modules/contrib/migrate/plugins/sources/sqlsrv.inc @@ -6,17 +6,16 @@ */ /** - * Implementation of MigrateSource, to handle imports from remote MS SQL Server - * db servers. + * Implementation of MigrateSource, to handle imports from remote MS SQL Server db servers. */ class MigrateSourceMSSQL extends MigrateSource { - /** * Array containing information for connecting to SQL Server: * servername - Hostname of the SQL Server * username - Username to connect as * password - Password for logging in * database (optional) - Database to select after connecting + * character_set (optional) - set to "UTF-8" for multibyte chars support * * @var array */ @@ -41,7 +40,7 @@ class MigrateSourceMSSQL extends MigrateSource { protected $result; /** - * By default, mssql_query fetches all results - severe memory problems with + * By default, sqlsrv_query fetches all results - severe memory problems with * big tables. So, we will fetch a batch at a time. * * @var int @@ -64,7 +63,7 @@ class MigrateSourceMSSQL extends MigrateSource { * Simple initialization. */ public function __construct(array $configuration, $query, $count_query, - array $fields, array $options = array()) { + array $fields, array $options = array()) { parent::__construct($options); $this->query = $query; $this->countQuery = $count_query; @@ -87,23 +86,28 @@ class MigrateSourceMSSQL extends MigrateSource { */ protected function connect() { if (!isset($this->connection)) { - if (!extension_loaded('mssql')) { - throw new Exception(t('You must configure the mssql extension in PHP.')); + if (!extension_loaded('sqlsrv')) { + throw new Exception(t('You must configure the sqlsrv extension in PHP.')); } if (isset($this->configuration['port'])) { - $host = $this->configuration['servername'] . ':' . $this->configuration['port']; + $host = $this->configuration['servername'] . ',' . $this->configuration['port']; } else { $host = $this->configuration['servername']; } - $this->connection = mssql_connect( - $host, - $this->configuration['username'], - $this->configuration['password'], - TRUE); - if (isset($this->configuration['database'])) { - return mssql_select_db($this->configuration['database'], $this->connection); + $connectionInfo = array( + "Database" => $this->configuration['database'], + "UID" => $this->configuration['username'], + "PWD" => $this->configuration['password'], + ); + // Add CharacterSet option. + if (!empty($this->configuration['character_set'])) { + $connectionInfo["CharacterSet"] = $this->configuration['character_set']; + } + $this->connection = sqlsrv_connect($host, $connectionInfo); + if ($this->connection !== FALSE) { + return $this->connection; } } } @@ -125,10 +129,12 @@ class MigrateSourceMSSQL extends MigrateSource { */ public function computeCount() { migrate_instrument_start('MigrateSourceMSSQL count'); - if ($this->connect()) { - $result = mssql_query($this->countQuery); - $result_array = mssql_fetch_array($result); - $count = reset($result_array); + if ($connect = $this->connect()) { + $result = sqlsrv_query($connect,$this->countQuery); + $result_array = sqlsrv_fetch_array($result); + if ($result_array) { + $count = reset($result_array); + } } else { // Do something else? @@ -178,10 +184,10 @@ class MigrateSourceMSSQL extends MigrateSource { } } - migrate_instrument_start('mssql_query'); + migrate_instrument_start('sqlsrv_query'); $this->connect(); - $this->result = mssql_query($this->query, $this->connection, $this->batchSize); - migrate_instrument_stop('mssql_query'); + $this->result = sqlsrv_query($this->connection, $this->query, array($this->batchSize)); + migrate_instrument_stop('sqlsrv_query'); } /** @@ -191,13 +197,13 @@ class MigrateSourceMSSQL extends MigrateSource { * difference between the end of the batch and the end of all data. */ public function getNextRow() { - $row = mssql_fetch_object($this->result); + $row = sqlsrv_fetch_object($this->result); // Might be totally out of data, or just out of this batch - request another // batch and see if (!is_object($row)) { - mssql_fetch_batch($this->result); - $row = mssql_fetch_object($this->result); + sqlsrv_num_rows($this->result); + $row = sqlsrv_fetch_object($this->result); } if (is_object($row)) { return $row; diff --git a/docroot/sites/all/modules/contrib/migrate/plugins/sources/xml.inc b/docroot/sites/all/modules/contrib/migrate/plugins/sources/xml.inc index bf923320..fe53c1aa 100644 --- a/docroot/sites/all/modules/contrib/migrate/plugins/sources/xml.inc +++ b/docroot/sites/all/modules/contrib/migrate/plugins/sources/xml.inc @@ -995,6 +995,7 @@ class MigrateXMLReader implements Iterator { /** * Implementation of Iterator::rewind(). */ + #[\ReturnTypeWillChange] public function rewind() { // (Re)open the provided URL. $this->reader->close(); @@ -1016,6 +1017,7 @@ class MigrateXMLReader implements Iterator { /** * Implementation of Iterator::next(). */ + #[\ReturnTypeWillChange] public function next() { migrate_instrument_start('MigrateXMLReader::next'); $this->currentElement = $this->currentId = NULL; @@ -1091,6 +1093,7 @@ class MigrateXMLReader implements Iterator { * @return null|SimpleXMLElement * Current item */ + #[\ReturnTypeWillChange] public function current() { return $this->currentElement; } @@ -1101,6 +1104,7 @@ class MigrateXMLReader implements Iterator { * @return null|string * Current key */ + #[\ReturnTypeWillChange] public function key() { return $this->currentId; } @@ -1111,6 +1115,7 @@ class MigrateXMLReader implements Iterator { * @return bool * Indicates if current element is valid */ + #[\ReturnTypeWillChange] public function valid() { return $this->currentElement instanceof SimpleXMLElement; }